Notifications

No notifications

/Phase 1

CSS Layout

CSS Layout β€” Flexbox, Grid & Positioning

Modern CSS provides two powerful layout systems: Flexbox for one-dimensional layouts and CSS Grid for two-dimensional layouts. Combined with positioning and stacking contexts, you can build any design.

Flexbox (One-Dimensional)

PropertyValuesPurpose
displayflexActivates flex container
flex-directionrow, columnMain axis direction
justify-contentcenter, space-between, …Alignment on main axis
align-itemscenter, stretch, …Alignment on cross axis
flex-wrapwrap, nowrapAllow wrapping
gap1remSpace between items

CSS Grid (Two-Dimensional)

PropertyValuesPurpose
displaygridActivates grid container
grid-template-columns1fr 1fr 1frDefine columns
grid-template-rowsauto 1fr autoDefine rows
gap1remSpacing between cells
grid-column1 / 3Span columns (child)
place-itemscenterAlign cell content

Positioning

static    β†’ Normal flow (default)
relative  β†’ Offset from normal position
absolute  β†’ Positioned relative to nearest positioned ancestor
fixed     β†’ Positioned relative to viewport
sticky    β†’ Scrolls normally then sticks at threshold

Z-Index & Stacking Contexts

z-index only works on positioned elements (relative, absolute, fixed, sticky). A new stacking context is created by elements with z-index, opacity < 1, transform, or filter. Children cannot escape their parent's stacking context.

On this page

Detailed Theory

Why Layout Used to Be Hard

For years, web layout was a hack-fest of float, clearfix, and tables-pretending-to-be-layouts. Modern CSS gives you two purpose-built tools that solve 95% of layouts:

  • Flexbox β€” for one direction at a time (a row OR a column).
  • Grid β€” for two directions at once (rows AND columns).
Learn these two and you can lay out almost any design.

Display: The First Layout Decision

Every element has a display value that controls how it flows:

ValueBehaviour
blockNew line, full width (
,

,

)

inlineSits in the line of text (, , )
inline-blockInline-flowing but accepts width/height
flexChildren become flex items (1-D layout)
gridChildren become grid items (2-D layout)
noneRemoved from layout entirely

Flexbox β€” Layout in One Direction

Set display: flex on a *parent* and its direct children become flex items. By default they sit in a row, side by side.

.row {
  display: flex;
  gap: 16px;            /* space between children */
  align-items: center;  /* vertical alignment */
  justify-content: space-between; /* horizontal distribution */
}

The Six Properties You'll Use 99% of the Time

On the parent:

PropertyCommon valuesDoes what
flex-directionrow / columnLay items horizontally or vertically
justify-contentflex-start / center / space-between / space-aroundDistribution along the main axis
align-itemsstretch / center / flex-start / flex-endAlignment on the cross axis
gapany lengthSpace between items (replaces margin tricks)
flex-wrapnowrap / wrapAllow items to drop to a new line

On the child:

PropertyDoes what
flex: 1Grow to fill remaining space
flex: 0 0 200pxDon't grow, don't shrink, basis 200 px
align-self: centerOverride parent's align-items for one item
margin-left: autoPush this item to the far right (handy in nav bars)

Centering β€” the Old Meme, Now Trivial

.parent {
  display: flex;
  justify-content: center; /* horizontal */
  align-items: center;     /* vertical */
  min-height: 100vh;
}

CSS Grid β€” Layout in Two Directions

Grid lets you draw a table of cells and place items into them.

.layout {
  display: grid;
  grid-template-columns: 1fr 3fr; /* sidebar + main */
  grid-template-rows: auto 1fr auto; /* header, body, footer */
  gap: 16px;
  min-height: 100vh;
}

The fr Unit

fr is a *fraction of remaining space*. After fixed widths and gaps are subtracted, every fr shares what's left.

grid-template-columns: 200px 1fr 1fr;
/* 200px sidebar, then two equal fluid columns */

Repeat & Auto-Fit β€” Magical Responsive Grids

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1rem;
}

Translation: "fit as many β‰₯220px columns as you can; share leftover space equally; no media queries needed". This single line gives you a responsive card grid.

Placing Items by Name

Name your areas, then assign children to them:

.layout {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-areas:
    "header  header"
    "sidebar main"
    "footer  footer";
}
.header  { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main    { grid-area: main; }
.footer  { grid-area: footer; }

Flexbox vs Grid β€” When to Reach for Which

Use Flexbox when…Use Grid when…
Items flow in one directionYou need rows *and* columns
Item sizes are content-drivenThe container defines the structure
You're building a navbar, toolbar, button rowYou're building a page layout, dashboard, card grid
You want items to wrap naturallyYou want explicit cell placement

You can β€” and should β€” nest them: a Grid page layout containing Flex navbars and card rows.

Positioning β€” When Things Need to Float Above the Page

position removes elements from the normal flow:

ValueBehaviour
staticDefault. Normal flow.
relativeStays in flow but you can nudge with top/left. Establishes a containing block.
absoluteRemoved from flow. Positioned relative to the nearest positioned ancestor.
fixedRemoved from flow. Positioned relative to the viewport (sticks while scrolling).
stickyActs relative until you scroll past a threshold, then fixed.

A common pattern: a parent with position: relative containing a child with position: absolute for things like badges or tooltips.

Intermediate: Stacking Context & z-index

z-index only works on positioned elements. It can be confusing because it lives inside a *stacking context*. A new stacking context is formed when an element has:

  • position: relative
absolutefixed
sticky and a z-index other than auto
  • opacity less than 1
  • transform, filter, perspective, clip-path
  • isolation: isolate (a great way to deliberately fence off a section)
  • Children are painted in this order inside their context:

    1. Background & borders of the context element 2. Children with negative z-index 3. Non-positioned flow content 4. Positioned children (ascending z-index)

    If two siblings live in different contexts, their z-index numbers don't compete with each other.

    Intermediate: Auto Margins Are Secretly Powerful

    In flexbox, an auto margin absorbs all extra space:

    .nav { display: flex; gap: 16px; }
    .nav .logout { margin-left: auto; } /* push to far right */

    Cleaner than justify-content: space-between when you only need one item separated.

    Intermediate: Subgrid (Modern Browsers)

    Lets a nested grid inherit the row/column tracks of its parent β€” perfect for aligning items inside cards to a global grid.

    .card { display: grid; grid-template-rows: subgrid; }

    Advanced: Container Queries

    Until recently you could only respond to *viewport* size. Container queries let a component respond to *its own* size:

    .card { container-type: inline-size; }

    @container (min-width: 400px) { .card .image { float: left; } }

    Now the same card component lays itself out differently in a sidebar vs the main area, no JavaScript needed.

    Advanced: Aspect Ratio

    Maintain a 16:9 ratio without padding tricks:

    .video { aspect-ratio: 16 / 9; width: 100%; }

    Advanced: Intrinsic Sizing Keywords

    min-content, max-content, and fit-content() size things to their *content*:

    .tag { width: max-content; }     /* exactly as wide as the text */
    .btn { width: fit-content(200px); } /* up to 200px, smaller if content is shorter */

    Practice Path

    1. Build a navbar (logo on left, links centred, login on far right) with flexbox + an auto margin. 2. Build a 3-column responsive blog grid using grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)). 3. Recreate a "Holy Grail" page layout (header, sidebar, content, aside, footer) with named grid areas. 4. Use position: sticky to keep a sidebar's TOC visible while the page scrolls.