- Learn
- Computer Science & IT
- Programming
- Web Development Basics
- CSS Layout with Flexbox and Grid
CSS Layout with Flexbox and Grid
display property and floats, then position elements with relative, absolute, fixed and sticky positioning and manage overlapping layers with z-index. Build rows and columns of items with flexbox and two-dimensional layouts with CSS grid, including sizing, gaps and alignment. Finish by choosing the right method for each part of a page, building common page and component layouts, and finding and fixing layout bugs with the browser's developer tools.BeginnerLesson 5 of 8 in Web Development Basics Course
What you will learn
- Describe how a browser places boxes when no layout CSS is applied, change that behavior with the
displayproperty, and use floats to wrap text around an element.- Follow normal flow: block and inline boxesPredict where block and inline boxes appear in normal flow, how their sizes behave and when vertical margins collapse.
- Change the layout with the display propertyUse
displayto change how an element takes part in its parent's layout and how its own children are laid out, and hide elements correctly. - Wrap text around an element with floatFloat an image or quote so that text wraps around it, clear content below floats and make a parent contain its floats.
- Follow normal flow: block and inline boxes
- Shift elements from their normal place, pin them to a container or the viewport, keep them in view while scrolling, and control which overlapping element appears on top.
- Offset elements with relative and absolute positioningUse relative and absolute positioning to nudge elements and to place overlays such as badges exactly inside a chosen container.
- Keep elements in view with fixed and sticky positioningPin elements to the viewport with fixed positioning, make headers and headings stick while scrolling with sticky positioning, and avoid the problems each one causes.
- Control which elements appear on top with z-indexPredict the stacking order of overlapping elements, use
z-indexwithin stacking contexts, and fix the classic "z-index does not work" problems.
- Offset elements with relative and absolute positioning
- Lay out a row or a column of items with flexbox: set its direction and wrapping, control how items grow and shrink, and align and space them.
- Set up a flex container and its axesTurn an element into a flex container, explain the main and cross axes, and control direction, wrapping and visual order without breaking the reading order.
- Size flex items with grow, shrink and basisCalculate how flexbox shares free space and overflow among items with
flex-basis,flex-growandflex-shrink, and use theflexshorthand with confidence. - Align and space flex itemsDistribute space along the main axis, align items on the cross axis, push items apart with auto margins, and space them with
gap.
- Set up a flex container and its axes
- Define rows and columns with CSS grid, place items on lines and named areas, let the grid place items automatically, and align items and tracks.
- Define grid tracks with fr, repeat and minmaxCreate the rows and columns of a grid, calculate track sizes with the
frunit, and userepeat(),minmax()andgap. - Place items by line numbers, spans and named areasPlace grid items with line numbers,
spanand named template areas, and keep the visual order and the reading order in agreement. - Let the grid place items automaticallyUse auto-placement and the implicit grid to place any number of items, and build card grids that adjust their column count with
auto-fillandauto-fit. - Align items and tracks in a gridAlign each item inside its grid area, align the whole set of tracks inside the container, and center content with the
place-shorthands.
- Define grid tracks with fr, repeat and minmax
- Pick the right layout method for each part of a page, build common page and component layouts, and find and fix layout bugs.
- Choose the right layout methodDecide between normal flow, flexbox, grid, positioning, floats and multiple columns for a given layout, and combine them on one page.
- Build page-level layoutsBuild a readable content column, a header–sidebar–main–footer page, a footer that stays at the bottom and a sticky sidebar.
- Build common component layoutsLay out recurring interface pieces: centered content, navigation bars, image-beside-text blocks, card grids with aligned parts, overlays, forms and input groups.
- Find and fix layout problemsUse the browser's developer tools and a checklist of common causes to find out why a layout breaks or a property has no effect, and test layouts against real content.
- Choose the right layout method
CSS Layout with Flexbox and Grid study guide
1How boxes flow
Browsers arrange readable pages before any special layout rules are added. Block and inline boxes explain that starting arrangement, including why a narrow paragraph still takes its own line and why some margins combine. Learn how display changes the outside and inside of a box, then use floats for the specific job of wrapping text around an image. These rules help you predict what will change when you later introduce flexbox or grid.
1.1 How block and inline boxes share a page
A page already has a layout before you add flexbox or grid. Normal flow places boxes in HTML order. In horizontal English text, blocks stack downward and inline content runs from left to right, wrapping when a line fills.
Blocks take a line
Paragraphs, headings, divisions and sections are block boxes by default. A block with width: auto fills its container's available width and grows in height with its content. Setting its width does not invite the next block onto the same line.
<p>Read the <a href="/guide">setup guide</a> first.</p>
<p>Then install it.</p>
The paragraphs start on separate lines. The link is an inline box within the first paragraph. Even if the first paragraph is only 300px wide, the second paragraph still begins below it.
Inline boxes follow the text
A <span>, <a>, <strong> or <em> normally takes only the width of its text. A non-replaced inline box ignores width and height. Adding a { width: 200px; } therefore does not make the link 200px wide.
Horizontal padding, borders and margins push adjacent text aside. Vertical padding and borders are painted, but they do not make the surrounding lines farther apart; a large background can overlap the line above or below. Vertical margins have no effect. An image is a replaced element: it is inline by default, yet width and height do apply to it.
Vertical margins can combine
In normal flow, touching vertical margins of block boxes can collapse into one gap. A paragraph with margin-bottom: 24px followed by a heading with margin-top: 32px leaves 32px between them. The larger positive margin wins; the gap is not 56px. With a 24px positive margin and a −10px margin, the result is 14px. Horizontal margins stay separate.
A first child's top margin can also collapse with its parent's top margin when no border, padding or inline content separates them. A heading's 20px top margin can move an entire unpadded header downward, leaving no space inside the header. Use top padding for interior space, add a border, or give the parent display: flow-root. A last child's bottom margin can collapse with its parent's bottom margin too.
Flex and grid items do not collapse margins with one another. If you switch a parent from normal flow to flexbox, the same two positive margins may now add together. Floated and absolutely positioned boxes also keep their margins separate.
Directions follow the writing mode
The block direction is where successive blocks go; the inline direction is where text runs. Arabic and Hebrew use horizontal lines too, but their inline direction is right to left. Logical properties follow these directions: margin-inline-start: 16px gives a left margin in English and a right margin in Arabic. padding-block sets padding along the block direction.
Key Takeaways
- Blocks start new lines even when given a narrow width.
- Non-replaced inline boxes ignore
widthandheight; images are an exception. - Touching vertical block margins can collapse; horizontal margins do not.
- Logical properties follow the block and inline directions.
- Padding or
flow-rootcan stop a child margin collapsing through its parent.
1.2 What display changes
The display property controls a box's relationship with its parent and the arrangement of its children. These are separate choices. A flex container can occupy a whole line while arranging its own children side by side.
Read display from the outside in
The outer display type is block or inline. The inner display type describes the layout inside the box, such as flow, flex or grid.
| Value | Outside | Inside |
|---|---|---|
block | Block | Normal flow |
inline-block | Inline | Separate flow region |
flex | Block | Flex layout |
inline-flex | Inline | Flex layout |
grid | Block | Grid layout |
inline-grid | Inline | Grid layout |
Modern two-keyword syntax makes the distinction visible: display: inline flex means the same as inline-flex. display: block flow-root means the same as flow-root. A single value such as grid supplies a block outer type by default.
Make an inline box accept a size
nav a {
display: inline-block;
padding: 12px 16px;
}
Each link still sits on a text line, but now it accepts width, height and vertical margins. Its vertical padding makes room in the line layout instead of just painting over nearby lines. This gives a link a larger click target.
Whitespace between inline-block elements in the HTML appears as a small space between the boxes. If you need a controlled row with an exact gap, flexbox provides that directly.
Changing display does not change the HTML element's meaning. A division styled inline remains a generic container. Choose a list, link or button for its purpose, then style its box.
Hide a box with the right effect
| Rule | Layout effect |
|---|---|
display: none | The element and its descendants generate no boxes. |
visibility: hidden | The box keeps its layout space while hidden. |
A hidden error message with display: none makes no gap. Showing it pushes later content downward. Using visibility: hidden reserves the gap, so revealing the message need not move anything. display: none also prevents keyboard focus and removes the hidden content from screen-reader output. A visually-hidden class serves the different purpose of keeping text available to screen readers while hiding it visually.
Children and independent regions
With ul { display: grid; }, the list items become grid items. Links inside those list items remain inside their own parent's layout. To arrange those links, give the list item its own layout or use subgrid where shared tracks are needed.
display: contents removes the wrapper's own box so its children participate in the surrounding layout. Browser accessibility behavior can also remove the wrapper's role, so avoid this on meaningful controls, lists and tables.
display: flow-root creates a block formatting context, an independent flow region. It contains floated children and prevents the parent's margins from collapsing with its children's margins. It achieves those effects without adding clipping or scrollbars.
Key Takeaways
- Display has an outer type and an inner type.
- Flex and grid affect direct children.
inline-blockkeeps inline placement while accepting box dimensions.display: noneremoves layout space;visibility: hiddenpreserves it.flow-rootcontains floats and separates parent–child margins.- Use
display: contentscarefully because browser behavior can remove the wrapper’s accessible role.
1.3 Text wrapping with floats
A portrait in an article often needs text beside it for a few lines, then text at full width below it. A float creates that shape of text flow. It has a different job from a sidebar that stays in a separate column.
Put an image beside flowing text
img.portrait {
float: left;
width: 160px;
margin: 0 16px 8px 0;
}
Place the image before the paragraphs that should wrap around it. The image moves to the left edge of its container. Following text uses the space on its right, staying 16px away horizontally and 8px below its bottom edge. Once the text passes the image, lines return to the container's full width. Use float: right for the opposite edge and float: none to remove floating.
A float is removed from normal flow, but nearby inline content still wraps around it. Following block boxes themselves ignore the float: their backgrounds and borders can extend behind it. Seeing a paragraph background under the image does not mean its text is failing to wrap.
A floated element becomes a block-level box. A floated <span> can therefore accept width and height. With no set width, a floated text box shrinks to fit its content; an image has its own dimensions.
Start the next section below the image
Suppose the text is shorter than the portrait, and a new section heading starts beside the portrait. Clearing controls that relationship:
.next-section {
clear: both;
}
The heading moves below earlier floats on either side. clear: left clears left floats only; clear: right clears right floats only. Clearing a later heading does not itself make the earlier image an ordinary block again.
Make the parent wrap around its floats
A parent with only floated children gets no normal-flow height from them. Its background and border can look collapsed, and the next content may rise beside the floats. Let the parent contain them:
.profile {
display: flow-root;
}
The parent's height now reaches around the floated image. This differs from clear: flow-root changes the parent's flow region, while clear moves a following element down past floats.
Older stylesheets often contain a clearfix: an ::after pseudo-element with content: "", display: block and clear: both. You may also see overflow: auto used to contain floats. That can add scrolling when content is too large; flow-root expresses the containment job directly.
Recognize older column layouts
Before flexbox and grid, page columns were often floated with percentage widths and clearing rules. Maintain those rules with an understanding of floats, but choose flexbox or grid for new columns that need sizing and alignment.
A direct child of a flex or grid container follows that layout, so float has no effect on that item. If a floated image stops wrapping text after you add display: flex to its parent, inspect the parent layout first.
Key Takeaways
- A float lets following inline content wrap beside it.
clearmoves a later box below earlier floats.flow-rootmakes a parent contain its floated children.- Floats have no effect on flex or grid items.
2Positioning and overlapping layers
Positioning controls offsets, overlays and elements that stay visible during scrolling. The key is knowing which space a box keeps and which ancestor supplies its reference. Work from a badge inside a card to fixed controls and sticky headings, then examine overlapping layers. Stacking contexts explain why a dropdown can stay hidden even when its own z-index is very large, and show which ancestor actually needs to change.
2.1 Offsets and the box they are measured from
Positioning lets one box overlap another or move away from its normal location. Before setting an offset, decide whether the box should keep its original space and which ancestor should act as its reference.
Static, relative and absolute
| Position | Space in normal flow | Offset reference |
|---|---|---|
static | Kept | Offsets have no effect |
relative | Kept | The box's original position |
absolute | Removed | Its containing block |
With position: relative; top: 10px; left: 20px, a box is drawn 10px down and 20px right from its original location. Its neighbors stay where they were. The original gap remains, so a large offset can make the box overlap its neighbors.
A relative parent needs no offsets to provide a reference for an absolute child. This is a common use of relative positioning.
Anchor a badge to a card
.card {
position: relative;
}
.badge {
position: absolute;
top: 8px;
right: 8px;
}
The badge is out of normal flow, so the card reserves no space for it. Its top and right edges sit 8px inward from the card's padding edges. Leave enough room in the card's content so a long title cannot run under the badge.
An absolute box's containing block is usually the padding box of its nearest positioned ancestor. A positioned element has any position value except static. If the card remains static, the badge looks farther up the ancestor chain. With no qualifying ancestor, it uses the initial containing block: a viewport-sized rectangle at the top of the document that scrolls with the page. An ancestor's non-none transform, filter or perspective can also establish this reference.
Stretch or center an overlay
An absolute box with automatic size and offsets that do not stretch it shrinks to fit its content. Setting both left and right offsets with an automatic width makes it fill the space between them; the top and bottom pair works similarly for an automatic height.
.overlay {
position: absolute;
inset: 0;
}
inset sets top, right, bottom and left together. With automatic dimensions and no margins, this overlay fills the containing block. A set width or height changes the sizing, so remove those limits when the layer should cover the whole box.
For a centered badge of unknown size, use top: 50%; left: 50%; transform: translate(-50%, -50%). The offsets move its top-left corner to the containing block's center. The translation moves it back by half its own width and height. With a known width and height, inset: 0; margin: auto is another centering method.
Check the percentage reference
A content-box parent with width: 400px and horizontal padding of 20px has a 440px padding box. An absolute child with width: 50% therefore has a 220px content width. Measuring only the parent's 400px content box gives the wrong result.
Use absolute positioning for a badge, tooltip or overlay. Page columns need boxes that respond to one another's size; flexbox, grid and normal flow provide that relationship.
Key Takeaways
- Relative positioning keeps the original space; absolute positioning removes it.
- An absolute box usually measures offsets from its nearest positioned ancestor’s padding box.
inset: 0stretches an automatically sized absolute overlay to its containing block.- Offset percentages and translation percentages use different reference boxes.
- Use normal flow, flexbox or grid for the page’s main structure.
2.2 Elements that stay visible while you scroll
A back-to-top control and a table heading both need to stay visible, but they have different relationships with the page. Fixed positioning ties a control to a reference window. Sticky positioning keeps a box in the flow and limits its movement to its section.
Pin a control to the viewport
.back-to-top {
position: fixed;
right: 16px;
bottom: 16px;
}
The button stays at the window's lower-right corner as the document scrolls. It takes no space in normal flow. A fixed header likewise reserves no space and can cover the first paragraph.
For a 64px fixed header, body { padding-top: 64px; } leaves space for the initial content. Also set html { scroll-padding-top: 64px; } so section links do not place their target headings under the header. Give the header a background so text scrolling behind it does not show through.
A non-none transform, filter or perspective on an ancestor can make that ancestor the fixed element's containing block. The element then stays inside that ancestor and can scroll away with it. Inspect ancestors when a fixed control unexpectedly moves with the page.
Let a heading stick within a section
thead th {
position: sticky;
top: 0;
background: white;
}
A sticky heading occupies its normal place first. When scrolling would take it above the top: 0 threshold, it stays there. It cannot travel beyond its containing block: the end of its section eventually pushes it out of view. This is useful for long tables and section navigation.
| Behavior | Fixed | Sticky |
|---|---|---|
| Normal-flow space | Removed | Reserved |
| Starts at its ordinary location | No | Yes |
| Stops at its section's end | No | Yes |
The viewport is the usual fixed reference. Sticky uses the nearest relevant scrolling ancestor; the page is the reference when no nearer scrolling box intervenes.
Diagnose a sticky box that does not stick
Check these causes in order:
- Set a non-
autooffset on the axis that should stick, such astop: 0for vertical scrolling. The keywordstickyalone sets no threshold. - Inspect ancestors for
overflow: hidden,autoorscroll. They can become the sticky reference even when a different box is actually scrolling. - Compare the sticky box's height with its containing block. A wrapper only as tall as its heading gives the heading no room to move.
A sticky sidebar in a grid can also stretch to the row's full height. align-self: start lets it keep its content height and leaves travel space.
Keep content and focus visible
Fixed and sticky bars use part of the visible screen. At 200% text zoom, a navigation bar can become much taller. Test keyboard navigation as well as scrolling. WCAG 2.2 criterion 2.4.11, Focus Not Obscured (Minimum), requires that author-added content does not entirely hide a focused element. Keep bars short and provide suitable scrolling space around targets.
Key Takeaways
- Fixed positioning removes the box from flow; sticky preserves its place.
- Sticky needs an offset and room to move inside its containing block.
- Overflow on an ancestor can change the sticky reference.
- Reserve space for fixed headers and check that focused content stays visible.
2.3 Stacking levels and stacking contexts
When boxes overlap, stacking order decides which one you see in front. A larger z-index can bring a box forward, but only within the group where that value is compared.
Make z-index apply
z-index works on positioned elements and on flex or grid items. A static paragraph in normal flow ignores it. A static grid item can use it without adding position: relative.
Without explicit levels, positioned boxes paint above ordinary non-positioned boxes. For comparable boxes at the same level, the one later in the HTML paints on top. Positive, zero and negative z-index values give you more control over that order.
A context is stacked as one unit
A stacking context contains a group that the browser stacks as a whole. A child's level cannot lift the group above a higher sibling context.
.site-header {
position: relative;
z-index: 1;
}
.menu {
position: absolute;
z-index: 9999;
}
main {
position: relative;
z-index: 2;
}
Here .menu is inside .site-header, while main is its sibling. Compare the outer groups first: the header is at 1 and main is at 2. Main paints above the entire header, including the menu. Increasing 9999 changes only the menu's place within the header.
Raise the header itself, for example to z-index: 3, or remove the unnecessary level on main. Choose the change that matches the intended order of the whole page.
Find what creates the group
The root element creates a stacking context. Common additional causes are:
- A relative or absolute box with a non-
autoz-index. - A flex or grid item with a non-
autoz-index. - Every fixed or sticky box.
opacitybelow 1, or a transform or filter other thannone.isolation: isolate.
A parent with opacity: 0.9 can therefore trap a dropdown even if nobody set a level on that parent. Walk up the ancestors in developer tools when a higher number makes no visible difference. Look for the first pair of sibling groups whose order is wrong.
Keep decorations inside a component
.panel {
position: relative;
isolation: isolate;
}
.panel-decoration {
position: absolute;
inset: 0;
z-index: -1;
}
isolation: isolate creates a context without changing the panel's appearance. The negative child paints behind the panel's text but above the panel's background. Without the local context, it can fall behind the parent's background and disappear.
Use a small shared scale for intended page layers: for example, 1 for raised cards, 10 for a sticky header, 100 for dropdowns and 1000 for a modal. CSS custom properties such as --z-dropdown: 100 make the choices easier to maintain.
Key Takeaways
z-indexapplies to positioned boxes and flex or grid items.- A stacking context is compared with neighboring contexts as one unit.
- A child’s large level cannot escape a lower ancestor context.
- Opacity and transforms can create unexpected contexts.
isolation: isolatecontains a component’s stacking levels.- Use a small shared scale after checking the ancestor contexts.
3Rows and columns with flexbox
Flexbox turns a group of children into a row or column that can share available space. Its axes explain direction and alignment, while basis, grow and shrink explain the final sizes. Follow a wrapped row and work through the arithmetic before choosing gaps, auto margins and alignment. You will also see why visual reordering can disrupt keyboard navigation and why a long code line can stop a flexible column from shrinking.
3.1 Flex rows, columns and wrapping
Flexbox arranges a group along one main direction. It suits navigation links, toolbars and other items whose sizes come from their content. A wrapped flex layout can have several lines, but each line shares its space independently.
Create the container
.nav {
display: flex;
}
The navigation's direct children become flex items. A link inside a list item is not a flex item of the navigation unless it is also a direct child. Text directly inside the container forms an anonymous flex item.
The defaults are a row, no wrapping, no growing and permission to shrink. Items start at the main start edge. In a horizontal row, auto-height items stretch to the line's height, so they often appear equally tall.
Name the axes before aligning
The main axis follows flex-direction. The cross axis is perpendicular to it. In horizontal English text:
| Direction | Main axis | First item starts at |
|---|---|---|
row | Horizontal | Left |
row-reverse | Horizontal | Right |
column | Vertical | Top |
column-reverse | Vertical | Bottom |
A row follows the inline direction, so its start is on the right in right-to-left text. A column follows the block direction. Main and cross describe roles, not permanent horizontal and vertical directions.
justify-content works on the main axis. align-items works on the cross axis. After switching from row to column, justify-content: center centers vertically, provided there is spare height.
Work out which items fit
.cards {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.card {
flex: 1 1 200px;
}
Consider five cards in a 700px content width. Each starts at 200px, and each can grow or shrink. Three cards plus two gaps need 632px; four plus three gaps need 848px. Three fit on the first line.
The first line shares 700px minus 32px of gaps: each card becomes about 222.7px wide. The remaining two share 700px minus one 16px gap: each becomes 342px wide. Items on the second line do not inherit the first line's widths. Use grid when columns must line up across rows.
flex-flow: row wrap is shorthand for direction and wrapping. Without wrapping, flexbox keeps all the items on one line, shrinking them where their sizing limits allow it.
Keep reading order meaningful
order defaults to 0. Lower values appear first; order: -1 brings an item before ordinary items. Reversed directions and order change the drawing order, while screen readers and normal keyboard focus still follow the HTML.
Keep important sequences in a sensible HTML order. Visual reordering can make a keyboard user jump around the screen, and can fail WCAG 1.3.2, Meaningful Sequence, or 2.4.3, Focus Order, when meaning or operation is harmed.
An item can also be a container. A card in a flex row can use its own display: flex; flex-direction: column to stack its contents. Use inline-flex when the outer container should sit within a text line, such as a button holding an icon and label.
Key Takeaways
- Flexbox changes the layout of direct children.
- Direction sets the main axis; the cross axis is perpendicular.
- Wrapped flex lines size independently.
- Visual order changes do not change the HTML reading or focus order.
- A flex item can contain its own flex layout.
3.2 How flex items grow and shrink
Flexbox begins with a size for each item, then adjusts those sizes to fit the container. The three parts of flex control that adjustment: grow, shrink and basis, in that order.
Start with the basis
flex-basis supplies the starting size along the main axis. With auto, it uses the item's width in a row or height in a column; if that size is also automatic, content supplies the size. An explicit basis takes precedence over width, while minimum and maximum sizes still limit the final result.
Subtract all bases and gaps from the container's content size. A positive result is free space for growing. A negative result is space the items need to give up.
Share positive space
Three items in a 600px row have bases of 100px and grow factors 1, 1 and 2. With no gaps, the bases use 300px, leaving 300px. Four grow shares divide that remainder into 75px each. The final sizes are 175px, 175px and 250px.
Now add gap: 20px. Two gaps consume 40px, leaving 260px after the bases. Each share becomes 65px; the final widths become 165px, 165px and 230px. A factor of 2 doubles the added space, not the entire final width.
Give up space using weighted shrink
Two items with bases of 300px and 400px occupy a 500px container with no gap. They need to lose 200px. If both have flex-shrink: 1, their shrink weights are 300 and 400: each factor is multiplied by its base size.
The first loses about 85.7px and finishes at about 214.3px. The second loses about 114.3px and finishes at about 285.7px. Equal shrink factors do not mean equal pixel losses. flex-shrink: 0 protects an item's base size, which is useful for an avatar or logo.
These calculations describe items without padding, borders, margins or size limits that alter the result. Check those constraints when a real layout differs.
Read common shorthand values
| Declaration | Expanded value | Starting point |
|---|---|---|
flex: initial | 0 1 auto | Width or content; can shrink |
flex: auto | 1 1 auto | Width or content; can grow or shrink |
flex: none | 0 0 auto | Width or content; stays that size |
flex: 1 | 1 1 0% | Zero basis in a definite-width row |
Two items with content widths of 80px and 200px in a 600px row become 240px and 360px with flex: auto: both gain half of the 320px remainder. With flex: 1 and no limiting minimums, both start from zero and become 300px wide.
Let a flexible column become narrow
A flex item's automatic minimum can keep it as wide as an unbroken URL or code line. Permit shrinking on the item and handle the content inside it:
.sidebar { flex: 0 0 240px; }
.main { flex: 1; min-width: 0; }
.main pre { overflow-x: auto; }
The sidebar stays 240px wide. Main takes the remainder. The code scrolls within main instead of forcing the whole page wider. For ordinary long text, overflow-wrap: anywhere allows breaks. A zero minimum makes room available; it does not by itself wrap or scroll the content.
Key Takeaways
- The shorthand order is grow, shrink, basis.
- Grow factors divide added space, not final widths.
- Shrink losses depend on each factor multiplied by its base size.
- A non-
autobasis takes precedence over width. flex: 1andflex: autouse different starting sizes.min-width: 0permits shrinking; inner content still needs suitable overflow handling.
3.3 Space and alignment in flexbox
Alignment begins after sizing. Identify the main axis, the cross axis and the space left on each. A property can be valid yet make no visible difference when no room remains to distribute.
Share space on the main axis
justify-content positions the group along the main axis. For three 100px items in a 600px row with no gaps, 300px remains:
| Value | Result |
|---|---|
center | 150px before and after the group |
space-between | 150px between neighbors; none at the ends |
space-around | 50px at each outer end; 100px between neighbors |
space-evenly | Four equal spaces of 75px |
flex-start packs items at main-start; flex-end packs them at main-end. start and end follow the writing direction instead. In an English row-reverse, flex-start packs against the right edge, but start packs against the left.
If items with flex: 1 consume all the line's space, justify-content has no remainder to distribute. Reducing or removing growth changes that situation.
Align within each line
align-items positions items on the cross axis inside their line. The usual default, stretch, makes auto-height items in a row fill the line's height. An item with a set height does not stretch this way. Use center, start or end for other positions, or baseline to line up text of different sizes by its baseline.
align-self overrides this choice for one item. Flexbox has no justify-self: items share the main axis as a group. justify-items does not align flex items either.
To center a single child in both directions, set justify-content: center; align-items: center on its flex parent. A taller parent, such as one with min-height: 100vh, gives vertical centering room to show. If the only item already fills the line's cross size, centering it there produces no movement.
Separate groups with auto margins
nav {
display: flex;
align-items: center;
gap: 16px;
}
.logo {
margin-inline-end: auto;
}
In horizontal English, the logo stays left while the links move right. Its auto end margin absorbs the remaining space. An auto start margin on an item instead pushes that item and those following it toward the end. Logical margins adapt when text direction changes.
A single item with margin: auto can center on both axes. When an item is too large, auto margins avoid placing its overflow beyond the unreachable start edge, which ordinary centering can do.
Distinguish lines from items
align-content moves the lines as a group on the cross axis in a wrapping container with spare room. It has no effect with flex-wrap: nowrap. With wrap, it can still position a line even if the current items fit on just one line. align-items handles the items within each line.
gap: 16px 24px sets a 16px row gap and a 24px column gap. Gap creates space between items and lines, never around the outside of the container. Add padding for outer space. Any space distributed by alignment is additional to the gap.
Key Takeaways
justify-contentdistributes remaining main-axis space.flex-startfollows the flex direction;startfollows the writing direction.align-itemsaligns items within lines;align-contentdistributes wrapping lines.- Auto margins absorb free space and can separate groups.
- Gap adds interior spacing; padding adds outer spacing.
- Use
align-selffor one item’s cross-axis alignment. - Flexbox does not support
justify-selffor individual main-axis placement.
4Shared tracks with grid
Grid gives several rows a shared set of columns and lets individual boxes span or overlap those tracks. Define sizes, calculate fractional shares and place items by boundaries or named areas. Then let auto-placement handle a growing collection and compare auto-fill with auto-fit. Finish by separating item alignment within areas from track alignment within the whole container, so each property moves the part you intend.
4.1 Grid tracks and the space they share
Grid defines rows and columns together. Set the tracks on a container, then let its direct children occupy them. Unlike wrapped flex lines, grid rows share the same column structure.
Name the parts
A track is one row or column between two grid lines. A cell is the intersection of one row and one column. A grid area is a rectangle of one or more cells. Gaps, also called gutters, separate the tracks.
.dashboard {
display: grid;
grid-template-columns: 200px 1fr 2fr;
gap: 20px;
}
grid-template-columns defines the explicit columns; grid-template-rows defines the explicit rows. Without explicit columns, a grid has one column and its items stack into rows.
Calculate an fr share
The fr unit shares the space left after fixed tracks and gaps. In a 900px container, the example has a 200px fixed column and two gaps of 20px. Subtract those first: 660px remains. The two flexible columns request three shares in total, so one share is 220px. The widths are 200px, 220px and 440px.
The fractions divide the remaining track space, not the entire 900px. A 2fr track gets twice the flexible share of a 1fr track when minimum sizes do not constrain them.
Repeat tracks and set limits
repeat(4, 1fr) is shorthand for four equal flexible tracks. Repeating a pattern is possible too: repeat(2, 100px 1fr) creates 100px 1fr 100px 1fr.
Track sizes can also use lengths, percentages, auto, min-content and max-content. The content keywords request sizes based on the content's intrinsic needs.
minmax(150px, 1fr) gives a track a 150px minimum and a flexible maximum. For rows created automatically, use grid-auto-rows: minmax(100px, auto) to get a 100px minimum while allowing taller content to expand a row.
A plain 1fr track has an automatic minimum, like minmax(auto, 1fr). A long unbreakable URL can make one column wider than the rest. Use repeat(3, minmax(0, 1fr)) when the columns must share the available width equally, and provide wrapping or scrolling for oversized content inside them.
Keep gaps inside the available width
gap: 16px 32px means 16px between rows and 32px between columns. It creates no padding around the grid.
Three columns of 33.33% already use almost all a 900px container. Two 20px gaps then add about 40px beyond its width. Fractional tracks account for those gaps before sharing space, so repeat(3, 1fr) avoids this percentage-plus-gap overflow when content minimums fit.
Let rows respond to content
grid-template-rows: auto 1fr auto suits a header, main area and footer. The outer rows fit their content. With a container height or minimum height to fill, the middle row takes the remaining height. Keep room for growing content; a minimum page height allows a longer page to expand.
Key Takeaways
- Rows and columns are tracks bounded by grid lines.
frshares space after fixed tracks and gaps.repeat()can repeat one size or a track pattern.minmax()sets a minimum and maximum track size.minmax(0, 1fr)removes a flexible track’s automatic minimum.- Percentage tracks can overflow when gaps are added.
4.2 Placing items on lines and named areas
Grid placement describes an item's boundaries. Count the lines around the columns and rows, or name a rectangular region and place the item there. Both methods arrange boxes without changing their order in the HTML.
Count boundaries, not columns
A three-column grid has four column lines. In horizontal English, column line 1 is on the left and row line 1 is at the top. Negative numbers count backward from the explicit grid's end: -1 is its final line.
| Declaration | Placement |
|---|---|
grid-column: 1 / 3 | Covers the first two columns |
grid-column: 1 / -1 | Spans the explicit grid's full width |
grid-column: 2 / span 2 | Starts at line 2 and covers two columns |
grid-column: span 2 | Covers two columns at an automatic location |
To cover three columns starting at line 1, end at line 4. Ending at line 3 covers only two tracks.
In a dashboard with four columns and three rows, place a chart with grid-column: 1 / 4; grid-row: 1 / 3. It occupies three columns and two rows: six cells. A statistics panel at grid-column: 4; grid-row: 1 / 3 occupies the last column beside it. A table at grid-column: 1 / -1; grid-row: 3 fills the third row.
Draw the page using area names
.page {
display: grid;
grid-template-columns: 220px minmax(0, 1fr);
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"nav main"
"footer footer";
}
header { grid-area: header; }
nav { grid-area: nav; }
main { grid-area: main; }
footer { grid-area: footer; }
Each string describes a row, and each word describes a cell. Repeating header across the first row lets the header span both columns. A period marks an empty cell. Every row must contain the same number of cells, and each repeated name must form one rectangle. An L-shaped named area makes the whole grid-template-areas declaration invalid.
An area called main also creates lines called main-start and main-end. You can use those names for another item's boundaries. Define custom line names in square brackets in the track list, such as [content-start] 600px [content-end].
Overlap inside one grid area
An image and caption can both use grid-area: 1 / 1. They share the first cell; the caption later in the HTML paints over the image. align-self: end moves the caption to the bottom of that area. Grid items accept z-index without needing a non-static position, so you can explicitly change their layer order.
Preserve the reading sequence
Manual placement affects appearance, not the HTML order followed by screen readers and keyboard focus. Keep instructions, headings and links in a meaningful source order. A layout can look sensible while tab navigation jumps between distant cells; this can fail WCAG 1.3.2 or 2.4.3 when meaning or operation suffers.
Key Takeaways
- Placement uses grid lines; three tracks have four boundaries.
-1refers to the last line of the explicit grid.- Every named area must be rectangular, and all template rows need equal cell counts.
- Items can overlap in one area and use
z-indexwithout positioning. - Grid placement does not change reading or focus order.
4.3 Automatic grids that fit their content
A product list can grow from a few cards to many without changing its CSS. Define the columns, let auto-placement create rows, and choose whether unused columns should keep their space.
Let items find the next cell
The default grid-auto-flow: row places unpositioned items in source order, moving across a row and then down to the next. It skips occupied cells. Extra tracks form the implicit grid.
.products {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: minmax(150px, auto);
}
Seven items create three rows. The final row contains one item. Each row is at least 150px tall and can grow with its content. Explicit tracks come from the template; implicit tracks are added as placement needs them.
Negative line numbers count only within the explicit grid. If you define columns but no rows, grid-row: 1 / -1 cannot mean every automatically created row. Define explicit rows when an item must span their complete height.
grid-auto-flow: column fills columns and creates extra columns sized by grid-auto-columns. Adding dense lets later smaller items backfill holes left by larger spans. That can change the visual sequence, so avoid it for ordered instructions or other content whose sequence matters.
Count columns from a minimum
.products {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 16px;
}
In a 1000px content width, four 200px columns plus three 16px gaps need 848px. Five columns plus four gaps need 1064px, so only four fit. Their flexible final widths are 238px: subtract 48px of gaps and divide the remaining 952px by four.
At 500px, two minimum columns plus one gap need 416px; three need 632px. Two fit and each becomes 242px. The number of columns changes with the available space without a breakpoint.
Choose what happens to unused columns
With enough items, auto-fill and auto-fit look the same. With only three items in that 1000px grid, auto-fill retains a fourth empty column, so each occupied column remains 238px wide. auto-fit collapses that empty track and its gap. The three occupied columns then share 968px and become about 322.7px each.
A column with an item anywhere in it is occupied, even if one cell in its last row is empty. Auto-fit collapses empty tracks, not every empty cell.
Protect the narrowest container
Auto-repeat needs a definite minimum or maximum track size. repeat(auto-fill, 1fr) is invalid. A fixed minimum of 400px can also overflow a 320px container. Use:
grid-template-columns:
repeat(auto-fit, minmax(min(100%, 400px), 1fr));
min(100%, 400px) chooses the smaller minimum, so a narrow container can hold one track without being forced to 400px. Continue to handle oversized text or images within the cards.
Key Takeaways
- Auto-placement fills available cells and creates implicit tracks as needed.
grid-auto-rowssizes automatically created rows.- Auto-fill retains empty tracks; auto-fit collapses them.
- Column counts must include the gaps between columns.
- Use a definite auto-repeat minimum or maximum.
min(100%, …)keeps a track minimum within a narrow container.- Dense packing can change visual order.
4.4 Align boxes inside areas or tracks inside a container
Grid alignment has two different scales. You can move an item within its area, or move the entire set of tracks within the container. First identify which space you want to distribute.
Align items within their areas
In horizontal English, justify- properties act on the inline, horizontal axis. align- properties act on the block, vertical axis. Grid supports item alignment on both axes.
| Set on the container | Override on one item | Effect |
|---|---|---|
justify-items | justify-self | Inline position within the area |
align-items | align-self | Block position within the area |
Values include start, end, center and stretch. align-items: baseline aligns text baselines. Most automatically sized items stretch by default. An image with its own aspect ratio normally starts at the area's start edge instead of being stretched in both directions.
For a row of cards, stretching makes every card fill the row's height. Change to align-items: start and each card keeps its content height; their bottom edges can differ. align-self: end on one caption places it at the bottom of its grid area.
Center a box in both directions
.hero {
display: grid;
place-items: center;
min-height: 60vh;
}
place-items combines align-items followed by justify-items. With one value, it applies that value to both. The minimum height creates vertical room around a short item. place-self is the corresponding shorthand on an individual item.
The item remains a box with text inside. To center the words within that box, set text-align: center on the item. Moving a box to the center of a cell does not change how its text is aligned.
Move the tracks as a group
justify-content positions the full set of columns along the inline axis. align-content positions the rows along the block axis. These need extra space outside the tracks to show their effect.
For three fixed 200px columns in a 900px container with no gaps, 300px remains. justify-content: center leaves 150px before the first column and after the last. justify-content: space-between puts the outer columns at the container edges and distributes 150px between neighboring columns. Items stay inside their own tracks as the tracks move.
If the columns use fr and fill all available width, there is no horizontal remainder for justify-content to distribute. Setting justify-items: center can still visibly center a narrow child within its wide track. The first property positions tracks; the second positions items.
Key Takeaways
justify-follows the inline axis;align-follows the block axis.- Item alignment moves boxes within their areas.
- Content alignment moves tracks within the container.
place-itemscombines the two item-alignment properties.- Use
text-alignto align text inside an item.
5Build and debug real layouts
Real pages combine several layouts: a page grid can hold a flexible toolbar, cards and a positioned badge. Choose the method that fits each relationship, then build patterns that keep working when text grows or space becomes narrow. Work through content columns, footers, sidebars and form controls before using developer tools to locate inactive properties and overflow. Longer text, zoom and keyboard checks expose problems that sample content can hide.
5.1 Choose a method for the relationship you need
A page can use several layout methods at once. Choose each method for the relationship between the boxes in that part of the page: a sequence of text, a flexible group, shared columns or an overlapping layer.
Start from the content
Normal flow already handles articles, headings and paragraphs. It wraps text and moves later blocks down when earlier content grows. Add more structure when the design calls for a different relationship.
| Need | Useful method | Reason |
|---|---|---|
| A row or column of controls | Flexbox | Shares space among content-sized items |
| Columns aligned across several rows | Grid | Defines shared row and column tracks |
| A badge over an image | Absolute positioning | Places a layer relative to a chosen container |
| A control visible across the page | Fixed positioning | Keeps it tied to the viewport |
| A heading visible within its section | Sticky positioning | Keeps flow space and stops at the section's end |
| Text wrapping around a photo | Float | Shortens nearby text lines around the image |
| Text flowing into newspaper columns | Multiple-column layout | Continues text from one column into the next |
Flexbox is one-dimensional: it shares space along a row or column, with each wrapped line independent. Grid is two-dimensional: it defines columns and rows together. These are choices about the layout's constraints, not a ban on using either tool for a simple row.
Compare a wrapped row with shared columns
Seven cards occupy a 1000px content width with 16px gaps. In flexbox, give each card flex: 1 1 200px and allow wrapping. Four cards fit on line one and grow to 238px each. The three cards on line two grow to about 322.7px each. Each line spends its own free space.
Now use repeat(auto-fill, minmax(200px, 1fr)) in grid. Four columns fit. All seven cards use those same 238px column widths; the final row leaves one cell empty. Grid keeps alignment across the rows.
Use the flex version when wider items on the last line suit the design. Use the grid version when a consistent column structure matters.
Combine methods at different levels
A page can use grid for a sidebar and main area, flexbox for the main area's toolbar, and an absolute badge within one card. A card can be a grid item on the outside and a flex container on the inside. Set the outer relationship on its parent and the inner arrangement on the card itself.
For a long text list, columns: 3 or column-width: 250px creates multiple-column flow. Text continues down one column and then into the next; it is not a grid of independent cards. Check that this reading path suits the content.
Read older layouts with care
Floated columns, inline-block grids and HTML tables used for page layout still appear in older code. Their spacing and containment rules differ from flexbox and grid. When building new page structure, use modern layout tools. Keep <table> for data whose rows and columns express tabular relationships.
Key Takeaways
- Choose grid for shared rows and columns, flexbox for an independent row or column.
- Use floats when text must wrap around an image.
- Use positioning for overlaps or scroll-related placement.
- Multiple columns continue text through columns.
- A box can be an item of one layout and a container for another.
5.2 Page patterns that grow with the content
A useful page layout has a readable content width, space at the edges and room for longer content. Build its main regions in flow so a growing article moves the footer down naturally.
Center a content column
.container {
max-width: 1100px;
margin-inline: auto;
padding-inline: 16px;
}
The maximum limits growth on wide screens. Auto inline margins divide leftover space on both sides. Padding keeps text away from narrow screen edges. For running text, max-width: 65ch gives an approximate 65-character measure; one ch is the width of the digit 0 in the current font. A line length around 45–75 characters is a useful reading range, though actual letters vary in width.
Put page regions on a grid
.page {
display: grid;
grid-template-columns: 240px minmax(0, 1fr);
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
}
header { grid-area: header; }
aside { grid-area: sidebar; }
main { grid-area: main; }
footer { grid-area: footer; }
The header and footer span both columns. The sidebar keeps 240px, and main receives the remainder. The zero minimum on the flexible track prevents wide content from forcing the track beyond its available share. Handle that content with wrapping or scrolling inside main.
The three-column pattern often called the holy grail layout uses 200px 1fr 200px and middle-row areas "nav main aside", with the header and footer spanning all three columns. Fixed side columns still need enough available width; test the layout at narrow sizes.
Keep a short page's footer at the bottom
body {
margin: 0;
min-height: 100dvh;
display: grid;
grid-template-rows: auto 1fr auto;
}
With header, main and footer as direct children, the middle row fills unused height. A short page's footer reaches the window bottom; a long page's footer follows the content. This pattern is called a sticky footer, but the footer does not need position: sticky.
The traditional viewport unit is vh. On phones, 100vh can extend behind visible browser controls. Dynamic viewport height, dvh, follows the visible height as those controls change; all major browsers have supported it since 2022. Use min-height so longer content can enlarge the page. A fixed height can leave content overflowing over what follows.
A flex alternative uses a column body with min-height: 100dvh, then main { flex: 1; }. For a sidebar row, use .sidebar { flex: 0 0 240px; } and .main { flex: 1; min-width: 0; }.
Let a sidebar stick and an image span wide
A grid sidebar can use position: sticky; top: 16px; align-self: start. Keeping its own content height leaves room to move within its row.
For full-bleed article content, define columns as 1fr min(65ch, 100% - 32px) 1fr. Put ordinary children in column 2 and a wide image at grid-column: 1 / -1. The central track stays readable while the image spans the full container width.
Key Takeaways
- Auto inline margins center a limited-width content column.
- Use
min-heightfor full-height pages that must grow. - A sticky footer pattern keeps the footer in normal flow.
dvhfollows changing visible viewport height.- A zero flexible-track minimum helps prevent page overflow.
- A sticky grid sidebar needs travel space;
align-self: startavoids stretching. - A full-bleed item spans outside the article’s text column.
5.3 Reusable layouts for interface pieces
Small interface pieces combine the same few relationships: an image keeps its size, text fills what remains, related controls share a row, or several cards align their inner parts. Give each container the layout that expresses its job.
Choose the right kind of centering
| Content to center | Rule |
|---|---|
| One box on both axes | Parent: display: grid; place-items: center |
| A block with a limited width | Block: margin-inline: auto |
| Text or inline content | Parent: text-align: center |
Flexbox can also center one child with justify-content: center; align-items: center. Make sure the container has spare space on the relevant axis.
A navigation row and a media row
nav { display: flex; align-items: center; gap: 16px; }
.logo { margin-inline-end: auto; }
.media { display: flex; align-items: flex-start; gap: 16px; }
.media img { flex: none; width: 64px; }
.media-body { flex: 1; min-width: 0; }
In English, the logo stays left and the links gather right. When the navigation has exactly two children, a logo and a link list, justify-content: space-between can separate them; the list needs its own flex layout to arrange its links.
In the media row, the image keeps its width. Text receives the remainder and can shrink. Cross-axis start alignment prevents an auto-height image from stretching to match a long text block. This suits a comment, profile or product line.
Cards with aligned buttons
.cards {
display: grid;
grid-template-columns:
repeat(auto-fill, minmax(min(100%, 240px), 1fr));
gap: 24px;
}
.card { display: flex; flex-direction: column; }
.card .button { margin-top: auto; }
The parent grid stretches cards in each row to the same height. Within each card, the auto top margin spends unused vertical space before the button, placing it at the bottom. Titles can still have different heights.
To align titles, text and footers across cards, use subgrid. Make each card a grid item spanning three parent rows, then set display: grid; grid-template-rows: subgrid. Each card adopts those parent rows for its three parts. Subgrid has worked across major browsers since September 2023.
Overlays, forms and input groups
For text over an image, make the wrapper a grid and put both children at grid-area: 1 / 1. A later caption paints above the image. Another option is a relative wrapper with an absolute caption layer using inset: 0.
A form with alternating labels and fields can use grid-template-columns: max-content 1fr; gap: 12px 16px; align-items: center. The widest label sets one shared label column. The fields align in the second column; separate flex rows cannot share that label width automatically.
A search group uses display: flex; gap: 8px, with input { flex: 1; min-width: 0; } and button { flex: none; }. The input can shrink while the button keeps its natural width. For tags or toolbar controls that should wrap at their natural widths, use display: flex; flex-wrap: wrap; gap: 8px.
Key Takeaways
- Center a box, a block and inline text with the appropriate kind of alignment.
- Use a fixed-size image and a flexible text item for a media row.
- Column flexbox and an auto top margin align card buttons.
- Subgrid shares parent tracks across nested card parts.
- Grid can align labels across form rows.
- A flexible input often needs
min-width: 0.
5.4 Find the box causing the layout bug
A layout bug is easier to fix when you inspect the browser's actual boxes. Begin with the element that moved or overflowed, then check the layout it participates in before changing values.
Inspect in a useful order
- Find the element in developer tools.
- Inspect its parent's computed
display: normal flow, flex and grid give properties different jobs. - Check whether your property applies to that element in that layout.
- Compare computed sizes, margins and position with your expected values.
- Toggle one declaration at a time to see which constraint causes the problem.
The box-model panel shows content, padding, border and margin. Grid overlays show lines, numbers, tracks and gaps; flex overlays show items and their allocation. Use them to check what the browser built, not just what the stylesheet intended.
Check inactive properties
Offsets do nothing on a static element. Width and height do nothing on an ordinary inline <span>, though they do size an inline image. z-index needs a positioned box or a flex/grid item. float has no effect on flex or grid items, and justify-self cannot align a flex item.
A valid alignment declaration may have no visible effect because items already use all the space. align-content also has no effect on a nowrap flex container. Sticky positioning needs an offset and space to move.
Track down horizontal overflow
Overflow can come from an oversized box or from a smaller box pushed beyond an edge by margins, offsets or neighboring widths. Common causes include:
- A fixed width, such as 1200px, larger than the viewport.
width: 100%plus padding undercontent-boxsizing.width: 100vw, which can include a visible vertical scrollbar's width.- A long unbroken word, URL or code line.
- A flex item's automatic minimum or a
1frtrack's automatic minimum. - An auto-repeat minimum wider than its container.
Temporarily add * { outline: 1px solid red; } to reveal edges. Outlines use no layout space, so they expose boundaries without changing box sizes as borders would.
Work through a wide code block
A flex page has a 240px sidebar and a main column containing a 1400px-wide code sample. The whole page scrolls sideways. The flex overlay shows main wider than its share, and its computed minimum width is auto.
.main { min-width: 0; }
.main pre { overflow-x: auto; }
The first rule lets the flex item shrink. The second keeps the wide code accessible through local horizontal scrolling. Hiding all page overflow would conceal the symptom without making the code available.
For other surprises, inspect collapsing margins, a fixed header covering content, an absolute child whose intended parent is static, or a layer trapped inside an opacity- or transform-created stacking context.
Test real content and narrow space
Resize the window, use a long name or URL, and zoom text to 200%. Check keyboard focus near fixed bars. WCAG 2.2 criterion 1.4.4 requires text resizing to 200% without loss of content or function. Criterion 1.4.10 generally requires reflow at 320 CSS pixels without two-direction scrolling; content that needs a two-dimensional layout, such as a data table, has exceptions. Test more than the short sample text that first made the page look correct.
Key Takeaways
- Inspect the parent layout and computed values before changing declarations.
- Use overlays and outlines to locate actual box boundaries.
- Check whether a property applies and whether it has free space to use.
- Handle both a flexible item’s minimum and its overflowing content.
- Test narrow widths, 200% text zoom, longer text and keyboard focus.
CSS Layout with Flexbox and Grid examples
1Read the page’s natural layout
13 steps
- 1IntroductionStart with an ordinary article
Picture an article with a heading, two paragraphs, a link and a portrait. The browser already knows how to arrange these elements before you add layout CSS: headings and paragraphs are block boxes, links sit inline in the text, and
displaycan change that behavior.You will trace the default boxes, make the link a larger target, then place the portrait with a float so text wraps beside it. Watch both the text and the parent backgrounds: they respond to different parts of the layout.
- 2ExplanationTrace the block lines
The heading and paragraphs are block boxes by default. Each starts a new line and grows taller when its content wraps.
Set the first paragraph to
width: 260px. It becomes narrow, but the next paragraph still begins below it. A block does not become inline just because there is spare horizontal room next to it. Leave width automatic when it should fill its available line. - 3ExampleFollow the link inside a sentence
In
<p>Open the <a href="/notes">reading notes</a> before class.</p>, the link is part of the text line. It takes the space its words need and can wrap with the sentence.Adding
width: 190pxdoes not resize this ordinary inline link. Vertical padding can paint a larger background without moving adjacent text lines farther apart. An inline image is different: its width and height do apply. - 4ExampleMeasure a collapsed gap
The article paragraph has a 14px bottom margin. The following heading has a 26px top margin. When those positive vertical margins touch in normal flow, they collapse to 26px.
They do not add to 40px. If the parent later becomes flex or grid, the margins between its items stay separate, so the same declarations can produce more space.
- 5ChallengePut the gap inside the header
An unpadded header contains only a heading with a top margin. The margin collapses through the header and the gap appears above its background. How can you create interior top space instead?
---reveal---
Remove the heading’s top margin and add top padding to the header. Padding belongs inside the header’s box. A border or
flow-rootwould also stop parent–child collapse, but padding directly creates the desired interior spacing. - 6ExplanationGive the link its own sized box
Use
display: inline-blockon the article link when it needs a width and a taller padded target while staying in the text line..article-link { display: inline-block; padding: 10px 14px; }The box now participates with its full vertical size. Display changes its layout behavior; it remains an HTML link. Whitespace between neighboring inline-blocks still appears as a text space.
- 7Key InsightSeparate outside from inside
A box can take part in one layout and run another inside itself.
display: flexmeans block outside, flex inside.inline-flexkeeps the same inner flex layout but uses inline outer placement.The rule affects direct children. A flex navigation makes its list a flex item; it does not automatically make every nested link an item in that outer row. Put a separate layout on the list when its links need their own row.
- 8ChallengeReserve room for a message
A reading-status message should be hidden initially, with its space reserved so the article does not shift when it appears. Should it use
display: noneorvisibility: hidden?---reveal---
Use
visibility: hiddento keep its layout space.display: noneremoves its box and the gap, so showing it would move later content. If text must remain available to screen readers while hidden visually, a visually-hidden class serves that separate purpose. - 9ExampleFloat the portrait
Place the portrait before the paragraph and float it:
.portrait { float: left; width: 130px; margin: 0 18px 10px 0; }Text lines wrap beside the photo with an 18px horizontal gap. Once they pass its bottom margin, they return to full width. The paragraph’s background may extend behind the float even though the text itself stays beside it.
- 10ExampleContain the image’s height
If the article text is very short, the float may extend below its parent’s background. Floated children do not supply ordinary flow height.
Add
display: flow-rootto the wrapper. Its independent flow region now contains the portrait, so the wrapper’s border and background reach around it. This also separates parent–child margins; it does not add clipping or a scrolling area. - 11ChallengeBegin a new section below the portrait
The portrait still reaches below the article’s first paragraph. The next section heading must begin beneath it, while the paragraph may keep wrapping. What rule belongs on the heading?
---reveal---
Use
clear: left, orclear: bothif floats on either side should be cleared. This moves the heading below earlier floats. It is a different job fromflow-root, which makes a parent include the height of its floated children. - 12ChallengeA parent change removes the wrapping
You change the photo-and-text wrapper to
display: flex. Its floated portrait no longer makes text lines wrap beneath the image. Why, and what restores the intended article flow?---reveal---
The portrait is now a flex item, so its float has no effect. The paragraph occupies a separate flex item. Return this wrapper to normal flow, keep the portrait floated, and use
flow-rootif the wrapper should contain the image. - 13RecapRead the parent before changing the child
Block and inline behavior explains the article’s starting layout. Display can change outer participation, inner layout or whether a box exists at all.
For text around a portrait, keep the text in ordinary flow with a float, contain the float when needed, and clear later sections that must start below it. When the result changes unexpectedly, inspect the parent’s display as well as the child’s rules.
2Place badges and keep navigation visible
14 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionDecide what should move with what
- 2ExplanationKeep or remove the original space
- 3ExampleMake the card the badge’s reference
- 4ExamplePlace the badge inside the corner
- 5ChallengeChoose the percentage reference
- 6ExamplePin help to the window
- 7ExampleKeep a section heading in its section
- 8ChallengeA heading has nowhere to travel
- 9TipLeave space beneath a fixed header
- 10ExplanationCompare the outer groups first
- 11ExampleFix the ancestor level
- 12ChallengeDoes a static grid caption need position?
- 13ChallengeA fixed toolbar still loses the overlap
- 14RecapCheck reference, flow space and group
3Build a flexible toolbar and card row
17 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionBuild a row that shares its space
- 2ExplanationMake only the direct children flex items
- 3ExplanationTurn the axes with direction
- 4ChallengeCenter a vertical group
- 5ExampleStart the growth calculation
- 6ExampleAdd growth to the bases
- 7ExampleWeight the shrinking by base size
- 8ChallengeChoose equal widths or preserve size differences
- 9TipLet a long code line stay local
- 10ExampleLet cards wrap into independent lines
- 11ExplanationDistribute only the leftover space
- 12ExampleAlign text within the line
- 13ChallengePush a group to the far end
- 14Key InsightLines and items have different alignment
- 15TipKeep oversized centered content reachable
- 16ChallengeA centered row does not move
- 17RecapRead flexbox in three stages
4Build a dashboard and an automatic card grid
18 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionGive several rows shared boundaries
- 2ExplanationTracks are the spaces between lines
- 3ExampleSubtract fixed tracks and gaps
- 4ExampleTurn shares into column widths
- 5ChallengePercentage columns exceed the row
- 6ExampleCount the panel’s end boundary
- 7ExplanationUse names for page regions
- 8ChallengeA shape that areas cannot express
- 9ConnectionShare a cell to create an image layer
- 10ExplanationLet new rows appear
- 11ExampleFind how many minimum columns fit
- 12ExampleCollapse unused tracks with auto-fit
- 13ChallengeKeep a minimum inside a narrow box
- 14ExplanationMove an item inside its area
- 15ExampleMove the columns as one group
- 16ChallengeWhy do card bottoms stop lining up?
- 17ChallengeA full-width banner above automatic cards
- 18RecapSeparate sizing, placement and alignment
5Assemble a reading page and fix its weak points
19 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionBuild from the page down to its parts
- 2ExplanationGive each method a concrete job
- 3ChallengeChoose columns for a resource collection
- 4ExampleLimit the reading width
- 5ExampleReserve one fixed and one flexible column
- 6ExampleMake room for the footer without fixing it
- 7TipAllow height and viewport space to change
- 8ChallengeLet a photo go wider than the article
- 9ExampleNest a flex toolbar inside the page grid
- 10ExampleKeep the image and text in balance
- 11ExampleAlign card parts at the needed level
- 12ExampleLet a field share a row with a button
- 13ChallengeCenter the box or its words?
- 14ExplanationInspect the layout the browser built
- 15ExampleFollow a wide code block outward
- 16TipReveal edges without moving them
- 17ChallengeA width reset is not enough
- 18ChallengeTest the page beyond the sample
- 19RecapUse real content to check each relationship
CSS Layout with Flexbox and Grid practice questions
Set 1: Flow, layers and flexible containers10 Practice Questions
Question 1 of 10
Show answerHide answer
Question 2 of 10
<span> has width: 180px and 10px vertical padding. Why can its background overlap neighboring text lines while its width stays content-sized?Show answerHide answer
Question 3 of 10
z-index: 4 contains an absolute menu at z-index: 800. A sibling relative main area is at z-index: 5. Both outer boxes are in the same parent stacking context. What change puts the entire header above main?Show answerHide answer
Question 4 of 10
position: relative; top: 9px. What happens to the following paragraph’s normal-flow position?Show answerHide answer
Question 5 of 10
Show answerHide answer
Question 6 of 10
Show answerHide answer
Question 7 of 10
Show answerHide answer
Question 8 of 10
Show answerHide answer
Question 9 of 10
Show answerHide answer
Question 10 of 10
min-width: auto; the whole page scrolls sideways. The code must remain available without widening the page. What paired fix addresses both boxes?Show answerHide answer
Set 2: Boxes, space and layout choices10 Practice Questions
Save this lesson to see every answer and practice every set.
Question 1 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 2 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 3 of 10
position: relative and no other rule creates a containing block between them. What box supplies the badge’s offset reference?Show answerHide answer
Save this lesson to see this answer.
Question 4 of 10
position: sticky but all four offsets remain auto. What declaration lets it stick at the top during vertical scrolling?Show answerHide answer
Save this lesson to see this answer.
Question 5 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 6 of 10
flex shorthand, which part sets the item’s starting size along the main axis?Show answerHide answer
Save this lesson to see this answer.
Question 7 of 10
160px 1fr 2fr and a 15px column gap. Content minimums do not constrain the tracks. How wide is the 2fr column?Show answerHide answer
Save this lesson to see this answer.
Question 8 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 9 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 10 of 10
Show answerHide answer
Save this lesson to see this answer.
Set 3: Shared tracks and changing content10 Practice Questions
Save this lesson to see every answer and practice every set.
Question 1 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 2 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 3 of 10
top: 0 inside an ancestor with overflow: auto. The page scrolls, but that ancestor does not. What should be inspected as the likely reason the heading never sticks to the viewport?Show answerHide answer
Save this lesson to see this answer.
Question 4 of 10
opacity: 0.8. The card is inside a relative section at z-index: 2. An overlapping sibling section is relative at z-index: 3. Raising the tooltip’s z-index changes nothing. What outer change can bring this tooltip’s whole section forward?Show answerHide answer
Save this lesson to see this answer.
Question 5 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 6 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 7 of 10
"banner banner" "banner main" as its two rows. Why is this named-area declaration invalid?Show answerHide answer
Save this lesson to see this answer.
Question 8 of 10
repeat(auto-fit, minmax(180px, 1fr)) in an 860px grid with 20px gaps. They have no size constraints or extra spacing. How many occupied columns remain, and how wide is each?Show answerHide answer
Save this lesson to see this answer.
Question 9 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 10 of 10
grid-area: 1 / 1. The caption follows the image in HTML and neither has z-index. Which one paints on top?Show answerHide answer
Save this lesson to see this answer.
Set 4: Diagnose placement and alignment10 Practice Questions
Save this lesson to see every answer and practice every set.
Question 1 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 2 of 10
<ul> is a grid container. Each <li> contains a link. Which elements become grid items of the <ul>?Show answerHide answer
Save this lesson to see this answer.
Question 3 of 10
content-box. An absolute child has width: 50% and right: 12px, with no own padding, border or margin. What is the child width and its left-edge distance from the card’s left padding edge?Show answerHide answer
Save this lesson to see this answer.
Question 4 of 10
flex: 1 1 150px in a 640px wrapping row with 10px gaps. There are no margins, padding, borders or size limits. How do the cards divide into lines, and what widths do the two lines produce?Show answerHide answer
Save this lesson to see this answer.
Question 5 of 10
row-reverse. The group should be packed against the left edge, regardless of its reversed main-start. What justify-content value follows that writing-direction start edge?Show answerHide answer
Save this lesson to see this answer.
Question 6 of 10
repeat(2, 80px 1fr)?Show answerHide answer
Save this lesson to see this answer.
Question 7 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 8 of 10
justify-content: center, how much space lies before the first column?Show answerHide answer
Save this lesson to see this answer.
Question 9 of 10
top: 12px, no fixed height, and default stretching; it fills the row and does not visibly travel. No ancestor overflow interferes. What change creates room for it to stick while keeping it in flow?Show answerHide answer
Save this lesson to see this answer.
Question 10 of 10
width: 100%, 14px left and right padding, and box-sizing: content-box, with no border. Its parent’s content width is 390px. Why does this box exceed the parent?Show answerHide answer
Save this lesson to see this answer.
Set 5: Combine the rules in new layouts10 Practice Questions
Save this lesson to see every answer and practice every set.
Question 1 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 2 of 10
display: flex. The image still has float: left, but the paragraph no longer wraps its lower lines beneath it. How can ordinary text wrapping around the image be restored?Show answerHide answer
Save this lesson to see this answer.
Question 3 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 4 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 5 of 10
order: -1 moves the last link visually first. What sequences do normal keyboard focus and screen-reader reading follow?Show answerHide answer
Save this lesson to see this answer.
Question 6 of 10
margin-inline-start: auto, and the container has justify-content: center. No other spacing applies. Where does the third item start from the left content edge?Show answerHide answer
Save this lesson to see this answer.
Question 7 of 10
grid-column: 2 / -1; grid-row: 2 / span 2. How many cells does it cover?Show answerHide answer
Save this lesson to see this answer.
Question 8 of 10
1fr min(65ch, 100% - 32px) 1fr. In its current font, 1ch is 8px. For content widths of 480px and 900px, what are the middle track widths, and which placement makes a photo full bleed?Show answerHide answer
Save this lesson to see this answer.
Question 9 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 10 of 10
Show answerHide answer
Save this lesson to see this answer.
Stuck on your own question? Homework Help
Key Terms
A
Absolute positioning
Align-content
Align-items
Align-self
Auto margin
Auto-fill
Auto-fit
Auto-placement
Automatic minimum size
B
Baseline alignment
Block box
Block formatting context
C
Ch unit
Clear
Clearfix
Computed value
Containing block
Content alignment
Content column
Cross axis
D
Dense packing
Display none
Dynamic viewport height
E
Explicit grid
F
Fixed positioning
Flex container
Flex item
Flex shorthand
0 0 180px gives a sidebar a 180px basis without growing or shrinking.Flex wrapping
Flex-basis
Flex-grow
Flex-shrink
Flexbox
Float
Flow-root
Form grid
Fr unit
Free space
Full bleed
G
Gap
Grid area
Grid cell
Grid container
Grid item
Grid line
Grid track
I
Implicit grid
Inline box
Inline direction
Inline-block
Inner display type
Input group
Inset
Isolation
Item alignment
J
Justify-content
Justify-self
L
Layout overlay
M
Main axis
Margin collapsing
Media object
Minmax
Multiple-column layout
N
Named area
Named line
Nested layout
Normal flow
O
One-dimensional layout
Outer display type
Overflow
Overlay
P
Place-items
Positioned element
R
Reflow
Relative positioning
S
Scroll-padding-top
Span
grid-column: 2 / span 3 gives the panel a span of three column tracks.Stacking context
Stacking order
Sticky footer pattern
Sticky positioning
Subgrid
T
Two-dimensional layout
V
Viewport
Visibility hidden
Z
Z-index
- 1How the Web Works
- 2HTML
- 3HTML Forms
- 4CSS
- 5CSS Layout with Flexbox and Grid
- 6Responsive Web Design
- 7Building Accessible Web Pages
- 8Publishing a Website
About this lesson
Make your own Study Materials
Turn your notes, slides and documents into Study Guides, Practice Questions, Flashcards and 6 more tools.