Every site ends up rebuilding the same handful of pages: a landing page, a 404, a terms page, an about page, a blog post. Different content, same underlying shapes — a nav bar, a heading with supporting text, some cards, a closing call to action, a footer. customizable.fscss is a pure CSS module for exactly that: the recurring page structure, built once, reused everywhere it's needed, with nothing forced on a page it doesn't use.
<script src="https://cdn.jsdelivr.net/npm/fscss@1.1.24/exec.min.js" defer></script>
<style>
@import((page-root, page-base, page-hero, page-btn, page-btn-primary) from customizable)
@page-root()
@page-base(body)
@page-hero(.page-hero)
@page-btn(.page-btn)
@page-btn-primary(.page-btn-primary)
</style>
<section class="page-hero">
<h1>A modern landing page, built entirely in CSS</h1>
<p>Swap the copy, drop in your own images, and it adapts down to any screen size.</p>
<a href="#" class="page-btn page-btn-primary">Get started</a>
</section>
Just CSS mixins compiled by FSCSS.
The core idea: components, not a template
Most page kits hand you one fixed layout and expect you to delete the parts you don't want. customizable.fscss works the other way — each piece is its own independent mixin, and a page imports only what it actually uses:
@import((page-root, page-base, page-404, page-btn, page-btn-primary) from customizable)
That's the entire import for a 404 page. No hero styles, no feature grid, no footer columns compiled in for a page that will never render them. A full marketing landing page pulls in more:
@import((*) from customizable)
Same module, two completely different outcomes, because the selection list decides what actually ships.
What's in it
- Navigation — sticky, blurred on scroll, wraps its links on narrow screens instead of overflowing
-
Hero section — fluid heading size via
clamp(), action buttons that stack full-width on mobile - Badge — a small pill with a glowing dot, for "now live" or version announcements
-
Images — three related mixins:
page-imgfor general content images,page-hero-imagefor a larger screenshot/mockup below the hero copy,page-figurefor an image-plus-caption pair inside long-form content - Buttons — a shared base plus primary/ghost variants
- Feature grid — auto-reflowing cards, collapses to one column on mobile
- CTA banner — a closing statement with its own gradient background
- Footer — split into a multi-column link grid and a separate copyright bar, so a page can use either independently
- 404 page — fills the viewport, centers itself, no dependency on anything else on the page
-
page-prose— a full typography scale for long-form content: terms of service, about pages, blog posts
One token layer drives everything
Every color, radius, spacing value, and font comes from a single set of CSS custom properties, written once by page-root:
@page-root()
:root {
--page-accent: #0fcbe8;
--page-radius: 12px;
}
Because every component reads from these variables instead of hardcoded values, that two-line override changes the accent color across the navigation, badges, buttons, and CTA banner at once. No hunting through component definitions to restyle a brand.
Responsive by default, not by afterthought
Every structural mixin carries its own breakpoint at 640px, written inside the mixin itself rather than as a separate stylesheet bolted on later. That means the responsive behavior travels with the component the moment it's imported — a page doesn't need to reimplement mobile handling for something it just pulled in. Stacked hero buttons, single-column feature grids, wrapped navigation links, and a reduced-column footer all come included.
Try it
<script src="https://cdn.jsdelivr.net/npm/fscss@1.1.24/exec.min.js" defer></script>
<style>
@import((*) from customizable)
</style>
Or compile ahead of time with the CLI for zero runtime dependency:
npm install -g fscss
fscss page.fscss page.css
Full documentation, every component's markup, the complete token reference, and known limitations are in the README: github.com/fscss-ttr/customizable.fscss
If a page type you build often isn't covered here, say so — that's usually where the next addition to the module comes from.
Top comments (0)