Chapter 17 of 17 · CSS for Beginners — Complete Free Tutorial

CSS Variables & Specificity

The final chapter connects everything: custom properties (CSS variables) for maintainable design systems, and the full explanation of the cascade — how the browser decides which rule wins.

Defining and using variables

:root {
  --brand: #4f46e5;
  --brand-dark: #4338ca;
  --radius: 0.75rem;
  --space: 1.25rem;
}

.btn-primary {
  background: var(--brand);
  border-radius: var(--radius);
}
.btn-primary:hover {
  background: var(--brand-dark);
}

Rules: names are case-sensitive and must start with --; the value is a token of almost anything (colors, lengths, even whole selectors via --val). Use var() at usage time, never store a variable inside another's declaration without a fallback.

Fallbacks

color: var(--accent, #4f46e5);            /* used if --accent is missing */
padding: var(--space, 1rem);

Where variables live matters

  • Declare in :root for globals; they inherit everywhere like font-size.
  • Re-declare on a component to override for that subtree:
    .dark-panel {
      --bg: #0f172a;
      --text: #e2e8f0;
      background: var(--bg);
      color: var(--text);
    }
  • Variables do not inherit from a class you did not nest under — always define them on an ancestor of their consumers.

Theming without JavaScript

:root {
  --bg: #ffffff;
  --text: #0f172a;
}
[data-theme="dark"] {
  --bg: #0f172a;
  --text: #e2e8f0;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #0f172a;
    --text: #e2e8f0;
  }
}
body { background: var(--bg); color: var(--text); }

Toggle by setting <html data-theme="dark">; respecting the OS setting is the default. Expected output: the entire site flips theme with one attribute change — every consumer of --bg/--text updates at once.

Math with variables

:root { --base: 16px; --scale: 1.25; }
h1 { font-size: calc(var(--base) * var(--scale) * var(--scale)); }

The cascade: how a winner is chosen

When multiple rules hit the same element, the browser asks, in order:

  1. Origin & importance — normal order: agent (browser defaults) < user < author (yours). !important flips each order, so author-!important beats author-normal but loses to user-!important.
  2. Specificity — if origins tie, the more specific selector wins (below).
  3. Source order — exact tie: the last rule in the stylesheet wins.

Specificity scoring

Score each selector as a-b-c:

SlotCountsExample → score
a — inline stylestyle="…"style="color:red" → 1-0-0-0
b — idsNumber of #id#main → 0-1-0-0
c — classes/attrs/pseudo-classesEach counts 1.card:hover → 0-0-2-0
d — elements/pseudo-elementsEach counts 1li::before → 0-0-0-2
p                 { color: black; }   /* 0-0-0-1 */
.lead              { color: blue; }    /* 0-0-1-0  → wins */
#content .lead     { color: red; }     /* 0-1-1-0  → wins again */
section .lead      { color: green; }   /* 0-0-2-0  → beats .lead */
a:hover            { color: purple; }  /* 0-0-2-0  → beats plain a */

!important overrides normal declarations regardless of specificity — but it is a debt: it makes the next override harder. Reach for it only for true one-offs (browser quirk fixes, utility overrides), and fix "my style doesn't apply" by reducing competing specificity or reordering, not by escalating.

Inheritance

Some properties flow down from the parent: font-family, font-size, line-height, color, text-align, letter-spacing… Others do not: margins, padding, borders, width, height, background. Control it with:

.widget { color: inherit; }            /* take parent value */
.reset  { all: unset; }                /* nuke everything (use carefully) */
input   { font: inherit; }             /* forms don't inherit by default */

Cascade strategies that scale

  • Class-only styling — no ids for styling; keeps specificity flat (0-0-1-0 everywhere).
  • Low & uniform specificity — beats fighting: the later rule wins naturally.
  • Layers — modern CSS can organise origins of your own: @layer base, components, utilities; — layer order beats specificity for clean overrides (worth knowing as you advance).
  • Tokenise — colours/spacing/typography as variables in one place; components consume them.

Common mistakes

  • Escalating specificity arms race — !important → #id → more !important. Stop; restructure or reorder.
  • Defining variables too deep — a variable declared on .card cannot be seen by siblings.
  • Typo in var() — --brand-color vs --brandcolor silently yields the fallback/initial value; dev tools highlights custom property usage.
  • Overriding an id rule from a component file — you'll need equal specificity; better never to have written the id rule.

Practice checklist

  1. Move your palette into :root variables and swap every hard-coded colour.
  2. Build a dark theme with data-theme + prefers-color-scheme.
  3. Write two conflicting rules and predict the winner before inspecting — then verify.

Where to go next

You now have the complete CSS toolkit: selectors, box model, Flexbox, Grid, responsive techniques, motion, and architecture. Put it together by:

  • Rebuilding a favourite website's landing page from scratch.
  • Reading the HTML semantic structure chapter again and styling every semantic element properly.
  • Making it interactive with the JavaScript for Beginners course — toggles, form validation, API data and animations on click.
  • Exploring Scriptly's other tutorials and practice problems to keep the streak going.

Quiz: CSS Variables & Specificity

5 questions · 70% to pass

Frequently Asked Questions

CSS (Cascading Style Sheets) is the language that controls how HTML content looks — colours, fonts, spacing, layout, responsiveness and animation. HTML provides structure and meaning; CSS provides presentation. One stylesheet can restyle an entire website at once.

The fundamentals (selectors, box model, Flexbox, media queries) take about 2–3 weeks of daily practice. Grid, animations and architecture come with a little more practice. This 17-chapter series is designed for 3–4 weeks at a relaxed pace — faster if you type out every example.

Yes. HTML first, then CSS, then JavaScript. CSS and HTML together let you build complete, good-looking static pages, and almost every JavaScript framework assumes you already know CSS layout and selectors.

No — CSS is a styling language with selectors and property-value declarations, not variables, loops or conditionals. You can get far without any programming logic, and JavaScript adds the behaviour later.

Flexbox distributes space along one axis (a row or a column) and is ideal for components — toolbars, navbars, card rows. Grid controls rows and columns together and is ideal for page structure and card grids. They are complementary: many layouts use a grid page shell with flex components inside.

Usually one of three reasons: the selector does not match (check class names), a more specific rule wins (use the browser inspector to see computed styles and specificity), or the file is not linked/loads in the wrong order. The specificity chapter explains how the cascade decides.

Every element is a box of four layers: content, padding (inner space), border, and margin (outer space). With box-sizing: border-box, the width you set includes padding and border — the universal reset every project uses.

Use relative units, flexible grids like repeat(auto-fit, minmax(260px, 1fr)), images with max-width: 100%, and mobile-first media queries. The goal is zero horizontal scrolling from 320px up — the responsive chapters show the full workflow.

Not to learn. Frameworks are productivity tools built on the same CSS you are learning here; understanding the fundamentals makes any framework easier to use (and to debug when it fights you). Learn vanilla CSS first, then evaluate frameworks with an informed eye.

JavaScript for interactivity, then a build tool and version control (Git). With HTML, CSS and JavaScript you can build complete websites; after that, frameworks like React or server-side tools like Laravel Blade build on these fundamentals.