Skip to main content
    Courses/HTML & CSS/Flexbox Advanced Patterns

    Lesson 21 • Advanced Track

    CSS Flexbox: Advanced Patterns & Real Layouts

    By the end of this lesson you'll control exactly how flex items grow, shrink, and reorder themselves — and use that control to build the layouts real apps ship with: a sticky footer, the holy-grail page, and equal-height responsive card grids.

    What You'll Learn

    Read and write the flex shorthand: flex-grow, flex-shrink, flex-basis
    Override one item's alignment with align-self, and its position with order
    Wrap items onto multiple lines and space those lines with align-content
    Use gap for clean, consistent spacing instead of fragile margins
    Nest flex containers to build complex component layouts
    Build a sticky footer, holy-grail layout, and equal-height card grid
    Before this lesson: you should already know the Flexbox basics — turning on display: flex, the difference between the main and cross axis, and justify-content / align-items. If any of that feels shaky, review Flexbox Basics first, then come back for the advanced control.

    💡 Think of It Like This

    A flex container is a row of passengers sharing a bench seat. flex-basis is how much room each person needs before anyone budges. flex-grow is appetite for the empty space — a passenger with flex-grow: 2 spreads out into twice as much of the leftover bench as a neighbour on flex-grow: 1.

    flex-shrink is who gives way when the bench gets crowded: a higher number means "I'll squeeze in first." So the flex shorthand — grow shrink basis — is really just three answers to: how big do I start, how eagerly do I expand, and how willingly do I compress? Nail those three and every layout in this lesson becomes obvious.

    1. The flex Shorthand: grow, shrink, basis

    Three properties decide how a flex item is sized. flex-basis is the item's starting size along the main axis (its width in a row). flex-grow says how much of any leftover space it absorbs, as a ratio against its siblings. flex-shrink says how much it gives up when there isn't enough room. You almost always set all three at once with the flex shorthand.

    ShorthandMeansUse it for
    flex: 11 1 0%Equal columns, ignoring content size
    flex: auto1 1 autoGrow/shrink but respect content size
    flex: none0 0 autoFixed, never grows or shrinks
    flex: 0 0 200px0 0 200pxA rigid 200px sidebar

    Run the worked example. The same three boxes are shown with different flex values so you can see grow ratios, a fixed item, and a basis-driven start size side by side.

    Worked example: flex-grow, flex-shrink, flex-basis

    Three rows showing grow ratios, a fixed item, and flex-basis

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>flex shorthand</title>
      <style>
        * { box-sizing: border-box; margin: 0; padding: 0; }
        body { background:#0f172a; color:#e5e7eb; font-family: system-ui, sans-serif; padding:20px; }
        h3 { color:#3b82f6; margin:18px 0 8px; font-size:14px; }
    
        .row { display:flex; gap:8px; margin-bottom:6px; }
        .box { padding:14px; border-radius:8px; color:#fff; font-size:13px; text-align:center; }
        .a { background:#3b82f6;
    ...

    2. Overriding One Item: align-self & order

    align-items aligns every item on the cross axis. When you want one item to break ranks, align-self on that single child overrides the container's alignment just for it — handy for pushing one badge to the top while the rest sit centred.

    order changes the visual position of an item without touching the HTML. Items sort by their order value (default 0), low to high. It is perfect for reordering on different screen sizes — but remember it only moves things visually, so keyboard and screen-reader order still follow your HTML.

    Worked example: align-self and order

    One item breaks the alignment; order reshuffles without editing HTML

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>align-self & order</title>
      <style>
        * { box-sizing: border-box; margin: 0; padding: 0; }
        body { background:#0f172a; color:#e5e7eb; font-family: system-ui, sans-serif; padding:20px; }
        h3 { color:#3b82f6; margin:18px 0 8px; font-size:14px; }
    
        .row {
          display:flex;
          align-items:center;   /* default: all items vertically centred */
          gap:10px; height:120px;
          background:#1e293b; border-radius
    ...

    3. Wrapping: flex-wrap, align-content & gap

    By default flex items stay on one line and shrink to fit. Set flex-wrap: wrap and items that don't fit flow onto a new line instead — this is what turns a flex row into a responsive grid. Pair it with gap, which adds consistent spacing between items (and between wrapped rows) without the margin headaches.

    Once items wrap onto multiple lines, align-content spaces those lines along the cross axis — think of it as justify-content but for whole rows. It does nothing on a single-line container, which trips up a lot of people. Run the example and shrink the preview to watch items wrap and the rows space out.

    Worked example: flex-wrap + align-content + gap

    Items wrap to new lines; align-content distributes the rows

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>flex-wrap</title>
      <style>
        * { box-sizing: border-box; margin: 0; padding: 0; }
        body { background:#0f172a; color:#e5e7eb; font-family: system-ui, sans-serif; padding:20px; }
        p { color:#94a3b8; font-size:13px; margin-bottom:10px; }
    
        .wrap {
          display:flex;
          flex-wrap: wrap;            /* let items spill onto new lines */
         
    ...

    4. Nested Flex: the Holy-Grail Layout

    Real layouts are flex containers inside flex containers. The classic "holy grail" — header, two sidebars, a main column, and a footer — is just a vertical flex column whose middle row is itself a horizontal flex row. The outer column uses flex: 1 on the middle band so it fills the height; the inner row uses fixed-basis sidebars and a flex: 1 main.

    Note min-width: 0 on the main column — without it, long content would refuse to shrink and blow out the layout (more on that in Common Errors). On narrow screens, flex-wrap and a media query collapse everything into a single column.

    Worked example: holy-grail layout

    Header, sidebar, main, sidebar, footer — nested flex

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Holy Grail</title>
      <style>
        * { box-sizing: border-box; margin: 0; padding: 0; }
        body {
          background:#0f172a; color:#e5e7eb; font-family: system-ui, sans-serif;
          display:flex; flex-direction:column;   /* OUTER: vertical column */
          min-height:100vh;
        }
        header, footer { background:#1e293b; padding:15px 20px; text-align:cent
    ...

    5. Equal-Height Card Grid

    Cards with different amounts of text usually end up different heights — ugly. Flexbox fixes it twice over. First, align-items: stretch (the default on the cross axis) makes every card in a row the same height automatically. Second, make each card itself a vertical flex column and put margin-top: auto on the footer button — the auto margin soaks up spare space and pins the button to the bottom, so buttons line up across cards of any length.

    Worked example: equal-height cards with aligned buttons

    flex-wrap grid + nested column + margin-top:auto footer

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Equal-height cards</title>
      <style>
        * { box-sizing: border-box; margin: 0; padding: 0; }
        body { background:#0f172a; color:#e5e7eb; font-family: system-ui, sans-serif; padding:24px; }
        h1 { color:#3b82f6; margin-bottom:18px; font-size:1.3rem; }
    
        .grid {
          display:flex; flex-wrap:wrap; gap:16px;
          align-items: stretch;   /* every
    ...

    🎯 Your Turn #1 — A fixed sidebar with the flex shorthand

    Build a two-column row: a rigid 220px sidebar that never resizes, and a main column that fills the rest. Fill in the blanks marked ___, run it, and check the expected result in the comments.

    Your Turn #1: fixed sidebar + flexible main

    Use flex: 0 0 220px and flex: 1

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Your Turn 1</title>
      <style>
        /* 🎯 YOUR TURN — fill in the blanks marked ___ */
    
        * { box-sizing: border-box; margin: 0; padding: 0; }
        body { background:#0f172a; color:#e5e7eb; font-family: system-ui, sans-serif; padding:20px; }
    
        .layout { display:flex; gap:12px; }
    
        .sidebar {
          background:#1e293b; padding:16px; border-radius:10px;
          /* 1) Make this a RIGID 220px column: no grow, no shrink, basi
    ...

    🎯 Your Turn #2 — Wrap a grid and align one item

    Turn a flex row into a wrapping grid with even spacing, then make the "featured" tile jump to the front using order. Fill in the blanks and verify the expected behaviour in the comments.

    Your Turn #2: flex-wrap + gap + order

    Make items wrap, space them, and reorder one

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Your Turn 2</title>
      <style>
        /* 🎯 YOUR TURN — fill in the blanks marked ___ */
    
        * { box-sizing: border-box; margin: 0; padding: 0; }
        body { background:#0f172a; color:#e5e7eb; font-family: system-ui, sans-serif; padding:20px; }
    
        .grid {
          display:flex;
          /* 1) Let items spill onto new lines when they don't fit. */
          ___   
    ...

    🧩 Mini-Challenge — Equal-height pricing cards from scratch

    Support is faded now — only an outline is given. Build a row of pricing cards that stay equal height with their buttons aligned along the bottom. Use the worked examples in sections 3 and 5 as your reference if you get stuck.

    Mini-Challenge: pricing cards

    flex-wrap grid of equal-height cards with bottom-aligned buttons

    Try it Yourself »
    Code Preview
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Mini-Challenge</title>
      <style>
        /* 🧩 MINI-CHALLENGE: a row of equal-height pricing cards
           1. Make a .pricing container: display:flex, flex-wrap:wrap, gap:16px
           2. Give each .plan card  flex: 1 1 200px  so they wrap on small screens
           3. Make each .plan a NESTED column: display:flex; flex-direction:column
           4. Put margin-top
    ...

    ⚠️ Common Errors (and the fix)

    • Flex item overflows the page / won't shrink. Every flex item has min-width: auto by default, so a long word, a wide image, or a <pre> block stops it shrinking and blows out the layout. Fix: add min-width: 0 (or min-height: 0 in a column) to the item.
    • Confusing flex-basis with width. Setting both width and flex-basis is contradictory — flex-basis wins for the initial main-axis size. Fix: inside a flex container, size items with the flex shorthand (e.g. flex: 1 1 280px), not width.
    • "flex: 1 made my cards tiny." flex: 1 is 1 1 0% — a zero basis — so items collapse to equal fractions and ignore a minimum width. Fix: give them a real basis: flex: 1 1 280px.
    • align-content does nothing. It only spaces multiple lines. On a single-line container it has no effect. Fix: make sure flex-wrap: wrap is set and there is more than one row of items.
    • order broke keyboard navigation. order moves items visually but not in the DOM, so tab order and screen readers still follow the HTML. Fix: write the HTML in a sensible reading order and use order only for small visual tweaks.

    📋 Quick Reference

    GoalUse this
    Equal columns (ignore content)flex: 1;
    Card that wraps, min 280pxflex: 1 1 280px;
    Rigid 200px sidebarflex: 0 0 200px;
    Align one item differentlyalign-self: flex-end;
    Reorder visuallyorder: -1;
    Wrap onto new linesflex-wrap: wrap;
    Space wrapped rowsalign-content: space-between;
    Spacing between itemsgap: 16px;
    Pin a footer/button to bottommargin-top: auto;
    Stop overflow / allow shrinkmin-width: 0;

    ❓ Frequently Asked Questions

    What is the difference between flex-basis and width?

    flex-basis sets a flex item's size along the main axis (its width in a row, its height in a column) before flex-grow and flex-shrink redistribute leftover space. width is fixed and ignores that redistribution unless flex-shrink kicks in. The practical differences: flex-basis switches axis automatically with flex-direction, it wins over width when both are set on the same item, and flex-basis: 0 makes an item start from nothing so flex-grow shares space in pure ratios. Reach for flex-basis (usually via the flex shorthand) when an item lives in a flex container; reach for width when you want a hard size that grow and shrink leave alone.

    Why is my flex item overflowing its container instead of shrinking?

    By default every flex item has min-width: auto (or min-height: auto in a column), which means it refuses to shrink smaller than its content — a long word, a wide image, or a <pre> block sets a floor that flex-shrink cannot cross. The fix is to add min-width: 0 (or min-height: 0) to the item so it is allowed to shrink past its content and let overflow, text-overflow, or word-break handle the rest. This single line is the cure for the classic 'my flexbox blows out the page width' bug.

    What does flex: 1 actually mean?

    flex: 1 is shorthand for flex: 1 1 0% — flex-grow: 1, flex-shrink: 1, flex-basis: 0%. Because the basis is 0, every item starts from nothing and the whole container is shared out in proportion to the grow values, so three items with flex: 1 each become exactly equal thirds. That is different from flex: 1 1 auto (which factors in each item's content size first) and from flex: auto (which is flex: 1 1 auto). When you want equal columns regardless of content, flex: 1 is the right tool; when you want a minimum size that still grows, use flex: 1 1 280px.

    Should I use order to rearrange my layout?

    Use order for purely visual reordering — for example, moving a sidebar before the main content on wide screens while keeping the main content first in the HTML for screen readers and tab order. The key caveat is that order changes only the visual position, not the DOM order: keyboard focus and assistive tech still follow the source order, so a large mismatch confuses users. Use it sparingly and never as a substitute for writing the HTML in a sensible reading order.

    When should I use Flexbox instead of CSS Grid?

    Flexbox is one-dimensional: it lays items out along a single axis (a row or a column) and is ideal for distributing space inside that line — navbars, toolbars, button groups, centering, and content that should flow and wrap. CSS Grid is two-dimensional: it controls rows and columns at the same time and is the better choice for full page layouts and gallery grids where items must line up in both directions. A good rule of thumb: if you are thinking in a single line, use Flexbox; if you are thinking in a real grid of rows and columns, use Grid. They also compose well — a Grid page with flex containers inside its cells is common.

    What is the difference between justify-content, align-items and align-content?

    justify-content distributes space along the main axis (the direction your items flow). align-items aligns items along the cross axis within a single line. align-content only does something when items wrap onto multiple lines — it distributes the lines themselves along the cross axis, so on a single-line container it has no effect. If your align-content rule seems to be ignored, the usual reason is that flex-wrap is not set to wrap or there is only one line of items.

    🎉 Lesson Complete

    You can now bend Flexbox to any layout. The essentials:

    • flex: grow shrink basis — use flex: 1 for equal columns, flex: 1 1 280px for wrapping cards, flex: 0 0 200px for rigid sidebars
    • align-self overrides one item's cross-axis alignment; order moves it visually (not for screen readers)
    • flex-wrap: wrap + gap builds responsive grids; align-content spaces the wrapped rows
    • Nest flex containers for holy-grail layouts and equal-height cards with margin-top: auto
    • ✅ Remember min-width: 0 to stop content overflowing

    Next up: CSS Grid Level 2, where you'll handle true two-dimensional layouts that Flexbox can't do alone.

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy PolicyTerms of Service