📖 Core Concept
Every HTML element is a rectangular box. The box model describes the layers around
that box: content → padding → border → margin.
Understanding this is fundamental — it controls all spacing and sizing in CSS.
MARGIN
BORDER
PADDING
CONTENT
width × height
/* THE #1 RULE: Always set box-sizing globally */*, *::before, *::after {
box-sizing: border-box;
/* width now INCLUDES padding + border */
}
.box {
width: 20rem; /* content area */padding: 1rem 2rem; /* inside the border */border: 2px solid; /* the edge */margin: 1rem auto; /* outside space, auto = center */
}
/* Individual sides */padding-top: 1rem; /* or: padding: T R B L */margin-left: auto; /* auto on horizontal = push */border-radius: 0.5rem; /* rounds corners */outline: 2px solid blue; /* OUTSIDE border, no layout impact */
box-sizing: border-box vs content-box comparison
box-sizing: border-box ✓
width: 12rem total = 12rem ✓
box-sizing: content-box ✗
width: 12rem total = 14rem ✗
02
Relative Units
📖 Why Relative Units?
Absolute units (px) are fixed. Relative units scale with context — the root font size,
parent element, or viewport. This makes designs accessible, responsive, and
maintainable. This entire page uses relative units throughout.
rem
Relative to root font-size (html). Best for font sizes and spacing. Scales with user preferences.
em
Relative to parent font-size. Cascades — can compound! Great for padding relative to text size.
%
Relative to parent dimension. width: 50% = half of parent. Vertical % often relative to parent width!
vw
1% of viewport width. 100vw = full window width. Fluid layouts and hero sections.
vh
1% of viewport height. 100vh = full screen height. Mind the mobile browser chrome!
ch
Width of the "0" character. Perfect for limiting text line length: max-width: 65ch.
clamp(min, ideal, max) — constrains a fluid value. The ideal is usually vw-based for fluid type.
/* Relative Units Reference *//* rem — scales with root font-size */html { font-size: 100%; } /* = 16px by default */h1 { font-size: 2.5rem; } /* 40px at 16px root *//* em — relative to current/parent font-size */button {
font-size: 1rem;
padding: 0.75em 1.5em; /* scales WITH the button's font-size */
}
/* Viewport units */.hero {
min-height: 100vh;
font-size: clamp(1.5rem, 4vw, 3rem); /* fluid! */
}
/* ch — optimal reading width */.article { max-width: 65ch; } /* ~65 chars per line *//* fr — grid fractions */.grid { grid-template-columns: 1fr 2fr 1fr; }
03
Flexbox
📖 1D Layout System
Flexbox arranges items in a single direction — either a row or column.
It excels at: centering things, distributing space, and aligning items
along an axis. Think of it as "smart row or column."
justify-content: space-between
A
B
C
D
flex: 1 (flex-grow) distributes remaining space
fixed
flex:1
flex:2
align-items: center (cross-axis alignment)
short
tall
tiny
/* FLEX CONTAINER */.container {
display: flex;
flex-direction: row; /* row | column | row-reverse */justify-content: space-between; /* main axis: flex-start | center | space-around */align-items: center; /* cross axis: flex-start | flex-end | stretch */flex-wrap: wrap; /* allow wrapping to next line */gap: 1rem; /* space between items (row-gap, column-gap) */
}
/* FLEX ITEMS */.item {
flex: 1; /* shorthand: flex-grow:1 flex-shrink:1 flex-basis:0 */flex-grow: 2; /* take 2x the remaining space */flex-shrink: 0; /* refuse to shrink */flex-basis: 10rem; /* starting size before grow/shrink */align-self: flex-end; /* override parent align-items */order: -1; /* visual reorder (negative = moves first) */
}
/* CENTERING TRICK (classic use case) */.center {
display: flex;
align-items: center;
justify-content: center;
}
04
CSS Grid
📖 2D Layout System
Grid works in TWO dimensions simultaneously — rows AND columns. Use it for
page-level layouts and complex component structures. Flexbox for components in
one direction; Grid for the overall page skeleton or 2D arrangements.
grid-template-columns: repeat(4, 1fr) — with spanning
1×1
span 2 cols
1×1
span 3 cols
row span 2
1×1
1×1
1×1
1×1
/* GRID CONTAINER */.grid {
display: grid;
grid-template-columns: repeat(4, 1fr); /* 4 equal columns */grid-template-columns: 16rem 1fr 1fr; /* fixed sidebar + 2 fluid */grid-template-rows: auto 1fr auto; /* header, main, footer */gap: 1rem; /* row and column gap */grid-template-areas:
"header header header"
"sidebar main main"
"footer footer footer";
}
/* GRID ITEMS */.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.wide-item {
grid-column: 1 / 3; /* from line 1 to line 3 */grid-column: span 2; /* span 2 columns from current pos */grid-row: span 2; /* span 2 rows */
}
/* RESPONSIVE GRID — no media queries needed! */.auto-grid {
grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
/* items wrap automatically when they can't fit */
}
05
Positioning
📖 The Stacking Context & Document Flowposition controls how an element is placed. Most values remove
the element from the normal document flow. The key insight: absolute
elements are positioned relative to the nearest ancestor with
position: relative (or absolute/fixed/sticky).
Live positioning example — hover the boxes
static (normal flow)relative (top:1rem left:2rem)
absolute (top:0.75rem right:0.75rem)
/* position values */.static { position: static; } /* default — in normal flow */.relative { position: relative; } /* offset but STAYS in flow (creates positioning context!) */.absolute { position: absolute; } /* OUT of flow, relative to positioned ancestor */.fixed { position: fixed; } /* OUT of flow, relative to VIEWPORT */.sticky { position: sticky; } /* in flow UNTIL threshold, then sticks *//* Offset properties (work with non-static) */top: 0;
right: 0;
bottom: 0;
left: 0;
inset: 0; /* shorthand for all four! *//* Stacking order */z-index: 10; /* higher = in front. Only works on positioned elements! *//* Classic centering with absolute */.centered {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
06
Selectors & Specificity
📖 Selecting the Right Element
CSS selectors are patterns that match elements. When multiple rules conflict,
specificity determines the winner.
Inline styles > #id > .class/:pseudo > element tag.
Count: (inline, IDs, classes, elements) — compare left to right.
Selector
Syntax
What it targets
Universal
*
Every element
Type
p, h1, div
Elements by tag name
Class
.card
Elements with class="card"
ID
#hero
Element with id="hero" (unique!)
Descendant
.nav a
Any <a> inside .nav
Child
.nav > li
Direct <li> children of .nav
Adjacent
h2 + p
First <p> immediately after h2
Sibling
h2 ~ p
All <p> siblings after h2
Attribute
[type="text"]
Elements by attribute value
Pseudo-class
:hover :nth-child(2n)
Element state or position
Pseudo-element
::before ::after
Virtual sub-elements
:is() / :where()
:is(h1, h2, h3)
Match any in list (:where has 0 specificity)
:not()
p:not(.special)
Exclude matching elements
/* SPECIFICITY: (inline, id, class, element) */p { color: black; } /* (0,0,0,1) */.text { color: blue; } /* (0,0,1,0) — wins over tag */#intro { color: red; } /* (0,1,0,0) — wins over class *//* style="..." *//* (1,0,0,0) — wins over #id *//* !important *//* nuclear option — avoid! *//* Modern approach: use :is() to group without specificity issues */:is(h1, h2, h3, h4) { line-height: 1.2; }
/* Attribute selectors */[href^="https"] { /* starts with */ }
[href$=".pdf"] { /* ends with */ }
[class*="icon"] { /* contains */ }
07
Animations & Transforms
📖 Performant Animation
For smooth 60fps animations, prefer transform and opacity.
These run on the GPU compositor thread and don't trigger layout recalculations.
Avoid animating width, height, top, left
— these cause expensive reflows!
📖 GPU-Powered Effectsfilter applies image processing effects visually — without touching
the actual image data. backdrop-filter blurs what's behind a
semi-transparent element, creating "frosted glass" effects.
Hover each box to see the filter activate!
📖 Dynamic, Cascading Values
CSS custom properties (variables) cascade like any CSS property —
child elements inherit them. This makes component-level theming trivial:
redefine the variable on a parent element and all children update instantly.
They're also writable from JavaScript!
Each card below uses the same CSS class, but different --t-accent variables:
Default
--t-accent: #c94a1f
Ocean
--t-accent: #4db8ff
Forest
--t-accent: #5acc5a
Sunset
--t-accent: #ff7a30
Lavender
--t-accent: #b070ff
/* DEFINE on :root for global access */:root {
--color-primary: #c94a1f;
--spacing-unit: 1rem;
--font-body: 'DM Sans', sans-serif;
}
/* USE with var() */.button {
background: var(--color-primary);
padding: var(--spacing-unit);
/* var(--name, fallback) — fallback if undefined */color: var(--text-color, white);
}
/* SCOPE to a component — overrides cascade down */.card-ocean {
--color-primary: #4db8ff; /* only affects this card and children */
}
/* CHANGE with JavaScript */// JSdocument.documentElement.style.setProperty('--color-primary', 'blue');
/* READ with JavaScript */getComputedStyle(el).getPropertyValue('--color-primary');
10
Responsive Design
📖 Mobile-First Strategy
Start with styles for the smallest screen, then use min-width media
queries to progressively enhance for larger screens. This keeps base CSS lean
and ensures mobile devices don't download unnecessary styles.
Modern CSS often eliminates media queries entirely with fluid units and Grid/Flex.
This grid responds to viewport — resize your browser window!
Col 1
Col 2
Col 3
Col 4
4 cols on desktop → 2 cols on tablet → 1 col on mobile
/* MOBILE-FIRST: base styles = mobile */.grid {
display: grid;
grid-template-columns: 1fr; /* single column on mobile */
}
/* ENHANCE for tablets (min-width = mobile-first) */@media (min-width: 48rem) { /* 768px */.grid { grid-template-columns: repeat(2, 1fr); }
}
/* ENHANCE for desktops */@media (min-width: 64rem) { /* 1024px */.grid { grid-template-columns: repeat(4, 1fr); }
}
/* USER PREFERENCE media queries */@media (prefers-color-scheme: dark) {
:root { --bg: #0e0e0e; --fg: #f5f0e8; }
}
@media (prefers-reduced-motion: reduce) {
* { animation: none !important; }
}
/* NO MEDIA QUERY needed with auto-fit */.fluid-grid {
grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
/* columns appear/disappear automatically! */
}
11
Pseudo-classes & States
📖 Styling Dynamic States
Pseudo-classes apply styles based on element state or position
in the DOM — without JavaScript. They're the backbone of interactive CSS.
Note: :focus-visible is preferred over :focus for
accessibility — it only shows focus rings for keyboard navigation.
Interact with these buttons — hover, click, tab, try disabled
:nth-child(2n) = even (red), :nth-child(3n+1) = 1st,4th,7th... (blue)
1
2
3
4
5
6
7
8
9
10
11
12
/* STATE pseudo-classes */a:hover { /* mouse over */ }
a:active { /* being clicked */ }
a:visited { /* already clicked */ }
:focus { /* any focus */ }
:focus-visible { /* keyboard focus only — prefer this! */ }
:checked { /* checkbox/radio checked */ }
:disabled { /* form element disabled */ }
:placeholder-shown { /* input showing placeholder */ }
:empty { /* element has no children */ }
:target { /* element matching URL hash */ }
/* STRUCTURAL pseudo-classes */:first-child { /* first sibling */ }
:last-child { /* last sibling */ }
:nth-child(2n) { /* every even element */ }
:nth-child(3n+1) { /* 1st, 4th, 7th... */ }
:nth-last-child(2) { /* 2nd from end */ }
:only-child { /* only child of parent */ }
:not(.special) { /* all EXCEPT .special */ }
:is(h1, h2, h3) { /* match any — inherits highest specificity */ }
:where(h1, h2, h3) { /* match any — always 0 specificity */ }
:has(img) { /* parent that contains an img */ }
12
Shapes & clip-path
📖 Pure CSS Shapesclip-path masks elements to any shape using geometry functions.
The visible area is defined by the shape — everything outside is invisible.
Hover any shape below to see it animate back to a rectangle!
Hover each shape — it animates to rectangle via clip-path transition
📖 Mixed-Unit Arithmeticcalc() is the only way to mix different CSS units in a computation.
This is enormously powerful: you can subtract a fixed header height from 100vh,
combine viewport units with rem-based padding, etc.
Always put spaces around + and - operators!
Widths computed with calc(), min(), max(), clamp()
calc(100% - 4rem)
min(100%, 30rem)
clamp(8rem, 50%, 22rem)
max(10rem, 25%)
/* calc() — mixed unit arithmetic */height: calc(100vh - 4rem); /* full height minus header */width: calc(50% - 1rem); /* half width minus gap */font-size: calc(1rem + 0.5vw); /* fluid with floor */padding: calc(var(--space) * 2); /* multiply a variable *//* Operators: + - * / (spaces required around + and -!) */calc(1rem + 8px)/* ✓ mixes units */calc(100% - 30px)/* ✓ subtract fixed from fluid */calc(3 * 2rem)/* ✓ multiply (unitless * unit) */calc(100px/2)/* ✓ divide (no spaces needed for /) *//* min() — picks smallest value */width: min(100%, 40rem); /* responsive max-width without @media! *//* max() — picks largest value */padding: max(1rem, 5%); /* at least 1rem, grows on wide screens *//* clamp(min, ideal, max) — fluid with guardrails */font-size: clamp(1rem, 2.5vw, 1.5rem); /* fluid type */gap: clamp(0.5rem, 2vw, 2rem); /* fluid spacing */
14
Typography Deep Dive
📖 Type as Design
Typography accounts for 95% of web design. CSS gives you incredible control:
font loading, weight, tracking, leading, optical sizing, and even gradient text.
Always use rem for font sizes so they respect user preferences.
font-weight: 100
The quick brown fox
font-weight: 300
The quick brown fox
font-weight: 400
The quick brown fox
font-weight: 700
The quick brown fox
letter-spacing: -0.05em
The quick brown fox
letter-spacing: 0.15em uppercase
The quick brown fox
line-height: 1 (tight)
The quick brown fox
font-style: italic
The quick brown fox
gradient text
The quick brown fox
/* Typography properties */font-family: 'Playfair Display', Georgia, serif; /* fallback chain */font-size: 1.125rem; /* always use rem for accessibility */font-weight: 700; /* 100-900 or bold/normal */font-style: italic; /* normal | italic | oblique */line-height: 1.6; /* unitless! scales with font-size */letter-spacing: 0.05em; /* tracking — em scales with size */word-spacing: 0.1em; /* between words */text-transform: uppercase; /* capitalize | lowercase */text-decoration: underline wavy var(--accent);
text-underline-offset: 0.2em;
text-indent: 2em; /* first line indent */text-align: justify; /* left | center | right | justify */text-wrap: balance; /* balances line lengths (modern!) *//* GRADIENT TEXT technique */.gradient-text {
background: linear-gradient(90deg, #c94a1f, #2563a8);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
/* @font-face — load custom fonts */@font-face {
font-family: 'MyFont';
src: url('font.woff2') format('woff2');
font-weight: 400 700; /* variable font range */font-display: swap; /* show fallback until loaded */
}