Organising CSS at scale
On a big site, many rules from many people end up styling the same element, and the winner is decided by specificity, which nobody planned. Follow one heading through a real conflict: an id rule beats the component's class rule. Then fix it with three tools: BEM names that keep selectors to one class, a design token kept in a custom property, and cascade layers that let a later layer win before specificity is even compared. Last, change one token and watch the component follow.
5 quick questions
Pick an answer to see why. Your score saves with your progress.
01Without layers, #shop h2 { color: navy; } and .card__title { color: teal; } both match the same heading. Which colour does it get?
Specificity is compared ids first. #shop h2 has one id; .card__title has none. Source order only matters when specificity is equal.
02With @layer base, components; at the top, base holds #shop h2 { color: navy; } and components holds .card__title { color: teal; }. What colour is the heading?
The cascade compares layers before specificity. For normal declarations a later layer beats an earlier one, so components wins even though its selector scores lower.
03In BEM, what does the class card--sale name?
BEM is block__element--modifier. card is the block, card__title an element of it, and card--sale a modifier, a version of the card.
04:root { --brand: teal; } and .card__title { color: var(--brand); }. You change the first line to --brand: tomato. What happens?
Custom properties are inherited, so the heading sees --brand from :root. var(--brand) is replaced by the current value, so every rule that uses it follows the change.
05A rule is written outside any @layer block. How does it compare with layered rules (normal declarations)?
Unlayered styles count as coming after every layer, so they beat layered ones. That is why old code is often moved into an early layer when a site adopts layers.
Glossary
- Specificity
- A score for a selector, written ids,classes,tags. The browser compares ids first, then classes, then tags: #shop h2 is 1,0,1 and .card__title is 0,1,0.
- Cascade
- The browser's way of picking one value when several declarations set the same property on the same element.
- Cascade layer
- A named group of styles made with @layer. Layers are ordered by first mention, and a later layer beats an earlier one before specificity is compared.
- @layer statement
- A line such as @layer base, components; that creates layers and fixes their order before any styles are put in them.
- BEM
- Block, Element, Modifier: a naming method for classes, such as card, card__title and card--sale, so each part is styled with one class.
- Design token
- A named design value, such as the brand colour, kept in one place and reused everywhere. In CSS it is often a custom property.
- Custom property
- A property whose name starts with --, such as --brand. It is inherited and read with var(--brand).
- :root
- A pseudo-class that matches the document's root element, the <html> element in a web page.
Notes and sources
- A real browser runs the whole cascade at once, for every element and property. The figure splits it into steps: the first steps show the sheet without its layer lines, and the heading starts in the browser's default black until the first comparison. From then on, after every step the heading shows the colour a real browser would give that sheet.
- Styles outside any layer beat every layered style. That is why the heading stays navy while only components is wrapped, why the token on line 1 can stay unlayered, and why a site moving to layers puts its old rules in an early layer, as base is here. Wrap base first instead and the unlayered card rule would win at once.
- For declarations marked !important the layer order flips: an earlier layer's !important beats a later one's. This lesson only uses normal declarations.
- BEM is one naming method among several; the others share the same goal of short, single-class selectors. The HTML file is not drawn as a card; the browser only shows the heading's place in it: <h2 class="card__title"> inside <article class="card"> inside <div id="shop">.
- Save the full page as index.html and the card as style.css in the same folder and open the page: the heading is teal. Delete the @layer lines and it turns navy; set --brand to tomato and it turns tomato.
- W3C: CSS Cascading and Inheritance Level 5 (cascade sorting order, cascade layers)
- W3C: Selectors Level 4, calculating a selector's specificity
- W3C: CSS Custom Properties for Cascading Variables Level 1
- W3C: CSS Color Module Level 4, named colors
- MDN: Organizing your CSS (BEM, keeping specificity low)
- MDN: Cascade layers
- MDN: @layer
- MDN: Specificity
- MDN: Using CSS custom properties (variables)
- MDN: :root
Quiz Unlocks after the last step.