WGU D276 practice

Flexbox vs CSS Grid: Main Axis, Cross Axis, justify-content, align-items, and grid-template-columns

The main axis is whichever direction your flex items flow, and the cross axis runs perpendicular to it. justify-content moves items along the main axis; align-items moves them along the cross axis. See how flex-direction flips those roles, how grid separates track alignment from item alignment, how grid-template-columns builds a column track list, and when each method is the right tool.

The main axis is whichever direction your flex items flow, and the cross axis is the one running perpendicular to it. Everything else follows from that: justify-content always distributes items along the main axis, and align-items always positions them along the cross axis. That is why the very same declaration centers items horizontally in one container and vertically in another.

flex-direction decides which axis is which

A flex container starts with flex-direction: row, so the main axis is horizontal. Change the direction and the axes rotate with it.

  • row (the initial value) — main axis horizontal, running in the inline direction of the writing mode (left to right on an English page); cross axis vertical.
  • row-reverse — main axis still horizontal, but main-start moves to the right edge on a left-to-right page; cross axis vertical.
  • column — main axis vertical, top to bottom; cross axis horizontal.
  • column-reverse — main axis vertical, bottom to top; cross axis horizontal.

Notice that flexbox talks about "start" and "end," not "left" and "right." The row direction follows the writing mode, so in a right-to-left writing mode flex-start on a row is the right edge. Same idea with row-reverse: main-start moves to the right, and justify-content: flex-start obediently packs your items over there.

What the values do

  • justify-content distributes leftover space on the main axis: flex-start, flex-end, center, space-between (first and last items flush to the edges), space-around (end gaps half the size of the gaps between items), and space-evenly (identical gaps everywhere). If the items already consume all the space — say they have flex-grow: 1 — there is nothing left to distribute and the property appears to do nothing.
  • align-items positions items on the cross axis: stretch, flex-start, flex-end, center, and baseline. Its initial value is normal, which behaves as stretch in flexbox — that is why equal-height cards happen for free.

Grid has the same axes plus a second layer

Grid is two-dimensional, so it separates where the tracks sit from where each item sits inside its area. justify-content and align-content align the sized grid as a whole within the grid container, along the inline and block axes, which only shows up when the tracks are smaller than the container. justify-items and align-items align each item inside its own grid area — inline axis and block axis respectively.

Building columns

grid-template-columns declares the explicit column track list:

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

The fr unit takes a share of leftover space, minmax() sets a floor and a ceiling for a track, and repeat() saves you typing. auto-fill creates as many repetitions as fit; auto-fit does the same but then collapses any repeated track left empty after item placement, treating it as a fixed 0px track and collapsing its gutters too.

Picking one

One direction at a time — a nav row, a button group, a stacked card body — is a flexbox job. Rows and columns that must line up with each other, like a full page shell, is a grid job. They nest happily: grid for the page, flex inside each cell. For the wider course picture, see the WGU D276 Web Development Foundations study guide.

Practice: Flexbox And Grid

  1. You have a container with display: flex and flex-direction: column holding three boxes. You want the boxes centered horizontally in the container. Which declaration on the container does that?

    • align-items: center
    • justify-content: center
    • align-content: center
    • text-align: center
    Show answer & explanation

    Correct answer: align-items: center. With flex-direction: column the main axis is vertical, so the cross axis is horizontal, which makes align-items the horizontal control here. justify-content: center is the tempting pick because it centers horizontally in a row, but in a column it works on the main axis and centers the boxes vertically instead. align-content has no effect on a single-line flex container, and flex-wrap defaults to nowrap, so it is inert until you opt into wrapping; text-align only affects inline content inside each box, not the boxes themselves.

  2. A grid container is 900px wide and declares grid-template-columns: 200px 200px 200px with no gap. You add justify-content: center. What happens?

    • The three column tracks are centered as a group, leaving 150px of empty space on each side
    • Each item is centered horizontally inside its own 200px cell, while the tracks stay at the left
    • The three columns stretch to 300px each so they fill the container
    • The rows are centered vertically within the container
    Show answer & explanation

    Correct answer: The three column tracks are centered as a group, leaving 150px of empty space on each side. In grid, justify-content aligns the sized grid as a whole along the inline axis of the container, so 600px of tracks in a 900px container leaves 150px on either side. Centering each item inside its own cell is justify-items, or justify-self per item, which is the most common mix-up on this property. The columns cannot stretch because they are fixed at 200px, and moving the whole grid vertically would be align-content.

  3. A 1200px-wide grid container with no gap uses grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)) and contains exactly four cards. What is the result?

    • Four cards, each 300px wide, filling the full 1200px row
    • Four 150px cards at the left, with the right half of the row left empty
    • Four 150px cards centered in the row
    • Exactly four 150px columns, because minmax caps each track at its minimum
    Show answer & explanation

    Correct answer: Four cards, each 300px wide, filling the full 1200px row. auto-fit first works out how many 150px repetitions fit, which is eight, then collapses any repeated track left empty after item placement; the spec treats a collapsed track as having a fixed sizing function of 0px. That leaves four live tracks sharing all 1200px through the 1fr maximum, so each card is 300px. Option two describes auto-fill, which keeps the eight tracks at 150px each, and that is the classic confusion between the two keywords. No centering occurs because nothing set justify-content.

  4. A two-column grid uses grid-template-columns: 1fr 1fr, but one column holds a very long unbroken string, refuses to shrink, and pushes the grid wider than its container. Why, and what is the standard fix?

    • A bare 1fr means minmax(auto, 1fr), and that auto minimum will not go below the item's min-content size, so use minmax(0, 1fr) instead
    • fr units are ignored once content overflows, so you must switch the tracks to 50% 50%
    • justify-content: stretch is the grid default and forces tracks past their share, so set it to start
    • The long item generated an implicit column sized by grid-auto-columns, which defaults to max-content
    Show answer & explanation

    Correct answer: A bare 1fr means minmax(auto, 1fr), and that auto minimum will not go below the item's min-content size, so use minmax(0, 1fr) instead. CSS Grid Level 1 says a flex value appearing outside minmax() implies an automatic minimum, i.e. minmax(auto, 1fr), and that auto floor keeps the track at least as wide as the item's min-content contribution. Writing minmax(0, 1fr) removes the floor and lets the track shrink, usually paired with min-width: 0 or a non-visible overflow value on the item. Percentages look like a fix but they ignore gaps and do nothing about the item's min-content size; and no implicit column exists here, since both items sit in the two explicit tracks — grid-auto-columns would only size implicit tracks, and its initial value is auto, not max-content.

  5. A flex container on a left-to-right English page has flex-direction: row-reverse and justify-content: flex-start, with three items. Where do the items end up?

    • Packed against the right edge, with the first item in source order furthest right
    • Packed against the left edge, with the first item in source order furthest left
    • Packed against the left edge, but drawn in reverse visual order
    • Centered, because row-reverse cancels out the effect of flex-start
    Show answer & explanation

    Correct answer: Packed against the right edge, with the first item in source order furthest right. row-reverse moves main-start to the right edge in a left-to-right writing mode, and flex-start means packed toward main-start, not packed toward the left. So the group sits on the right with item one closest to the right edge. The tempting answer treats flex-start as a physical left, which is exactly the assumption flexbox's logical start and end vocabulary exists to break, and nothing about row-reverse disables justify-content.

  6. You are building a page shell: a header across the top, a fixed-width sidebar beside a flexible main area, and a footer across the bottom, with the sidebar and main edges lining up with the header and footer. Inside the header, a logo sits at the left and three nav links are evenly spaced at the right. Which split of layout methods fits best?

    • Grid for the page shell, because rows and columns must align at once, and flexbox inside the header, because that is a single row of items
    • Flexbox for the page shell, since flex-wrap can produce the second row, and grid inside the header for the even link spacing
    • Grid for both, because flexbox cannot align items on two axes and so is unsuitable inside the header
    • Flexbox for both, because grid only helps when every track has a fixed pixel width
    Show answer & explanation

    Correct answer: Grid for the page shell, because rows and columns must align at once, and flexbox inside the header, because that is a single row of items. The shell has to line up in two dimensions at the same time, with column edges shared across separate rows, which is exactly what grid tracks give you, while the header is a one-dimensional row and so is flexbox's natural job. Wrapping a flex line does create a visual second row, but wrapped lines size independently, so the sidebar edge would not reliably align with the header and footer. Flexbox does align within its line on both axes by way of justify-content and align-items, and grid tracks can be fr, auto, minmax(), or percentages, so the last two options rest on false premises.

A worked example: grid outside, flexbox inside

Here is the pattern you will reach for constantly — grid handles the two-dimensional gallery, flexbox handles what happens inside each card.

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

.card {
  display: flex;
  flex-direction: column;   /* main axis is now vertical */
  align-items: flex-start;  /* cross axis is horizontal, so this hugs the left */
}

.card .button {
  margin-top: auto;         /* absorbs the leftover main-axis space */
}

Read it axis by axis. The gallery makes as many 220px-minimum repetitions as fit and lets each grow via 1fr. Every card is stretched to the height of its row, because a grid item's align-self resolves to stretch by default. Inside a card, column flips the main axis vertical, so align-items: flex-start stops the heading and text from stretching edge to edge, and margin-top: auto soaks up the free main-axis space above the button, pinning it to the bottom of every card no matter how much text sits above it.

Mistakes people actually make

  • Assuming justify-content means "horizontal." It means "main axis." Before writing any alignment rule, say the container's flex-direction out loud first.
  • Reaching for align-content to align items. In flexbox it aligns lines on the cross axis, and it has no effect on a single-line flex container — meaning one with flex-wrap: nowrap, the default. Once you set flex-wrap: wrap it does apply, even if only one line ends up forming. In grid it moves the row tracks as a group, not the items inside their cells.
  • Expecting justify-content to move things when there is no free space. Give the items flex-grow: 1 and they swallow the leftover space themselves, leaving the property nothing to distribute.
  • Mixing up auto-fill and auto-fit. With few items in a wide container, auto-fill keeps the empty tracks and your cards stay narrow; auto-fit collapses those empty tracks to zero, so the remaining cards stretch. Neither is "correct" — pick the result you want.
  • Fighting an unshrinkable 1fr track. A bare 1fr carries an automatic auto minimum, so long words and wide media can force the track past its share. minmax(0, 1fr) is the fix.

Reasoning through the tricky cases

When alignment refuses to budge, ask three questions in order. Which axis is main here? Is there any free space left to distribute? Am I aligning the container's tracks, or the items inside their areas? That third question is the one grid adds, and it explains most "my CSS did nothing" moments: you wanted justify-items or justify-self, and you wrote justify-content.

Two more things worth memorizing. First, gap works in both flexbox and grid, so you rarely need margin hacks for spacing. Second, the keyword families differ: flex-start and flex-end are defined against the flex container's own main and cross axes, while the generic start and end resolve against writing mode. Grid uses start and end, and treats flex-start and flex-end as equivalent to them. The definitive references are MDN's basic concepts of flexbox and MDN on grid-template-columns. When you are ready to drill this further, work through more D276 practice questions.

Want someone to walk you through this?

Book 1-on-1 prep for WGU D276 — original coaching, never exam content.

Stuck on this topic? WhatsApp us on +1 646 980 4914.

Working through the whole course? Read the full WGU D276 study guide, or see every WGU D276 practice topic.

More WGU D276 practice

Html Document Structure

The five lines at the top of every HTML file are not decoration. Here is what the doctype, the html/head/body split, meta charset, and the viewport tag each do — why the browser misbehaves when you leave one out, and how to reason about the cases that trip people up.

Semantic Structure Tags

Semantic structure tags describe what a block of content is, not how it looks. This lesson explains the difference between article, section, aside, main, nav, header and footer — including the syndication test that settles article vs. section, the strict placement rules for main, and how header and footer change meaning depending on where they sit — then gives you practice questions with worked explanations.

Headings Text Links Lists

Heading elements rank content instead of sizing it, strong and em carry meaning that b and i do not, a fragment link points at an element's id, and ul, ol, and dl each describe a different kind of grouping. Work through how each one behaves, then test yourself on the cases people actually get wrong.

Images And Alt Text

An image starts with one element and one honest description. From there, srcset, sizes, and picture answer a single question: which file should the browser download on this screen? This guide walks through alt text, figure and figcaption, resolution switching, and art direction, then gives you six practice questions with full explanations.

Html5 Audio And Video

The audio and video elements embed media without a plugin. Learn how the browser chooses among source children, which MIME types to use for MP4, WebM, and MP3, what controls and preload actually do, and why fallback content between the tags is not an error message. Includes practice questions with full explanations.

Html Tables

A plain-English walkthrough of HTML table markup for WGU D276: how table, caption, thead, tbody, tr, th and td nest, what the scope attribute actually does for assistive technology, and how colspan and rowspan reshape the grid — plus practice questions with worked explanations.