Skip to content

CSS Layers

Split project-wide CSS into the following three layers.

LayerRole
GlobalSite-wide values, functions, mixins, utilities
PagePer-page entry CSS (component placement)
ComponentComponent design with Block/Element + Variant/State

Global Layer

Responsible for site-wide settings, functions, mixins, resets, and utilities.

Exclude shared partials via Stylelint ignoreFiles; keep shared keyframes linted.
Details: Stylelint setup.

File structure by role

CategoryFilesRole
Settingsvariables.scss, global/config.scssColors, typography, spacing, breakpoints
Functions/Mixinsglobal/function.scss, global/mixin.scssNumeric conversions, media query generation, etc.
Base stylesreset.scss, base.scss, print.scssResets, element styles, print styles
Utilitiesutilities.scssSingle-purpose classes like .u-hidden, .u-sr-only
Shared animationskeyframes.scss@keyframes used across multiple components (kf- prefix)

Utility classes

Sparingly define single-purpose classes that don’t depend on structure or skin.

  • u- prefix required (e.g. .u-hidden, .u-sr-only)
  • Separate category from Block/Element (not subject to two-word/one-word rules)
  • Keep to the minimum reused site-wide

Shared animations

Centralize @keyframes used across multiple components in keyframes.scss.

  • Use a prefix like kf-
  • Place at root level only (not inside @media / @layer)

Component-specific @keyframes go in each component’s SCSS.
See File Management for details.

Page Layer

Per-page entry SCSS (e.g. home.scss, about.scss).

Role

  • Import components (@use)
  • Place child Blocks inside the page root class (e.g. .main-container)
  • Page-specific spacing, backgrounds, etc.

Scope

DoesDoes not
Import and place componentsDefine component internals
Adjust spacing between BlocksDefine Block internal layout

The page layer focuses on placing imported components. If you add page-layer classes, follow the same Block/Element rules and avoid styling internals of imported components.

Example

@use "@styles/partials/global" as *;
@use "@components/hero/hero-container";
.main-container {
> .hero-container {
// @components/hero/hero-container.scss
margin-top: 0;
}
}

Extract repeating page structures as shared components under components/parts/.

Page-layer root classes (e.g. .main-container) are not subject to “one Block per file”. Keep them within each page’s entry SCSS.

Component Layer

Consistent rules for Block/Element structure, Variant/State separation, SCSS sections, and file management.

  • Block (two words): the component itself (e.g. .hero-container)
  • Element (one word): an element within a Block (e.g. .title)
  • Variant / State: data attributes (default) or class mode
  • One Block per file: each Block maps to one SCSS file
  • @keyframes: component-specific ones go at root level, end of file

See Components for details.

Directory structure example

src/
├── styles/ # Global layer
│ └── partials/
│ ├── global/
│ │ ├── config.scss
│ │ ├── function.scss
│ │ ├── index.scss
│ │ └── mixin.scss
│ ├── base.scss
│ ├── keyframes.scss
│ ├── print.scss
│ ├── reset.scss
│ ├── utilities.scss
│ └── variables.scss
├── components/ # Component layer
│ ├── common/ # Site-wide shared
│ │ └── site-header/
│ │ └── site-header.scss
│ ├── parts/ # Multi-page shared
│ │ └── hero-banner/
│ │ └── hero-banner.scss
│ └── pages/ # Page-specific
│ ├── home/
│ │ └── home-hero/
│ │ └── home-hero.scss
│ └── about/
│ └── about-intro/
│ └── about-intro.scss
└── assets/
└── css/ # Page layer
├── home.scss
└── about.scss

Sample repository (simplified)

spiracss-scss-structure