EXSA
Generate custom CSS
Layouts
EXSA ships with three composable page layouts and two starter templates — drop-in CSS files that turn semantic HTML zones into complete page shells. Each layout is a single CSS file. Link the one you need, add its classes to <body>, and structure your HTML with the documented zones.

How Layouts Work

Every layout follows the same pattern:
1. Link the layout CSS after exsa.css (and a theme, if you use one — themes are optional).
2. Add the layout's body classes to <body>.
3. Structure your HTML with the documented zone elements.
Layouts use the topbar component's --topbar-height variable, so body padding automatically matches your topbar size (topbar--sm, topbar--xl, etc.).

General Layout
The compositional page shell. Add toggle classes to <body> to activate zones — topbar, hero, sidebar, content, footer. Designed for documentation sites, reference pages, and content-heavy UIs.

Body Classes

ClassEffect
layout--has-topbarReserves space for a fixed topbar
layout--has-heroFull-bleed hero below topbar
layout--aside-leftLeft sidebar + content flex row
layout--aside-rightRight sidebar + content flex row
layout--has-sidebarShorthand for layout--aside-left
Dashboard-style modes (layout--aside-full, layout--full-height, layout--content-scroll, layout--aside-collapsed) moved to dist/layouts/dashboard.css — use dash--sidebar, dash--topbar, dash--sidebar-sm.
layout--centeredSingle column, max-width constrained
layout--sticky-footerFooter at viewport bottom
layout--aside-stickySidebar sticks on scroll
layout--topbar-fullTopbar spans full viewport width
layout--topbar-contentTopbar aligns with content area
layout--footer-fullFooter spans full viewport width
layout--footer-contentFooter aligns with content area

CSS Tokens

TokenDefaultDescription
--topbar-height56pxSynced with topbar.css size variant
--layout-aside-left-w260pxLeft sidebar width
--layout-aside-right-w260pxRight sidebar width
--layout-hero-min-h55vhHero minimum height

Zone Diagram

TOPBAR — .topbar (fixed, z-index: 1000)
HERO — <header> (classless, full-bleed, optional)
ASIDE
.layout__aside-left
(260px, sticky)
CONTENT
.layout__content
(flex: 1, scrolls)
ASIDE
.layout__aside-right
(260px, sticky)

Starter HTML

Show starter template
HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <link rel="stylesheet" href="exsa/dist/exsa.css">
  <link rel="stylesheet" href="exsa/dist/themes/breeze.css">
  <link rel="stylesheet" href="exsa/dist/components/topbar.css">
  <link rel="stylesheet" href="exsa/dist/components/sidebar.css">
  <link rel="stylesheet" href="exsa/dist/components/footer.css">
  <link rel="stylesheet" href="exsa/dist/layouts/general.css">
</head>
<body class="exsa layout--has-topbar layout--aside-left layout--aside-sticky">

  <!-- Topbar -->
  <header class="topbar topbar--xl">
    <div class="topbar__left">...</div>
    <div class="topbar__right">...</div>
  </header>

  <!-- Shell: sidebar + content -->
  <div class="layout__shell">

    <aside class="sidebar layout__aside-left">
      <ul class="sidebar__nav">...</ul>
    </aside>

    <main class="layout__content">
      <!-- Your page content -->
    </main>

  </div>

  <footer class="footer">...</footer>

</body>
</html>
Blog Layout
Centered, reading-optimized layout for articles, documentation, and prose-heavy pages. Blog mode is merged into dist/layouts/general.css — use the shared layout--* classes for the topbar/hero and blog--* classes for the prose features.

Body Classes

ClassEffect
blog--has-tocSticky table-of-contents sidebar
blog--proseTypography boost (larger text, generous spacing)
blog--wideWider content (720px → 980px)
blog--fullwidthRemove max-width constraint
Topbar/hero/footer: use the shared layout--has-topbar, layout--has-hero, layout--sticky-footer classes.

CSS Tokens

TokenDefaultDescription
--topbar-height56pxSynced with topbar.css
--layout-content-w720pxReadable line length

Starter HTML

Show starter template
HTML
<link rel="stylesheet" href="exsa/dist/layouts/general.css">

<body class="exsa layout--has-topbar blog--has-toc blog--prose">

  <header class="topbar">...</header>

  <div class="blog__shell">
    <main class="blog__content">
      <article>
        <h1>My Blog Post</h1>
        <p>Article content...</p>
      </article>
    </main>
    <aside class="blog__toc">
      <a href="#">Introduction</a>
      <a href="#">Section 1</a>
    </aside>
  </div>

  <footer class="footer">...</footer>

</body>
Dashboard Layout
Full-viewport admin panel / app shell. Fixed sidebar, scrollable content area, optional right detail panel. Body is 100dvh tall (mobile-safe) with hidden overflow — the content pane handles its own scroll. Responsive: below 1024px the sidebar auto-collapses to icon mode (opt out with dash--sidebar-fixed); below 768px it becomes an overlay drawer with backdrop (toggle dash--sidebar-open on <body>).

Body Classes

ClassEffect
dash--sidebarFixed full-height left sidebar
dash--sidebar-smAlways-collapsed icon-only sidebar
dash--sidebar-fixedOpt out of auto-collapse / drawer (never collapses)
dash--sidebar-openMobile: drawer expanded (JS toggles; shows backdrop)
dash--sidebar-darkDark background sidebar variant
dash--topbarFixed topbar above content
dash--topbar-fullTopbar spans full width (over sidebar)
dash--panelOptional right detail panel
dash--denseCompact density — overrides the scaling factors

CSS Tokens

TokenDefaultDescription
--dash-sidebar-w260pxSidebar width (scales with --space-factor, min 224px)
--dash-sidebar-sm56pxCollapsed sidebar width (scaled, min 52px)
--topbar-height56pxTopbar height (from topbar.css; scaled by dashboard)
--dash-panel-w320pxRight panel width (scaled, min 280px)
--dash-padding32pxContent gutter (.dash__content-inner)
--dash-panel-padding24pxRight panel padding
--dash-gap16pxGrid / card / toolbar spacing
--dash-col-min180pxMin column width for .dash-grid
--dash-toolbar-z89Sticky toolbar layer

Starter HTML

Show starter template
HTML
<link rel="stylesheet" href="exsa/dist/layouts/dashboard.css">

<body class="exsa dash--sidebar dash--topbar dash--sidebar-dark dash--dense">

  <aside class="dash__sidebar">
    <div class="dash__sidebar-head">Admin</div>
    <ul class="sidebar__nav">...</ul>
  </aside>

  <div class="dash__backdrop"></div>  <!-- mobile drawer backdrop (≤767px) -->

  <header class="topbar">
    <button class="topbar__toggle">☰</button>  <!-- opens the drawer on mobile -->
    ...
  </header>

  <main class="dash__content">
    <div class="dash__content-inner">
      <!-- .dash-grid > .dash-card.dash-stat | .dash__toolbar + table -->
    </div>
  </main>

</body>

Responsive & Density

Auto icon-collapse — below 1024px the sidebar shrinks to icon mode automatically; add dash--sidebar-fixed to keep it expanded.
Mobile drawer — below 768px the sidebar slides in over the content as a drawer with a backdrop. Toggle dash--sidebar-open on <body> (the topbar toggle button works out of the box; close via backdrop click or Escape).
Density — the whole shell (sidebar, topbar, paddings, gaps) consumes --space-factor and --font-factor. Use dash--dense or data-profile="compact" for control-heavy apps, data-profile="spacious" for consumer dashboards.

Content Primitives

ClassPurpose
.dash-cardPanel card — sizes --sm/--lg, slots __head, __title, __sub
.dash-gridAuto-fit responsive grid — tune min column width via --dash-col-min
.dash-statKPI card — __label, __value (+ --num mono/tabular), __delta (+ --up/--down)
.dash__toolbarSticky filter bar — sits just below the topbar above tables
Store Layout
Ecommerce product catalog with announcement bar, cart topbar, filter sidebar, product grid, and sticky footer.

Body Classes

ClassEffect
shop--announcePromo announcement bar above topbar
shop--topbarFixed topbar with cart/search
shop--heroFull-bleed promo banner
shop--sidebarLeft filter/category sidebar
shop--sidebar-rightRight sidebar (cart summary)
shop--sticky-footerFooter at viewport bottom

CSS Tokens

TokenDefaultDescription
--topbar-height56pxSynced with topbar.css
--shop-sidebar-w260pxFilter sidebar width
--shop-announce-h40pxAnnouncement bar height
--shop-hero-min-h40vhHero minimum height

Starter HTML

Show starter template
HTML
<link rel="stylesheet" href="exsa/dist/layouts/store.css">

<body class="exsa shop--announce shop--topbar shop--sidebar shop--sticky-footer">

  <div class="shop__announce">🚀 Free shipping on orders over $50</div>

  <header class="topbar">
    <!-- Cart, search, account links -->
  </header>

  <div class="shop__shell">

    <aside class="shop__aside">
      <div class="shop__aside-group">
        <div class="shop__aside-title">Categories</div>
        <a href="#">Clothing</a>
      </div>
    </aside>

    <main class="shop__content">
      <div class="shop__grid">
        <div class="shop__card">
          <img class="shop__card-image" src="product.jpg">
          <div class="shop__card-body">
            <div class="shop__card-title">Product</div>
            <span class="shop__card-price">$24.99</span>
          </div>
        </div>
      </div>
    </main>

  </div>

  <footer class="footer">...</footer>

</body>
Fullpage Layout
Single-viewport landing page. Full-screen backdrop — a video/image cover or a seamless panned tile — under a centered brand block with social icon rings and a bottom copyright gradient. Optional logo mark, nav row, and pure-CSS :target content panels (Dimension-style). Pure CSS with a staggered entrance, prefers-reduced-motion safe. Starter template with a hardcoded palette — copy the dist/templates/fullpage/ folder, open index.html, and edit.

Body Class & Zones

ClassEffect
layout--fullpageActivates the fullpage shell (add to <body>)
.fullpage__backdropFull-viewport backdrop — first img/video covers
.fullpage__backdrop--panSeamless scrolling tile (set --fullpage-pan-image)
.fullpage__veilPattern + gradient above the backdrop
.fullpage__contentCentered brand block (h1 + tagline)
.fullpage__socialIcon rings under the tagline (needs icons.css)
.fullpage__logoOptional CSS-diamond mark above the title
.fullpage__navLink row under the tagline
.fullpage__panelFull-screen overlay — opens via :target (href="#panel-id")
.fullpage__panel-close✕ that closes panels — link it to the shell id (#home)
.fullpage__copyrightBottom gradient footer

Tokens

TokenDefaultPurpose
--fullpage-fontvar(--font-family)Brand font
--fullpage-base-font-size15ptPage scale (13pt / 12pt below 1680 / 1280px)
--fullpage-pan-imagenoneSeamless tile for --pan mode (required)
--fullpage-pan-distance2250pxTile width (1500px below 1680px)
--fullpage-pan-duration60sOne scroll loop
--fullpage-pan-color#348cb2Base color behind the tile
--fullpage-patternnoneOptional texture over the backdrop
--fullpage-overlaydark gradientGradient above the backdrop
--fullpage-social-size2.5emIcon ring diameter
--fullpage-logo-size5.5emLogo ring diameter
--fullpage-nav-gapclamp(10px,2vw,24px)Nav link spacing
--fullpage-panel-bgrgba(14,15,21,.97)Panel background
--fullpage-panel-width620pxPanel content width

Starter HTML

Copy-paste starter
HTML
<body class="exsa layout--fullpage">

  <!-- Backdrop: media cover -->
  <div class="fullpage__backdrop" aria-hidden="true">
    <video src="bg.mp4" muted autoplay loop playsinline></video>
  </div>
  <!-- OR seamless tile:
  <div class="fullpage__backdrop fullpage__backdrop--pan" aria-hidden="true"></div>
  -->

  <div class="fullpage__veil" aria-hidden="true"></div>

  <main class="fullpage__content">
    <header class="fullpage__brand">
      <h1>Your Name</h1>
      <p>Tagline &bull; goes &bull; here</p>
      <nav class="fullpage__social" aria-label="Social links">
        <a href="#" aria-label="X"><span class="ic ic-social-x"></span></a>
        <a href="#" aria-label="GitHub"><span class="ic ic-social-github"></span></a>
        <a href="#" aria-label="Email"><span class="ic ic-mail"></span></a>
      </nav>
    </header>
  </main>

  <footer class="fullpage__copyright">
    <span>&copy; 2026 Your Name.</span>
  </footer>

</body>
Starter with panels (Dimension-style)
HTML
<main class="fullpage__content" id="home">
  <header class="fullpage__brand">
    <div class="fullpage__logo" aria-hidden="true"></div>
    <h1>Title</h1>
    <p>Tagline</p>
    <nav class="fullpage__nav">
      <a href="#intro">Intro</a>
      <a href="#contact">Contact</a>
    </nav>
  </header>
</main>

<div class="fullpage__panels">
  <a href="#home" class="fullpage__panel-close" aria-label="Close">✕</a>
  <article class="fullpage__panel" id="intro">
    <div class="fullpage__panel-inner">
      <h2>Intro</h2>
      <p>Panel content — text, images, forms.</p>
    </div>
  </article>
  <article class="fullpage__panel" id="contact">
    <div class="fullpage__panel-inner">
      <h2>Contact</h2>
      <form method="post" action="#">
        <div class="fullpage__fields">
          <div><label for="name">Name</label><input type="text" id="name"></div>
          <div><label for="email">Email</label><input type="email" id="email"></div>
          <div class="full"><label for="message">Message</label><textarea id="message" rows="4"></textarea></div>
        </div>
        <button type="submit" class="btn btn--primary">Send</button>
      </form>
    </div>
  </article>
</div>

<!-- Panels are pure CSS: #intro opens the panel, ✕ (#home) closes it. -->
Onepage Layout
Multi-section marketing landing page — full-viewport photo hero with a top nav and nested hover dropdowns, headline banner, carousel reel, featured article, card grid, and a dark 3-column footer. Pure CSS (dropdowns, smooth anchor scrolling), no JavaScript required except the optional carousel component. Starter template with a hardcoded palette — copy the dist/templates/onepage/ folder, open index.html, and edit.

Body Class & Zones

ClassEffect
layout--onepageActivates the onepage shell (add to <body>)
.onepage__headerFull-viewport photo hero (nav + brand + action)
.onepage__navTop nav with nested hover dropdowns (pure CSS)
.onepage__heroBrand block: logo, hr, tagline, circled Start button
.onepage__bannerWhite headline band
.onepage__sectionWhite content band (--alt = #fafafa)
.onepage__section-headCentered section title + subtitle
.onepage__gridResponsive card grid
.onepage__articleFeatured article (image + copy + button)
.onepage__footerDark footer: columns, icons, copyright

Tokens

TokenDefaultPurpose
--onepage-max-wvar(--width-content)Container width
--onepage-body-bg#f0f4f4Page background
--onepage-section-bg#fffContent band background
--onepage-heading#483949Heading color
--onepage-accent#ef8376Link / highlight color
--onepage-accent-hover#df7366Accent hover
--onepage-header-bgphoto + veilHero backdrop (gradient + image)
--onepage-footer-bg#2b252cFooter background
--onepage-icon-size2.5emCircled icon diameter

Starter HTML

Copy-paste starter
HTML
<link rel="stylesheet" href="exsa/templates/onepage.css">

<body class="exsa layout--onepage">

  <header class="onepage__header" id="header">
    <nav class="onepage__nav" aria-label="Main">
      <ul>
        <li><a href="#header">Home</a></li>
        <li><a href="#work">Work</a></li>
      </ul>
    </nav>
    <div class="onepage__hero">
      <h1><a href="#header" class="onepage__logo">Brand</a></h1>
      <hr>
      <p>Your tagline</p>
      <a href="#banner" class="btn">Start</a>
    </div>
  </header>

  <section class="onepage__banner" id="banner">
    <h2>Hi. You're looking at <strong>Brand</strong>.</h2>
    <p>A short intro paragraph.</p>
  </section>

  <section class="onepage__section" id="work">
    <div class="onepage__container">
      <header class="onepage__section-head">
        <h2>What we do</h2>
        <p>Section subtitle</p>
      </header>
      <div class="onepage__grid">
        <article class="card card--hoverable">
          <img class="card__image" src="img.jpg" alt="">
          <div class="card__body">
            <h3 class="card__title">Feature</h3>
            <p class="card__text">Copy...</p>
          </div>
        </article>
      </div>
    </div>
  </section>

  <footer class="onepage__footer">
    <div class="onepage__container">
      <div class="onepage__cols">
        <section class="onepage__col">
          <header class="onepage__col-head">Column</header>
          <ul class="onepage__list">
            <li>Item <span class="onepage__timestamp">2 days ago</span></li>
          </ul>
        </section>
      </div>
    </div>
  </footer>

</body>
Background System
Token-driven image backgrounds for any page or section — works with every layout. Add bg-page and set --bg-image; size, position, repeat, parallax, veils, blend modes, and filters are one class each. Link dist/components/background.css after exsa.css + your theme.

Quick Setup

Copy-paste starter
HTML
<link rel="stylesheet" href="exsa/dist/components/background.css">

<!-- Page background: cover + fixed parallax + dark readability veil -->
<!-- Note: use root-relative paths — urls resolve against the CSS that consumes them -->
<body class="exsa bg-page bg-cover bg-fixed bg-veil--dark"
      style="--bg-image:url('/img/bg.jpg')">

  <!-- Section hero: centered, no repeat, custom overlay -->
  <section class="bg-page bg-center bg-no-repeat"
           style="--bg-image:url('/img/hero.jpg'); --bg-overlay:rgba(17,139,238,.25); min-height:60vh;">
    ...
  </section>

  <!-- Pattern tile: dot-grid, repeat -->
  <div class="bg-page bg-pattern">...</div>

  <!-- Multiple layers + blend -->
  <body class="exsa bg-page bg-blend--multiply"
        style="--bg-image:url('/img/photo.jpg'), linear-gradient(var(--color-secondary), var(--color-link))">
</body>

CSS Tokens

TokenDefaultDescription
--bg-imagenoneBackground image — comma-separate for layers. Use root-relative paths (/img/bg.jpg): urls resolve against the consuming stylesheet
--bg-colorvar(--color-bg)Color behind the image (loading fallback)
--bg-sizecovercover | contain | auto | custom
--bg-positioncentercenter | top | bottom | left | right
--bg-repeatno-repeatno-repeat | repeat | repeat-x | repeat-y
--bg-attachmentscrollscroll | fixed (parallax) | local
--bg-overlaytransparentVeil color/gradient above the image
--bg-blendnormalnormal | multiply | screen | overlay | soft-light
--bg-filternoneImage filter — grayscale(1), sepia(.65), blur(4px)…

Utility Classes

ClassEffect
.bg-pageActivates the background (image + veil pseudo-layers)
.bg-cover / .bg-contain / .bg-autoImage sizing
.bg-center / .bg-top / .bg-bottom / .bg-left / .bg-rightImage position
.bg-repeat / .bg-repeat-x / .bg-repeat-y / .bg-no-repeatImage tiling
.bg-fixed / .bg-scroll / .bg-localParallax / attachment — fixed auto-falls-back under prefers-reduced-motion
.bg-veil--dark / .bg-veil--light / .bg-veil--gradient / .bg-veil--colorReadability overlays above the image
.bg-blend--multiply / .bg-blend--screen / .bg-blend--overlay / .bg-blend--softBlend the image with the layers beneath it
.bg-blurBackdrop blur only — apply to your own panels
.glass / .glass--strong / .glass--darkComplete glass panels — translucent bg + blur + light border + shadow
.bg-grayscale / .bg-sepiaFilters the image only — content stays untouched
.bg-patternTiled SVG dot-grid — override --bg-pattern-image / --bg-pattern-size
.bg-noneRemove the background
Combining Layouts
Layouts are independent CSS files with their own namespaces — they don't conflict. You can link multiple layout files on one page if you need hybrid behavior, but typically you choose one layout per page.
If you need...Use
Documentation site with sidebargeneral.css
Blog, articles, prosegeneral.css (blog mode)
Admin panel, dashboarddashboard.css
Web store, product catalogstore.css
Single-viewport landing pagedist/templates/fullpage/
Multi-section marketing landing pagedist/templates/onepage/

Quick Rules

  • One layout per page. General + blog on the same body will fight over padding. Pick one.
  • Link order matters. Layout CSS goes after exsa.css, theme, and component CSS.
  • Topbar height auto-syncs. Both general.css and store.css use --topbar-height with :has() — swap topbar--sm for topbar--xl and body padding updates automatically.
  • Components work in any layout. Sidebar.css, footer.css, card.css — they're layout-agnostic. Use them everywhere.
  • Tokens are your knobs. Override --topbar-height, --layout-aside-left-w, etc. in your theme to customize spacing.