Real Flexbox Layouts: Navbar, Cards, Search Bar and Centering
Build five common interface patterns with Flexbox: a navbar, a centered hero, equal-height cards, a comment row and a search bar, with a map of every class.
What you will learn
Knowing the Flexbox properties is one thing. Knowing which ones to reach for when you meet a real design is what matters. In this lesson you will build five patterns that appear on almost every website: a navbar, a centered hero section, a row of equal-height cards, a comment with an avatar beside the text, and a search bar. For each one you will see the HTML, which element is the flex container, which are the flex items, and why each property is there.
The HTML we will style
<!-- Pattern 1: navbar -->
<header class="navbar">
<a href="#home" class="navbar-logo">CodeNest</a>
<nav class="navbar-links">
<a href="#html" class="navbar-link">HTML</a>
<a href="#css" class="navbar-link">CSS</a>
<a href="#js" class="navbar-link">JavaScript</a>
</nav>
<a href="#signup" class="navbar-cta">Sign up</a>
</header>
<!-- Pattern 2: centering inside a hero -->
<section class="hero">
<div class="hero-content">
<h1 class="hero-title">Learn web development</h1>
<p class="hero-text">Free lessons, simple examples.</p>
</div>
</section>
<!-- Pattern 3: equal-height cards -->
<section class="cards">
<article class="card">
<h3 class="card-title">HTML</h3>
<p class="card-text">The structure of every web page.</p>
<a href="#html" class="card-link">Start HTML</a>
</article>
<!-- two more cards: CSS and JavaScript -->
</section>
<!-- Pattern 4: avatar next to text -->
<div class="comment">
<div class="comment-avatar">A</div>
<div class="comment-body">
<h4 class="comment-name">Aisha</h4>
<p class="comment-text">The flexbox lessons finally made layout click...</p>
</div>
</div>
<!-- Pattern 5: search bar -->
<form class="search">
<input class="search-input" type="search" placeholder="Search lessons">
<button class="search-button" type="submit">Search</button>
</form>
This table shows, for each pattern, who is the container and who are the items. Keep it in mind as you read the CSS:
| Pattern | Flex container | Flex items | Main idea |
|---|---|---|---|
| 1. Navbar | .navbar |
.navbar-logo, .navbar-links, .navbar-cta |
align-items: center and margin-left: auto |
| 1b. Links inside it | .navbar-links (a nested container) |
the three .navbar-links |
a second flex row inside the first |
| 2. Hero | .hero |
.hero-content |
justify-content and align-items: center |
| 3. Cards | .cards |
the three .cards |
flex: 1 1 220px and flex-wrap |
| 3b. Inside each card | .card (a column container) |
.card-title, .card-text, .card-link |
margin-top: auto pins the link to the bottom |
| 4. Comment | .comment |
.comment-avatar, .comment-body |
a fixed avatar and a fluid text column |
| 5. Search bar | .search |
.search-input, .search-button |
flex: 1 makes the input fill the row |
Notice that one element can be both an item and a container: .navbar-links is an item of .navbar, and a container for the links. This is called nesting and it is the key to building complex layouts from simple pieces.
Pattern 1: the navbar
A navbar has a logo on the left, links in the middle or on the right, and sometimes a button at the far end. All of the children are in one row, centred vertically.
/* the <header class="navbar">: the flex container */
.navbar {
display: flex;
align-items: center; /* vertically center logo, links and button */
gap: 24px;
padding: 12px 20px;
background-color: #1e293b;
}
/* the <a class="navbar-logo"> */
.navbar-logo {
color: white;
font-weight: bold;
text-decoration: none;
}
/* the <nav class="navbar-links">: an item of .navbar AND a container itself */
.navbar-links {
display: flex;
gap: 16px;
margin-left: auto; /* eat all the free space on the left */
}
/* each <a class="navbar-link"> */
.navbar-link {
color: #cbd5e1;
text-decoration: none;
}
/* the <a class="navbar-cta"> button */
.navbar-cta {
padding: 8px 16px;
background-color: royalblue;
color: white;
text-decoration: none;
border-radius: 6px;
}
The trick is margin-left: auto on .navbar-links. As you learned, an auto margin absorbs all the free space, so everything from the links onwards is pushed to the right while the logo stays on the left. Compare this with justify-content: space-between, which would spread the logo, links and button evenly, putting the links in the middle. Both are valid. Which looks better depends on your design.
Why is
.navbar-linksa flex container too? Because its links should sit in a row with agap. Withoutdisplay: flexthey would flow as inline text. Making the<nav>a second flex container is the easy way to space them evenly.
A navbar that wraps on small screens
On narrow screens, the row can get too crowded. The simplest fix is to allow wrapping:
.navbar {
flex-wrap: wrap;
}
Items that do not fit move onto a second line instead of squashing. Later, in the responsive lessons, you will learn to use a media query to restructure it properly.
Pattern 2: centering inside a hero
A hero is a big banner with text in the middle. You learned the three-line recipe. Here it is in a real place:
/* the <section class="hero"> */
.hero {
display: flex;
justify-content: center; /* horizontal centre */
align-items: center; /* vertical centre */
min-height: 240px;
background-color: #eef2ff;
text-align: center;
}
/* the <div class="hero-content"> */
.hero-content {
max-width: 480px;
padding: 20px;
}
.hero-title {
margin: 0 0 8px;
}
.hero-text {
margin: 0;
color: #475569;
}
min-height (not height) means the hero can grow if the text gets longer. .hero-content has a max-width so that long text does not stretch across the whole banner. Note that text-align: center is still needed to centre the text lines inside the box. Flexbox centres the box, not the words inside it.
Pattern 3: equal-height cards
Cards in a row should line up, with the same height, even when one has more text. Flexbox does this almost for free, because align-items defaults to stretch.
/* the <section class="cards">: the flex container */
.cards {
display: flex;
flex-wrap: wrap;
gap: 16px;
padding: 20px;
}
/* each <article class="card"> */
.card {
flex: 1 1 220px; /* grow and shrink, but ideally 220px wide */
display: flex; /* the card is ALSO a container: its content stacks */
flex-direction: column;
padding: 20px;
border: 1px solid #dddddd;
border-radius: 12px;
background-color: white;
}
Two flex ideas work together:
flex: 1 1 220pxon.cardmeans each card wants to be 220px wide, but they can grow to share the row, and shrink if needed. Withflex-wrap: wrapon.cards, if three cards do not fit, the last one wraps to a new line. This gives you a responsive card grid without any media query. All cards in a line are the same height because ofstretch.display: flex; flex-direction: columnon.cardturns each card into a vertical container. That lets us push the link to the bottom of the card:
/* the <a class="card-link"> */
.card-link {
margin-top: auto; /* absorbs the free space ABOVE the link */
padding-top: 16px;
color: royalblue;
text-decoration: none;
font-weight: bold;
}
.card-title {
margin: 0 0 8px;
}
.card-text {
margin: 0;
color: #475569;
}
Because the card is a column container, margin-top: auto on the link eats the leftover vertical space, so the link sticks to the bottom edge. In the middle card, the text is longer, but all three links still line up on the same baseline at the bottom, which looks tidy.
Pattern 4: avatar beside text (the media object)
A fixed-size image or avatar on one side, and flexible text on the other, is called the media object. It is used in comments, news lists and chat messages.
/* the <div class="comment">: the flex container */
.comment {
display: flex;
align-items: flex-start; /* avatar stays at the top, not stretched */
gap: 12px;
margin: 24px 20px;
}
/* the <div class="comment-avatar">: a fixed-size circle */
.comment-avatar {
flex: 0 0 48px; /* never grow or shrink: always 48px */
height: 48px;
border-radius: 50%;
background-color: royalblue;
color: white;
font-weight: bold;
text-align: center;
line-height: 48px;
}
/* the <div class="comment-body">: takes the rest of the width */
.comment-body {
flex: 1;
min-width: 0; /* lets long words or code wrap instead of overflowing */
}
.comment-name {
margin: 0 0 4px;
}
.comment-text {
margin: 0;
}
The recipe is always the same: the small thing gets flex: 0 0 <size> and the text column gets flex: 1. Without flex: 0 0 48px, a long comment could squash the avatar into an oval. Without align-items: flex-start, the avatar would stretch to the full height of the text.
Pattern 5: the search bar
An input and a button side by side, with the input filling all the free space:
/* the <form class="search">: the flex container */
.search {
display: flex;
gap: 8px;
margin: 20px;
max-width: 480px;
}
/* the <input class="search-input"> */
.search-input {
flex: 1; /* fill the row */
padding: 10px 12px;
border: 2px solid #cccccc;
border-radius: 6px;
font: inherit;
}
/* the <button class="search-button"> */
.search-button {
padding: 10px 18px;
border: none;
border-radius: 6px;
background-color: royalblue;
color: white;
font: inherit;
cursor: pointer;
}
The button keeps its natural size, and flex: 1 makes the input take everything that remains. No widths, no percentages, no calculations. When the container gets narrower, the input shrinks and the button stays put.
Which Flexbox tool for which job?
| You want to… | Use |
|---|---|
| Put things in a row | display: flex on the parent |
| Centre something both ways | justify-content: center; align-items: center; |
| Push one item to the far end | margin-left: auto on that item |
| Make a column fill the rest | flex: 1 |
| Keep an item a fixed size | flex: 0 0 <size> |
| Let items flow onto new lines | flex-wrap: wrap with flex: 1 1 <size> |
| Pin something to the bottom of a card | flex-direction: column on the card, margin-top: auto on the item |
| Space items evenly | justify-content: space-between (or gap) |
Putting it together
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; font-family: Arial, Helvetica, sans-serif; }
/* 1. navbar */
.navbar { display: flex; align-items: center; gap: 24px; padding: 12px 20px; background-color: #1e293b; }
.navbar-logo { color: white; font-weight: bold; text-decoration: none; }
.navbar-links { display: flex; gap: 16px; margin-left: auto; }
.navbar-link { color: #cbd5e1; text-decoration: none; }
.navbar-cta { padding: 8px 16px; background-color: royalblue; color: white; text-decoration: none; border-radius: 6px; }
/* 2. hero */
.hero { display: flex; justify-content: center; align-items: center; min-height: 240px; background-color: #eef2ff; text-align: center; }
.hero-content { max-width: 480px; padding: 20px; }
/* 3. cards */
.cards { display: flex; flex-wrap: wrap; gap: 16px; padding: 20px; }
.card { flex: 1 1 220px; display: flex; flex-direction: column; padding: 20px; border: 1px solid #dddddd; border-radius: 12px; }
.card-link { margin-top: auto; padding-top: 16px; color: royalblue; text-decoration: none; font-weight: bold; }
/* 4. comment */
.comment { display: flex; align-items: flex-start; gap: 12px; margin: 24px 20px; }
.comment-avatar { flex: 0 0 48px; height: 48px; border-radius: 50%; background-color: royalblue; color: white; text-align: center; line-height: 48px; }
.comment-body { flex: 1; min-width: 0; }
/* 5. search */
.search { display: flex; gap: 8px; margin: 20px; max-width: 480px; }
.search-input { flex: 1; padding: 10px 12px; border: 2px solid #cccccc; border-radius: 6px; font: inherit; }
.search-button { padding: 10px 18px; border: none; border-radius: 6px; background-color: royalblue; color: white; font: inherit; cursor: pointer; }
Common mistakes
- Forgetting that
.navbar-linksneeds its owndisplay: flex. The<nav>is an item of the navbar, but its links are not items of anything until you make it a container too. - Using
heightfor a hero, so long text overflows. Usemin-height. - Expecting
justify-content: centerto centre the text lines. It centres the box. Usetext-alignfor text. - Letting the avatar shrink because
flex: 0 0 48pxwas left out. - Forgetting
min-width: 0on the fluid text column, so a long URL or code line stretches the layout. - Making all the cards a fixed
width. Useflex: 1 1 <size>withflex-wrap, so they adapt. - Forgetting
flex-direction: columnon the card and wondering whymargin-top: autopushes the link sideways instead of down. - Using
margin-top: autoon an item whose parent is not a flex container. Auto margins only absorb space inside flex (and grid) containers. - Layout with Flexbox when you need rows AND columns that align. Reach for Grid.
Practice
- Click Practice in Editor. Finish the navbar by adding the
.navbar-ctabutton. Then tryjustify-content: space-betweeninstead ofmargin-left: auto. How do they differ? - Build the hero. Make it centre its content, then try
min-height: 60vh. - Write the
.cardsand.cardrules. Resize the preview and watch how many cards fit on a line. Then addmargin-top: autoto the links. - Shorten the text of the second card. Do the links still line up?
- Build the comment pattern. Remove
flex: 0 0 48pxfrom the avatar and give the comment a very long text. What happens to the avatar? - Style the search bar. Check that the input takes the free space, and that the button does not get squashed.
- Add
flex-wrap: wrapto the navbar and shrink the preview to see how it behaves.
Recap
- A real layout is nested flex containers: each element can be an item of its parent and a container for its own children.
- Navbar:
display: flex; align-items: center;, andmargin-left: autoto push items to the right. - Hero:
display: flex; justify-content: center; align-items: center;withmin-height. - Cards:
flex: 1 1 220pxwithflex-wrap: wrapfor a responsive grid of equal-height cards. A column-direction card withmargin-top: autopins its last item to the bottom. - Media object: fixed item
flex: 0 0 <size>, fluid itemflex: 1; min-width: 0. - Search bar:
flex: 1on the input fills the row. - Next you will learn CSS Grid, which lays out rows and columns together.