SCSS structure#
How the styles are divided, in what order they stack, and where to reach when
building a new theme. Root: www/themes/<branch>/<theme>/desktop/assets/scss/.
The entry point and the order#
Everything starts in style.scss. The import order is binding — it decides
who overrides whom:
@use "utilities"; // the whole of Bootstrap, self-hosted
@use "abstracts" as *; // tokens, functions, mixins — emits NO CSS at all
@use "base"; // reset, general styles, utility classes
@use "components"; // the system's UI components
@use "layout"; // header, footer, main, parts, sections
@use "modules"; // styles of Nette components, split per module
@use "custom"; // ← the ONLY place for this theme's deviations
| Layer | What is in it | Touch it? |
|---|---|---|
utilities/ |
Bootstrap from node_modules |
no |
abstracts/ |
tokens, functions, mixins (emits not one line of CSS) | token values only |
base/ |
reset, typography, skins, utility classes | no |
components/ |
buttons, cards, forms… — the shared design system | no |
layout/ |
structural parts of the page | no |
modules/ |
styles of Nette components, per module | no |
custom/ |
this theme's deviations | yes, exclusively here |
Deviations belong exclusively in custom/
Everything above it is a shared base other themes use too. An edit straight in
components/ or base/ propagates to places nobody expects — and it surfaces
only when an entirely different theme breaks.
Bootstrap: BOTH branches use it, but differently#
The front end does use Bootstrap — all of it
A widespread misconception. Front-end templates stand directly on its
components: modal in forty templates, collapse and toast in twenty each,
dropdown and offcanvas in fifteen each, carousel in nine. Hence the whole
bundle, not a subset.
| Front end | Administration | |
|---|---|---|
| Where from | utilities/_bootstrap.scss → node_modules |
webpack → assets/dist/styles.css |
| What | all of Bootstrap | all of Bootstrap |
| When it loads | first, before the theme | before style.css (linked by _head.latte) |
| Why that way | Bootstrap is the base, the theme overrides it | the admin has its own components; utilities with !important must win |
In the administration @use \"utilities\" is DELIBERATELY commented out
It added the grid and utility API a second time at the end. Measured, not
guessed: removing it made style.css 79,857 B smaller and all 58 admin
pages stayed pixel-identical. Do not restore it "for the sake of the cascade" —
utilities carry !important, so they win from the first copy anyway.
Do not bring back the CDN link in either branch
Without an internet connection the styling would fall apart, and the version on
a CDN changes under your hands. One source (node_modules), one version for
both branches.
Your own display may override Bootstrap
A rule of the same specificity wins by order. Solve it with scope (nesting it
under your own class), not with !important.
Tokens#
Two levels, each with its own job:
| Level | Where | What for |
|---|---|---|
| Base | abstracts/_vars.scss |
palette, typography, spacing, radii, shadows, z-index |
| Component | next to the component itself | the component's "local API" — what can be changed from outside |
// components/_cards.scss — a token is the component's interface
.card {
--card-bg: var(--color-surface);
--card-radius: var(--border-radius);
background: var(--card-bg);
border-radius: var(--card-radius);
}
Never write a literal value into a component
A #2ecc8a inside a component means a new theme cannot be recoloured by
changing a token. The value belongs in a token; the component reads the token.
A component token belongs in the component's scope
Not in :root. Then the code itself shows what the component offers — and a
theme can override it without disturbing the others.
Component token values reference base tokens
--card-bg: var(--color-surface), not a concrete colour. Otherwise recolouring
the palette only works halfway.
A new theme, step by step#
- Copy the skeleton from
template1— the whole ofassets/scss/,layouts/,assets/js/. - Rewrite
custom/_vars-override.scss— only the tokens that differ from the system default (the primary colour with its full 100–900 scale, the typeface, the radius, section spacing). - Sections into
custom/sections/— header, hero, footer; your theme's own look, not an edit oflayout/. - Page-level deviations into
custom/pages/<module>/— when one page behaves differently from the rest. - Build it and walk the component catalogue — it shows everything the token change moved.
A new theme need not copy components
It inherits the whole design system and overrides only tokens. Reaching into
components/ is almost always a sign that a token is missing — and adding one
beats duplicating the component.
Building#
npx sass is not the same as sass
They are different compiler versions and can produce different output. Use the one the theme is normally built with.
Without a build, an SCSS change shows up nowhere
The site reads css/style.css, not the sources. A missing build looks like "my
edit does not work" and nobody connects it with the fact that nobody compiled it.
Things to watch out for#
An older component may have no styles in a new theme
It looks like broken rendering, but the rules are simply absent. Before fixing anything, check in the catalogue whether the component was ever styled in the theme — otherwise you are fixing something that never worked and looking for the cause in the wrong place.
Design-kit classes are NOT theme classes
The design kit and the theme use different naming. A chunk of markup copied from the design will not pick up any styling — and missing styling looks exactly like a bug in the code. More in Design system.