Skip to content
PolyFish CSS

Modules

Eleven files, each mapping to a part of a page. Take Core plus whatever your page actually contains — a marketing page needs four, a sign-in screen needs two.

FileCoversSizeNeeds Core
CoreTokens, reset, type, layout, buttons11 KBIs Core
GridTwelve-column responsive grid13 KBYes
HeadersTop bar, nav, heroes, page headers7 KBYes
ContentSections, cards, tables, forms, code12 KBYes
FormsFloating labels, validation, range, file5 KBYes
ComponentsBadges, tabs, menus, lists, dialogs13 KBYes
FootersFooter layouts and link columns4 KBYes
FontsSelf-hosted @font-face declarations4 KBIndependent
SpacePadding, margin, gap and grid utilities20 KBYes
EffectsTransforms, filters, gradients, animations6 KBYes
UtilitiesSpacing, colour, visibility helpers4 KBYes

What you get for what you load

Tick the modules you would link. Every component below that needs one you have not ticked is marked unavailable — this is the framework's dependency graph, made pokeable. Core is not a checkbox because nothing works without it.

modules linked

Buttons, type, layout

Every button variant, the type scale, container, stack, cluster, grid and split.

Core — always on

Nav, hero, page head

Announcement bar, sticky navigation with the mobile menu, four hero variants, breadcrumbs.

needs Headers

Sections, cards, tables

Section rhythm, cards, plans, stats, tables, alerts, code blocks, accordions, sidebars.

needs Content

Floating labels, validation

Input sizes, floating labels, feedback messages, fieldsets, range, file inputs, option cards.

needs Forms

Tabs, menus, dialogs

Badges, button groups, pagination, progress, lists, avatars, switches, tabs, menus, dialogs, toasts.

needs Components

Footers

Column, slim and accent footers, link columns, social row, legal bar, back-to-top.

needs Footers

Twelve columns

Explicit column spans, offsets and order across five breakpoints.

needs Grid

Padding and margin utilities

Every side and axis, gaps, grid tracks, flex sizing, four responsive breakpoints.

needs Space

Transforms and animation

Transforms, filters, gradients, rings, six animations, scroll snap, group hover.

needs Effects

Checkboxes and :has(). A dimmed tile is a component you would be writing markup for that has no styles behind it.

Core

The only required file. It declares every custom property the others read, resets the document, sets the type scale, and provides the layout primitives and buttons.

  • Layout: .pf-container, .pf-stack, .pf-cluster, .pf-grid, .pf-split, .pf-shell
  • Brand: .pf-logo, .pf-lockup
  • Buttons: .pf-btn with --secondary, --ghost, --orange, three sizes, --block, --square
  • Marks: .pf-pill, .pf-mark, .pf-dot, .pf-facet
  • Accessibility: .pf-skip, .pf-visually-hidden, a global :focus-visible ring, and a reduced-motion block

Grid

A twelve-column grid with five breakpoints — .pf-row, .pf-col-8, .pf-col-md-4, offsets, order and per-row gutters — for the layouts where the proportions themselves change per breakpoint.

Skip it for most pages. .pf-grid--3 is one class and handles its own breakpoints; a column system is two classes per child and handles them by hand. The module exists because some designs genuinely need the control, not because every page does.

Headers

Everything above the fold. The navigation's mobile menu is a checkbox and a sibling selector, so the module needs no script.

  • .pf-topbar — announcement strip, plus a --green variant
  • .pf-nav — sticky and blurred by default; --static and --flush variants
  • .pf-hero--split, --center and --photo variants, with the mesh background masked in
  • .pf-pagehead and .pf-breadcrumb for interior pages

See it in isolation on the headers example.

Content

The largest module, covering everything between the header and the footer.

  • Sections and section heads, eyebrows, ledes
  • Cards, feature grids, checklists, plan cards, stats
  • Tables that scroll horizontally rather than squashing
  • Forms — inputs, selects with a styled arrow, textareas, checkboxes, inline forms
  • Alerts, quotes, code blocks, accordions built on <details>, galleries, steps and CTA bands

See it in isolation on the page core example.

Forms

Content styles four controls. Forms handles everything a real form needs after that: input sizes, floating labels, validation states and feedback messages, fieldsets and legends, range sliders, file inputs, selectable option cards, form layout rows and character counters.

Two decisions worth knowing about. Validation styling hangs off aria-invalid rather than a class, so the visual state and the announced state cannot disagree. And it uses :user-invalid rather than :invalid — the latter matches an empty required field on page load, which paints a form red before anyone has typed a character.

Components

Eighteen pieces for the screens behind a login: badges and tags, button groups, pagination, progress bars and segmented meters, spinners, list groups, avatars and stacks, switches, input groups, tabs, disclosure menus, dialogs, tooltips, ratio boxes, skeletons, empty states, dividers and toolbars.

Still nothing required. Tabs are radio inputs, the menu is a <details>, the dialog is a native <dialog> with a :target fallback. Two components carry an honest limit in their source comments — the menu does not close on an outside click, and the tabs announce as a radio group rather than a tablist. Both need a listener to go further, and the framework does not pretend otherwise.

Footers

Three footers in 4 KB: the column footer, a one-line --slim variant for docs and app shells, and a full-bleed --green variant that recolours its own links, social row and back-to-top link.

See it in isolation on the footers example.

Fonts

Seven @font-face rules pointing at /fonts, covering the three families Core names. Independent of every other module — load it or don't, before Core or after, it only declares faces. Skipping it falls back to system stacks with no layout change.

Self-hosting is a security decision before it is a performance one: with no font CDN in the page, the Content-Security-Policy can refuse remote origins outright.

Space

The full spacing surface: padding and margin on every side and axis, gaps, grid track shorthands, flex sizing and placement, with the six most-used families repeated at four breakpoints. .pf-px-4, .pf-mt-6, .pf-md-py-8.

The suffix is a step on the space scale, not a pixel value, so retuning --pf-space-* retunes every utility with it. Negative margins are deliberately absent — a negative margin is nearly always a layout fighting its container, and a utility makes it easy to reach for twice.

It is the largest module at 20 KB minified, which is the honest cost of a utility surface with no compiler to purge it. It gzips to 2.8 KB because the strings repeat, and nothing else depends on it: if you would rather not carry it, do not load it.

Effects

Transforms composed through custom properties so translate, rotate and scale can be combined without the last declaration silently winning. Filters and a @supports-guarded frosted panel. Gradients built from role tokens, so they follow a theme. Rings with a real offset. Six named animations, all opt-in.

It also carries the pattern a utility framework needs and CSS has no shorthand for: .pf-group plus .pf-group-show, a child reacting to its parent's hover or focus. That reveal is scoped to (hover: hover) — on a touch device the affordance stays visible rather than hiding behind a state a finger cannot enter.

Every animation sits inside prefers-reduced-motion: no-preference rather than merely being slowed by Core's global block. An animation that starts at opacity: 0 and is slowed to nothing leaves the element invisible forever; not applying it at all is the only correct behaviour.

Utilities

Single-purpose helpers reading the same tokens: margins and gaps on the 4px scale, flex alignment, text sizes, role colours, two responsive visibility classes and a print block that hides navigation, footers and CTA bands.

This is the first file to drop if your project already has its own utilities — nothing else depends on it.

Rule of thumb

If you cannot point at the element on your page that needs a module, don't load it. A sign-in screen needs Core and Content; a docs page needs Core, Headers and Content.


Next: the token reference.

Other things you can poke

Every documentation page on this site has something interactive in it: swap page regions, retint a live page, change the type scale, see what each module unlocks, assemble your link block, frame a real page at 320px, weigh a page type, build an attribute list, turn the invisible guards on, flip a component through its states and filter the changelog by tag. All of it is radio inputs, checkboxes and :has() — no script runs any of it.