Back to handbooks index
Engineer's Reference Handbook

CSS · SCSS · Flexbox
& HTML5

A comprehensive, production-depth reference covering modern HTML5 semantics, CSS architecture, SCSS tooling, legacy float layouts, and an in-depth flexbox guide with real patterns.

HTML5 CSS3 SCSS / SASS Flexbox Responsive
🧱
01 — HTML5

Semantic Elements

HTML5 introduced meaningful structural elements that replace generic <div> soup — improving accessibility, SEO, and maintainability.

Page Structure Elements

ElementRoleNotes
<header>Site or section headerCan appear inside <article>, <section> — not just <body>
<nav>Navigation links blockUse for primary/secondary navigation. Not every link group needs this.
<main>Primary page contentOnly one per page. Landmark for assistive tech.
<article>Self-contained contentBlog post, news item, widget — makes sense standalone
<section>Thematic groupingNeeds a heading. Use <div> when purely for styling
<aside>Complementary contentSidebars, pull-quotes, related links
<footer>Closing contentAuthor, copyright, related links — can nest in sections
<figure>Self-contained figureImages, charts, code snippets with caption
<figcaption>Caption for figureFirst or last child of <figure>
<address>Contact informationFor the nearest <article> or <body> author
<mark>Highlighted textSemantic highlight — not just styling
<time>Date/timeMachine-readable with datetime attribute
<details> / <summary>Disclosure widgetNative accordion — no JS needed
<dialog>Modal/popupNative modal with .showModal() JS API
<body>
  <header>
    <nav>
      <ul>
        <li><a href="/">Home</a></li>
      </ul>
    </nav>
  </header>

  <main>
    <article>
      <header>
        <h1>Article Title</h1>
        <time datetime="2025-05-13">May 13, 2025</time>
      </header>
      <section>
        <h2>Intro</h2>
        <p>Content here...</p>
      </section>
      <figure>
        <img src="chart.png" alt="Q3 metrics">
        <figcaption>Q3 Performance Chart</figcaption>
      </figure>
    </article>
    <aside>Related posts...</aside>
  </main>

  <footer>
    <address>Written by <a href="mailto:v@tcs.com">Vick</a></address>
  </footer>
</body>
💡
SEO + A11y win: Screen readers use these elements as landmarks. Search engines weight heading hierarchy and semantic structure. Always prefer semantic elements over generic <div> wraps.

HTML5 Form & Input Types

HTML5 added ~14 new input types with native validation, keyboard hints, and browser UI — replacing much custom JS.

TypePurposeKey Attributes
emailEmail addressvalidates @ format, mobile keyboard
telPhone numbernumeric keyboard on mobile
urlWeb URLvalidates protocol prefix
numberNumeric inputmin, max, step
rangeSlidermin, max, step, value
dateDate pickermin, max, native picker
datetime-localDate + timeNo timezone. Use with care.
timeTime onlyHH:MM format
colorColor pickerReturns hex value
searchSearch fieldShows × clear button
fileFile uploadmultiple, accept
hiddenHidden valueSubmitted with form, not shown
<form novalidate>
  <!-- native email validation -->
  <input type="email" required placeholder="you@example.com">

  <!-- constrained number -->
  <input type="number" min="0" max="100" step="5">

  <!-- native date/time -->
  <input type="date" min="2025-01-01" max="2025-12-31">

  <!-- pattern validation -->
  <input type="text" pattern="[A-Z]{3}[0-9]{4}" title="Format: ABC1234">

  <!-- datalist autocomplete -->
  <input list="langs">
  <datalist id="langs">
    <option value="TypeScript"><option value="Rust">
  </datalist>
</form>

Media & Interactive Elements

<video>

Native video with controls, autoplay muted, loop, poster, preload. Use <source> for format fallback.

<audio>

Native audio player. Same attributes. Supports MP3, OGG, WAV via <source> children.

<canvas>

2D/WebGL drawing surface via JS API. Used for games, charts, image processing.

<picture>

Art direction — serve different images per breakpoint or format (WebP vs JPEG fallback).

<template>

Inert HTML fragment — not rendered until cloned/inserted via JS. Foundation of Web Components.

<slot> / Custom Elements

Web Components API — define reusable encapsulated elements with shadow DOM.

<!-- Responsive image with WebP + JPEG fallback -->
<picture>
  <source srcset="img/hero.webp" type="image/webp"
          media="(min-width: 800px)">
  <source srcset="img/hero-sm.webp" type="image/webp">
  <img src="img/hero.jpg" alt="Hero" loading="lazy">
</picture>

<!-- Native details/summary accordion -->
<details>
  <summary>Click to expand</summary>
  <p>Hidden content shown on click. No JS needed.</p>
</details>

Meta & Document Head

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="description" content="Page description for SEO (150-160 chars)">
  <meta name="theme-color" content="#0a0c10">

  <!-- Open Graph (social preview) -->
  <meta property="og:title"       content="Page Title">
  <meta property="og:description"  content="...">
  <meta property="og:image"       content="https://...">
  <meta property="og:type"        content="website">

  <!-- Performance hints -->
  <link rel="preconnect"     href="https://fonts.googleapis.com">
  <link rel="preload"        href="critical.css" as="style">
  <link rel="prefetch"       href="next-page.html">

  <!-- PWA manifest -->
  <link rel="manifest"       href="/manifest.json">
</head>
🎨
02 — CSS Core

Selectors & Specificity

CSS selectors determine what gets styled. Specificity determines which rule wins when multiple rules match.

Selector Types

SelectorSyntaxExample
Universal** { box-sizing: border-box }
Typeelp { margin: 0 }
Class.cls.card { padding: 16px }
ID#id#app { max-width: 1200px }
Attribute[attr][disabled] { opacity: 0.5 }
Attribute value[attr="val"][type="submit"] { ... }
Attr contains[attr*="val"][class*="btn"] { ... }
Attr starts[attr^="val"][href^="https"] { ... }
DescendantA Bnav a { ... }
Direct childA > Bul > li { ... }
Adjacent siblingA + Bh2 + p { margin-top: 0 }
General siblingA ~ Blabel ~ input { ... }
:is():is(A, B):is(h1,h2,h3) { ... }
:where():where(A)Like :is() but zero specificity
:has()A:has(B)div:has(> img) { ... }
:not():not(A)li:not(:last-child) { ... }

Specificity Calculation

Specificity is a 3-part score: (ID, CLASS, TYPE) — higher always wins. Inline styles beat all. !important overrides everything (use sparingly).

SelectorScore (ID, CLASSorATTR, TYPE)
*(0, 0, 0) — no specificity
p(0, 0, 1)
.class(0, 1, 0)
#id(1, 0, 0)
p.card(0, 1, 1)
#nav .link:hover(1, 2, 0)
style=""(1, 0, 0, 0) — inline beats everything
!importantNuclear option — overrides all specificity
⚠️
Keep specificity flat in modern CSS. Deep selector chains like #app .sidebar ul li a.active create maintenance nightmares. Prefer BEM class-only selectors .sidebar__link--active.

Box Model

/* Default: box includes padding + border INSIDE the declared width */
* { box-sizing: border-box; } /* ← always set this globally */

.box {
  width:   300px;   /* content + padding + border = 300px total */
  padding: 20px;    /* shorthand: top right bottom left */
  border:  2px solid #333;
  margin:  16px auto; /* auto horizontally = center block elements */

  /* margin collapse: adjacent vertical margins collapse to the larger one */
  /* doesn't happen with flex/grid children or inline elements */
}

/* Outline = outside border, doesn't affect layout */
.focused { outline: 2px solid blue; outline-offset: 3px; }

Positioning

ValueIn flow?Offset relative toUse case
static✓ YesDefault. No top/left/right/bottom effect.
relative✓ YesItself (original position)Slight nudge; creates stacking context for children
absolute✗ NoNearest positioned ancestorTooltips, badges, overlays
fixed✗ NoViewportSticky headers, floating buttons
sticky✓ YesNearest scroll containerSection headers that stick while scrolling
/* Tooltip pattern: parent=relative, tooltip=absolute */
.btn-wrapper { position: relative; }
.tooltip {
  position: absolute;
  bottom:  calc(100% + 8px);
  left:    50%;
  transform: translateX(-50%);
}

/* Sticky nav */
header { position: sticky; top: 0; z-index: 100; }

/* z-index only works on positioned elements */
/* stacking context created by: position+z-index, opacity<1, transform, will-change */

Custom Properties (CSS Variables)

CSS Custom Properties are live, cascade-aware, and can be changed at runtime — unlike SCSS variables which are compile-time.

/* Define on :root for global scope */
:root {
  --color-primary:   #38bdf8;
  --color-bg:        #0a0c10;
  --spacing-base:    8px;
  --spacing-lg:      calc(var(--spacing-base) * 3);
  --radius:          8px;
  --font-sans:       'DM Sans', system-ui, sans-serif;
}

/* Use with var() */
.card {
  background:    var(--color-bg);
  border-radius: var(--radius);
  padding:       var(--spacing-lg);
  color:         var(--color-primary, #fff); /* fallback */
}

/* Scoped override — dark theme via class toggle */
[data-theme="light"] {
  --color-bg: #ffffff;
  --color-primary: #0369a1;
}

/* Change at runtime with JS */
document.documentElement.style.setProperty('--color-primary', '#f472b6');

Pseudo-classes & Pseudo-elements

Pseudo-classDescription
:hoverMouse over
:focus / :focus-visibleKeyboard focus. Prefer :focus-visible for styling.
:activeBeing clicked
:checkedCheckbox/radio checked
:disabled / :enabledForm element state
:valid / :invalidNative form validation state
:nth-child(n)By position. Supports formulas: 2n, 3n+1, odd, even
:nth-of-type(n)By position among same tag siblings
:first-child / :last-childFirst/last among siblings
:only-childSingle child of parent
:emptyNo children (incl. text nodes)
:not(sel)Negation
:rootDocument root — <html>
/* Pseudo-elements — double colon convention */
.card::before {         /* inserts before content */
  content: '';
  display: block;
  /* decorative element */
}
.card::after { content: ''; } /* inserts after content */

p::first-line  { font-weight: bold; }
p::first-letter{ font-size: 2em; float: left; }
::selection    { background: #38bdf8; color: #000; }
::placeholder  { color: #888; font-style: italic; }

/* Zebra rows without JS */
tr:nth-child(even) { background: #f5f5f5; }

Transitions & Animations

/* Transition — smooth property change on state */
.btn {
  background:  var(--accent);
  transition:  background 0.2s ease, transform 0.15s ease, box-shadow 0.2s ease;
}
.btn:hover {
  background:  var(--accent-dark);
  transform:   translateY(-2px);
  box-shadow:  0 8px 20px rgba(0,0,0,0.3);
}
/* transition shorthand: property duration timing-function delay */

/* Keyframe animation */
@keyframes slideInUp {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: translateY(0); }
}
.card {
  animation: slideInUp 0.4s cubic-bezier(0.16, 1, 0.3, 1) both;
}
/* animation shorthand: name duration timing fill-mode iteration-count direction */

/* Stagger cards using animation-delay */
.card:nth-child(1) { animation-delay: 0ms; }
.card:nth-child(2) { animation-delay: 80ms; }
.card:nth-child(3) { animation-delay: 160ms; }

/* Respect motion preference */
@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

Responsive Design

/* Mobile-first: write base styles for small, then expand up */

/* Common breakpoints */
@media (min-width: 640px)  { /* sm — tablet portrait */ }
@media (min-width: 768px)  { /* md — tablet landscape */ }
@media (min-width: 1024px) { /* lg — desktop */ }
@media (min-width: 1280px) { /* xl — wide desktop */ }

/* Container query — respond to parent width, not viewport */
.wrapper { container-type: inline-size; container-name: card; }
@container card (min-width: 400px) {
  .card__body { flex-direction: row; }
}

/* Fluid typography — scales between min and max */
h1 {
  font-size: clamp(1.8rem, 5vw, 3.5rem);
  /* clamp(min, preferred, max) */
}

/* Fluid spacing */
.section { padding: clamp(32px, 5vw, 80px); }

/* Feature queries */
@supports (display: grid) {
  .layout { display: grid; }
}
⚗️
03 — SCSS / SASS

Variables, Maps & Architecture

SCSS compiles to CSS. It adds variables, nesting, mixins, functions, and partials — enabling scalable, DRY CSS architecture.

Variables & Maps

// SCSS variables — compile-time, not live like CSS custom properties
$color-primary:  #38bdf8;
$color-bg:       #0a0c10;
$spacing-base:   8px;
$font-sans:      'DM Sans', sans-serif;

// Maps — key-value collections
$colors: (
  'primary':  #38bdf8,
  'success':  #34d399,
  'warning':  #fbbf24,
  'danger':   #f87171,
);

$spacing: (
  'xs': 4px,
  'sm': 8px,
  'md': 16px,
  'lg': 24px,
  'xl': 40px,
);

// Access map values
.alert { color: map.get($colors, 'danger'); }

// Generate utility classes from map
@each $name, $value in $colors {
  .text-#{$name} { color: $value; }
  .bg-#{$name}   { background-color: $value; }
}

Nesting & BEM

// SCSS nesting with BEM methodology
.card {
  background: var(--bg);
  border-radius: 8px;
  overflow: hidden;

  // & = parent selector
  &:hover {
    border-color: var(--accent);
  }

  &--featured {       // .card--featured (modifier)
    border: 2px solid var(--accent);
  }

  &__header {          // .card__header (element)
    padding: 20px;
    border-bottom: 1px solid var(--border);
  }

  &__title {           // .card__title (element)
    font-size: 18px;
    font-weight: 700;

    &--large {           // .card__title--large (element+modifier)
      font-size: 24px;
    }
  }

  &__body {
    padding: 20px;
  }
}

// Generates: .card, .card:hover, .card--featured,
//            .card__header, .card__title, .card__title--large, .card__body

Mixins & Functions

// Mixin — reusable block of declarations
@mixin flex-center($direction: row) {
  display:         flex;
  align-items:     center;
  justify-content: center;
  flex-direction:  $direction;
}

@mixin truncate($lines: 1) {
  @if $lines == 1 {
    overflow:      hidden;
    text-overflow: ellipsis;
    white-space:   nowrap;
  } @else {
    display:            -webkit-box;
    -webkit-line-clamp: $lines;
    -webkit-box-orient: vertical;
    overflow:           hidden;
  }
}

@mixin respond-to($bp) {
  $breakpoints: ('sm': 640px, 'md': 768px, 'lg': 1024px, 'xl': 1280px);
  @media (min-width: map.get($breakpoints, $bp)) { @content; }
}

// Usage
.hero {
  @include flex-center(column);
  @include respond-to('lg') { flex-direction: row; }
}
.card__title { @include truncate(2); }

// Function — returns a value
@function rem($px, $base: 16) {
  @return #{$px / $base}rem;
}
@function spacing($mult) {
  @return $mult * 8px;
}

.card { padding: spacing(3); font-size: rem(14); } // → 24px, 0.875rem

// Placeholder extend — shared styles without duplication
%visually-hidden {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0);
}
.sr-only { @extend %visually-hidden; }

Partials & @use Architecture

// Modern SCSS architecture — @use (replaces @import)
// File: _tokens.scss
$color-primary: #38bdf8;
$spacing-unit: 8px;

// File: _mixins.scss
@use 'tokens' as t;
@mixin card-base { padding: t.$spacing-unit * 2; }

// File: components/_card.scss
@use '../tokens' as t;
@use '../mixins';

.card {
  @include mixins.card-base;
  color: t.$color-primary;
}

// File: main.scss — entry point
@use 'tokens';
@use 'components/card';
@use 'components/button';
@use 'layouts/grid';

Control Flow

// @if / @else
@mixin theme-btn($theme) {
  @if $theme == 'primary' {
    background: $color-primary;
    color: white;
  } @else if $theme == 'outline' {
    background: transparent;
    border: 2px solid $color-primary;
  } @else {
    background: gray;
  }
}

// @for loop
@for $i from 1 through 5 {
  .col-#{$i} { flex: 0 0 percentage($i / 12); }
}

// @each loop
$sizes: sm 12px, md 16px, lg 20px, xl 24px;
@each $name, $size in $sizes {
  .text-#{$name} { font-size: $size; }
}

// @while loop (rare — prefer @for)
$i: 1;
@while $i <= 3 {
  .item-#{$i} { z-index: $i * 10; }
  $i: $i + 1;
}
🔧
04 — Float (Legacy)

How Floats Work & Float vs Flex

Floats were originally designed for text wrapping around images. They were repurposed for layouts for over a decade — with painful workarounds. Flex has replaced them for layout.

Float Basics

/* Float takes an element out of normal flow */
/* Remaining content wraps around it */

.image-left {
  float:  left;        /* left | right | none | inherit */
  margin: 0 16px 8px 0;
  width:  40%;
}

/* Problem: parent collapses to 0 height when all children are floated */
.container {
  /* background color won't show — parent height = 0 */
}

/* clear stops float wrapping */
.clear-both { clear: both; } /* left | right | both */

Clearfix Patterns

/* Classic clearfix — fixes collapsed parent */
.clearfix::after {
  content:  "";
  display:  table;
  clear:    both;
}

/* Modern alternative — overflow */
.container { overflow: hidden; } /* creates BFC, contains floats */

/* Even more modern — display: flow-root */
.container { display: flow-root; } /* ← cleanest solution today */

/* Two-column float layout (the old way) */
.sidebar { float: left; width: 30%; }
.content { float: right; width: 68%; }
.wrapper { display: flow-root; } /* contains them */

Float vs Flexbox — Comparison

⚰️ Float (Legacy Layout)
  • Designed for text wrapping, hacked for layout
  • Parent container collapses — needs clearfix
  • Vertical alignment is painful or impossible
  • Equal height columns require hacks
  • Reordering requires DOM changes
  • Complex responsive behavior
  • Still valid for: image+text wrap
✅ Flexbox (Modern)
  • Designed specifically for UI layout
  • Container automatically sizes to children
  • Vertical centering is trivial: align-items: center
  • Equal height columns by default
  • Visual reorder with order property
  • Responsive without media queries via wrap
  • Browser support: 98%+ global
📌
When to still use float: Text wrapping around an image (magazine-style layout). That's about it. For all layout purposes, use Flexbox or CSS Grid.
05 — Flexbox

Core Concepts & Mental Model

Flexbox is a one-dimensional layout model. It distributes space and aligns items in a single row or column. Understanding axes is the key to mastering it.

The Two Axes

Every flex layout has two axes. Properties target different axes — this is the most common source of confusion.

MAIN AXIS (horizontal when flex-direction: row)
Item 1
Item 2
Item 3
AxisDefault directionControls
Main axisHorizontal (row)justify-content, flex-grow, flex-shrink
Cross axisVertical (perpendicular)align-items, align-self, align-content
🧠
Mental model: When flex-direction: column, the axes swap. The main axis becomes vertical. So justify-content distributes vertically, and align-items aligns horizontally. Always think "main vs cross", not "horizontal vs vertical".
📦
05a — Flexbox

Container Properties

Applied to the flex parent element. These control how children are laid out.

display: flex

.container {
  display: flex;        /* or inline-flex for inline container */
  /* All direct children become flex items automatically */
}

flex-direction

Sets the main axis — the direction items flow.

ValueDescription
rowDefault. Left to right (LTR). Main axis = horizontal.
row-reverseRight to left. Items reversed.
columnTop to bottom. Main axis = vertical.
column-reverseBottom to top.

flex-wrap

Controls whether items can wrap onto multiple lines.

ValueDescription
nowrapDefault. Items shrink to fit. Never wraps.
wrapItems wrap to next line when needed. Most useful.
wrap-reverseWraps but cross-axis direction reversed.
/* flex-flow = shorthand for flex-direction + flex-wrap */
.container { flex-flow: row wrap; }

justify-content — Main Axis Alignment

Distributes space along the main axis (between items and around them).

ValueBehavior
flex-startDefault. Pack items to start of main axis.
flex-endPack items to end of main axis.
centerCenter items along main axis.
space-betweenFirst item at start, last at end, equal space between.
space-aroundEqual space around each item (half-space at edges).
space-evenlyEqual space between all items AND at edges.
start / endRespects writing-mode direction.

align-items — Cross Axis Alignment

Aligns items along the cross axis within each line.

ValueBehavior
stretchDefault. Items stretch to fill container height.
flex-startAlign to cross-axis start (top for row).
flex-endAlign to cross-axis end (bottom for row).
centerCenter along cross axis.
baselineAlign by text baseline. Useful for mixed font sizes.
first baseline / last baselineBaseline of first/last line of text.

align-content — Multi-line Cross Axis

Only has effect when there are multiple flex lines (with wrap). Distributes space between lines.

ValueBehavior
stretchDefault. Lines stretch to fill container.
flex-start / flex-endLines packed to start/end.
centerLines centered.
space-betweenFirst line at top, last at bottom, space in between.
space-around / space-evenlyEven spacing around/between lines.

gap

The modern, clean way to add spacing between flex items. No margin hacks needed.

.container {
  display: flex;
  gap: 16px;               /* uniform gap between items */
  gap: 16px 24px;          /* row-gap column-gap */
  row-gap: 12px;            /* between wrapped lines */
  column-gap: 20px;         /* between items in a row */
}
💡
Before gap, developers used margin-right on items and :last-child { margin-right: 0 }. The gap property is supported in all modern browsers and is far cleaner.
🔩
05b — Flexbox

Item Properties

Applied to individual flex children. These override container alignment and control sizing behavior.

order

Changes visual position without changing DOM order. Default is 0. Lower values appear first.

.first  { order: -1; }  /* appears before all order:0 items */
.second { order: 0; }   /* default */
.last   { order: 1; }   /* pushed to end */

/* Reorder sidebar on mobile */
@media (max-width: 768px) {
  .sidebar { order: 2; }  /* sidebar goes below content on mobile */
  .content { order: 1; }
}

align-self

Overrides align-items for a single item.

.container { align-items: flex-start; }
.special-item { align-self: flex-end; } /* this item aligns to bottom */
/* Values: auto | flex-start | flex-end | center | baseline | stretch */

flex-grow, flex-shrink, flex-basis

The three sizing properties that control how items grow, shrink, and start out. Understanding these deeply is the key to confident flex layouts.

flex-basis — Initial Size

/* Sets the initial main-axis size of an item, BEFORE distributing free space */
.item { flex-basis: auto; }      /* default: use item's width/height */
.item { flex-basis: 0; }         /* start at zero, let grow fill */
.item { flex-basis: 200px; }     /* fixed starting size */
.item { flex-basis: 30%; }       /* percentage of container */
.item { flex-basis: max-content; }/* size to content */

flex-grow — Growing

/* How much of the EXTRA space an item claims, relative to siblings */
/* Default: 0 — items don't grow */
.item-a { flex-grow: 1; }   /* claims 1 share of free space */
.item-b { flex-grow: 2; }   /* claims 2 shares — gets TWICE as much extra */
.item-c { flex-grow: 0; }   /* stays at flex-basis, no growth */

/* With 3 items of flex-grow: 1 — they split free space equally */
/* With 1, 2, 1 — middle item gets twice as much free space */

flex-shrink — Shrinking

/* How much an item shrinks when space is TIGHT, relative to siblings */
/* Default: 1 — items shrink equally */
.item-fixed { flex-shrink: 0; }   /* NEVER shrink — stays at flex-basis */
.item-fluid { flex-shrink: 1; }   /* shrinks if needed */
.item-fast  { flex-shrink: 3; }   /* shrinks 3x faster than siblings */

flex — Shorthand

/* flex: grow shrink basis */
.item { flex: 0 0 auto; }   /* no grow, no shrink, auto size — "rigid" */
.item { flex: 1 1 0; }    /* grow, shrink, start at 0 — "fluid" */
.item { flex: 1; }         /* same as: flex: 1 1 0 */
.item { flex: auto; }      /* same as: flex: 1 1 auto */
.item { flex: none; }      /* same as: flex: 0 0 auto — rigid */

/* Common: sidebar + fluid content */
.sidebar { flex: 0 0 260px; }   /* fixed width sidebar */
.content { flex: 1; }            /* takes all remaining space */
FLEX SIZING DEMO — sidebar(fixed) + content(grow:1) + actions(fixed)
Sidebar
flex: 0 0 80px
Main content — flex: 1 (grows to fill)
Actions
flex: none

Alignment Deep Dive

/* The centering one-liner — works in any direction */
.center-everything {
  display:         flex;
  justify-content: center;
  align-items:     center;
}

/* Space between with cross-axis stretch */
.spread {
  display:         flex;
  justify-content: space-between;
  align-items:     stretch; /* children fill height */
}

/* Push last item to far right — the "auto margin" trick */
.nav { display: flex; align-items: center; }
.nav .logo  { }
.nav .links { }
.nav .cta   { margin-left: auto; } /* consumes all remaining space */

/* Auto margin = flexible spacer */
/* Can push to any direction: margin-top: auto in column pushes item to bottom */

/* Sticky footer pattern */
body {
  display:        flex;
  flex-direction: column;
  min-height:     100vh;
}
main { flex: 1; } /* grows to push footer down */
footer { /* stays at bottom always */ }
🧩
05c — Flexbox Patterns

Real-World Layout Patterns

Production patterns using flexbox. Copy-paste ready.

Navigation Bar

/* Classic: logo left, links center, CTA right */
.navbar {
  display:         flex;
  align-items:     center;
  padding:         0 24px;
  height:          64px;
  gap:             24px;
}
.navbar__logo   { flex: 0 0 auto; }
.navbar__links  {
  display: flex; gap: 8px;
  flex: 1;                 /* take available space */
  justify-content: center; /* center the links */
}
.navbar__actions {
  flex: 0 0 auto;
  display: flex; gap: 8px;
}

/* Responsive: hide links on mobile */
@media (max-width: 768px) {
  .navbar__links { display: none; }
}

Card Grid with Responsive Wrap

/* Auto-responsive card grid without media queries */
.card-grid {
  display:   flex;
  flex-wrap: wrap;
  gap:       16px;
}
.card {
  flex: 1 1 280px;     /* grow, shrink, minimum 280px */
  /* items wrap when they'd go below 280px */
  /* auto-fills row width with as many cards as fit */
}

/* Strict 3-column — breaks to 2 then 1 */
.strict-grid .card { flex: 0 0 calc(33.333% - 11px); }
@media (max-width: 768px) {
  .strict-grid .card { flex: 0 0 calc(50% - 8px); }
}
@media (max-width: 480px) {
  .strict-grid .card { flex: 0 0 100%; }
}

All Centering Patterns

/* 1. Center in known-height container */
.container {
  display: flex; justify-content: center; align-items: center;
  height: 400px;
}

/* 2. Full-page centering (hero) */
.full-page-center {
  display: flex; justify-content: center; align-items: center;
  min-height: 100vh;
  flex-direction: column; /* stack elements vertically */
}

/* 3. Horizontal-only center */
.h-center { display: flex; justify-content: center; }

/* 4. Vertically center variable-height content */
.v-center { display: flex; align-items: center; min-height: 200px; }

/* 5. Icon + text inline vertical center */
.icon-text { display: flex; align-items: center; gap: 8px; }

Sidebar Layout

/* Fixed sidebar + fluid content */
.page-layout {
  display: flex;
  min-height: 100vh;
}
.sidebar {
  flex: 0 0 280px;      /* fixed 280px, never grow/shrink */
  position: sticky;
  top: 0; height: 100vh;
  overflow-y: auto;
}
.main-content {
  flex: 1;              /* takes all remaining width */
  min-width: 0;        /* CRITICAL: prevents overflow with long content */
}

/* Collapse sidebar on mobile */
@media (max-width: 768px) {
  .page-layout { flex-direction: column; }
  .sidebar { flex: 0 0 auto; position: static; height: auto; }
}
⚠️
Critical gotcha: When using flex: 1 on a content area that contains long text or code blocks, add min-width: 0. Without it, flex items refuse to shrink below their content's intrinsic minimum width — causing horizontal overflow.

Holy Grail Layout

/* Classic 3-column holy grail: header, 3 cols, footer */
body {
  display:        flex;
  flex-direction: column;
  min-height:     100vh;
}
header, footer { flex: 0 0 auto; }

.columns {
  display:   flex;
  flex:      1;         /* fills body between header/footer */
  gap:       0;
}
.col-left  { flex: 0 0 200px; }  /* left sidebar */
.col-main  { flex: 1; min-width: 0; } /* main content */
.col-right { flex: 0 0 200px; }  /* right sidebar */

@media (max-width: 768px) {
  .columns    { flex-direction: column; }
  .col-left   { order: 2; }  /* left sidebar below main on mobile */
  .col-main   { order: 1; }
  .col-right  { order: 3; }
}
📋
05d — Flexbox

Complete Cheat Sheet

All flex properties at a glance, organized by container vs item.

Container Properties — Quick Reference

PropertyValuesNotes
displayflex | inline-flexActivates flex context
flex-directionrow | row-reverse | column | column-reverseSets main axis
flex-wrapnowrap | wrap | wrap-reverseMulti-line wrapping
flex-flow[direction] [wrap]Shorthand for both above
justify-contentflex-start | flex-end | center | space-between | space-around | space-evenlyMain axis alignment
align-itemsstretch | flex-start | flex-end | center | baselineCross axis, single line
align-contentsame as justify-content + stretchCross axis, multi-line only
gap[row-gap] [col-gap]Space between items
row-gap<length>Between wrapped rows
column-gap<length>Between items in a row

Item Properties — Quick Reference

PropertyDefaultValuesNotes
order0<integer>Visual sort order
flex-grow0<number>Growth ratio. 0 = don't grow
flex-shrink1<number>Shrink ratio. 0 = don't shrink
flex-basisautoauto | <length> | 0Initial size before grow/shrink
flex0 1 auto[grow] [shrink] [basis]Shorthand. prefer using this
align-selfautoauto | flex-start | flex-end | center | baseline | stretchOverrides align-items
min-widthauto0 | <length>Set to 0 to allow shrinking below content

Common Flex Patterns — One-Liners

/* Perfect center */
.center { display: flex; justify-content: center; align-items: center; }

/* Space between header items */
.header { display: flex; justify-content: space-between; align-items: center; }

/* Equal-width columns */
.equal-cols > * { flex: 1; }

/* Fixed sidebar + fluid main */
.layout { display: flex; }
.sidebar { flex: 0 0 260px; }
.main { flex: 1; min-width: 0; }

/* Responsive wrap */
.grid { display: flex; flex-wrap: wrap; gap: 16px; }
.grid > * { flex: 1 1 240px; }

/* Sticky footer */
body { display: flex; flex-direction: column; min-height: 100vh; }
main { flex: 1; }

/* Push item to end (auto margin trick) */
.nav .cta { margin-left: auto; }
.col .cta { margin-top: auto; } /* push to bottom of column */

/* Inline icon + text */
.btn { display: inline-flex; align-items: center; gap: 8px; }

/* Card with footer pinned to bottom */
.card { display: flex; flex-direction: column; height: 100%; }
.card__body { flex: 1; }
.card__footer { margin-top: auto; }

Common Gotchas & Fixes

ProblemCauseFix
Item overflows containerflex-shrink: 1 but min-width: auto prevents shrinkingAdd min-width: 0 to the item
Images stretch weirdlyalign-items: stretch stretches img to full heightalign-items: flex-start or align-self: flex-start on image
Items not equal heightNot using flex on the rowParent gets display: flex, children default to align-items: stretch
Gap not workingOld browserUse margin + :last-child { margin: 0 } as fallback
justify-content: center not centeringChild has width: 100%Remove full width from child, or use text-align: center instead
flex: 1 not sharing equallyItems have different content sizes and flex-basis: autoUse flex: 1 1 0 (basis 0) to share from zero
Vertical scroll inside flex childFlex child has no explicit height limitAdd overflow-y: auto; min-height: 0 to the child
🏆
Flex vs Grid rule of thumb: Use Flexbox for 1D layouts — rows or columns (navbars, card rows, button groups, stacks). Use CSS Grid for 2D layouts — rows AND columns together (page layouts, data tables, image galleries). They compose perfectly: a Grid page layout can contain Flex navbars inside.