Lesson 2 of 4
The box model, specificity and the cascade
2 min read
Box model
Every element is a box: content → padding → border → margin.
.card { width: 300px; padding: 20px; border: 1px solid #ddd; }
/* content-box (default): rendered width = 300 + 40 + 2 = 342px */
*, *::before, *::after { box-sizing: border-box; }
/* border-box: rendered width stays 300px; padding and border fit inside */Almost every modern stylesheet starts with box-sizing: border-box.
Margin collapsing: vertical margins between block elements merge into the larger one (20px + 30px → 30px, not 50px). It doesn't happen inside flex or grid containers.
Display
block: full width, starts on a new line (div,p,h1).inline: flows in text; width, height and vertical margins don't apply (span,a).inline-block: flows inline but accepts width and height.none: removed from layout (vsvisibility: hidden, which keeps the space).flex/grid: layout modes for children.
Specificity
When rules conflict, the more specific selector wins; on a tie, the later one wins.
| Selector | Specificity (inline, id, class, element) |
|---|---|
p | 0,0,0,1 |
.card p | 0,0,1,1 |
#main .card p | 0,1,1,1 |
style="..." | 1,0,0,0 |
!important overrides all of it; use it as a last resort. Keep selectors flat (single classes) so styles stay predictable. That's the idea behind BEM (.card__title--active) and utility frameworks like Tailwind.
Positioning
static: normal flow (default).relative: normal flow, nudged withtop/left; becomes the anchor for absolute children.absolute: removed from flow, positioned against the nearest positioned ancestor.fixed: positioned against the viewport (sticky headers, chat buttons).sticky: normal until it hits a scroll offset, then sticks (table headers, sidebars).
z-index only works on positioned elements (and flex/grid items), and only compares within the same stacking context. That's why a z-index: 9999 modal sometimes still appears behind something.
Units
px fixed; rem relative to the root font size (use for font sizes and spacing so user font settings work); em relative to the element's font size; % relative to the parent; vw/vh relative to the viewport; ch for readable line lengths (max-width: 65ch).
Check yourself
- What's the rendered width of a 300px box with 20px padding in content-box vs border-box?
- Which wins:
.nav aor#header a? - Why might a high
z-indexnot bring an element to the front?
Sign up free to save your progress.