Door 6 – Everyday Flexbox Patterns | CSS Adventskalender
Skip to content

Door 6 – Everyday Flexbox Patterns

Published: at 07:00 AM

Flexbox can do an incredible amount, but in everyday life, it’s a few recurring patterns that make the difference. These patterns solve typical layout problems consistently, are team-friendly, and have proven themselves over years.

This door shows the most important Flexbox patterns from practice that I use in almost every codebase. They are robust, intuitive, and help to develop layouts faster and more reliably.

Pattern 1: Perfect Centering

Probably the most common and universal Flexbox pattern is perfect centering. For years, centering elements – especially vertically – was one of the biggest challenges in CSS. With Flexbox, it has become trivial:

.center {
  display: flex;
  justify-content: center;
  align-items: center;
}

This pattern works for almost any use case such as modal overlays that need to display their content perfectly centered, loader animations that should appear in the middle of the viewport, or icons in buttons that need to sit exactly in the center. Empty states in applications that display a centered message.

The elegance lies in independence. The centering works along both axes completely independent of content or size. No matter how large the centered element is or how the container changes. The element remains perfectly centered. There are no calculations, no negative margins, and no tricks with positioning. Flexbox takes care of all the work.

Pattern 2: Distributing Space Evenly

Another fundamental pattern is the even distribution of elements with maximum spacing between them. space-between pushes the first element to the left edge, the last to the right edge, and distributes the available space evenly between all elements:

.spread {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

This pattern appears in almost every application. Header components use it to place the logo on the left and navigation on the right. Footer areas use it to distribute their links evenly across the full width. Toolbars, menus, and action bars use it to optimally position actions – primary on the left, secondary on the right.

A typical practical example is a header with multiple sections:

.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem;
}

Since the broad support of the gap property in Flexbox, this pattern has become even more robust. With gap, you define a minimum spacing between elements that is maintained even when the container width changes:

.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
}

The advantage: You no longer need to worry about margins on individual elements. The spacing is uniformly inserted between all items, never at the edge of the container.

Pattern 3: Autospace – Pushing Free Space to a Specific Spot

A very useful and often underestimated pattern is the use of margin: auto in Flexbox containers. This pattern allows you to specifically separate individual elements without affecting all other elements:

.auto-space {
  margin-left: auto;
}

The application becomes particularly clear in a toolbar. Suppose you have multiple buttons, most of which should be on the left, but one button – such as “Next” or “Save” – should be positioned all the way to the right:

<div class="toolbar">
  <button>Back</button>
  <button class="auto-space">Next</button>
</div>

The associated CSS is minimal:

.toolbar {
  display: flex;
  align-items: center;
}

Through margin-left: auto on the button, all available free space is used as left margin. The result: The button is automatically pushed to the right edge. Everything that comes to the right of this element is also pushed to the right.

This pattern works more reliably than space-between when you don’t want to distribute all elements evenly, but only need a targeted separation at a specific point. It is particularly valuable in dynamic interfaces where the number of elements can vary, but a specific element should always be at the end.

Pattern 4: Two Columns That Behave Flexibly

The classic two-column layout is one of the most frequently needed patterns in web applications. With Flexbox, it can be implemented elegantly and robustly:

.two-cols {
  display: flex;
  gap: 1rem;
}

.col {
  flex: 1;
}

The shorthand flex: 1 means that both columns share the available space equally. Each column receives exactly half the width, regardless of content. The gap property ensures clean spacing between columns without having to define margins on individual elements.

For production environments, this pattern is often made more robust with flex-basis:

.col {
  flex: 1 1 250px;
}

This notation means: The column can grow (flex-grow: 1), it can shrink (flex-shrink: 1), and its base width is 250 pixels. The columns flexibly adapt to the available space and shrink below their base width if necessary. For automatic wrapping, flex-wrap: wrap must additionally be set on the container, which then enables responsive behavior without explicit media queries.

This pattern is extremely common in admin interfaces and dashboards. Typical use cases are detail views with form on the left and preview on the right, lists with main content on the left and metadata on the right, or split editors with code and preview.

The Holy Grail pattern for very many layouts is the so-called sticky footer. This is a footer that sticks to the bottom of the viewport when content is short, but flows normally when scrolling when content is long enough. Before Flexbox, this pattern required complicated calculations or JavaScript. With Flexbox, it’s surprisingly simple:

.layout {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

.layout-content {
  flex: 1;
}

The associated HTML is minimally structured:

<div class="layout">
  <header>Header</header>
  <main class="layout-content">Content</main>
  <footer>Footer</footer>
</div>

How does it work? The layout container takes up at least the full viewport height (min-height: 100vh). Through flex-direction: column, the children are arranged vertically. The crucial part is flex: 1 on the content area: This takes up all available space, while header and footer only claim as much space as they need.

The result: When content is short, the content area expands and pushes the footer to the bottom edge. When content is long, the content area grows accordingly and the footer appears after the content and this completely naturally and without position: fixed or other hacks. This pattern works reliably in all modern browsers and is the preferred method for layouts with sticky footer.

Pattern 6: Scrollable Areas in Flexbox Layouts

A problem that regularly challenges teams: An area within a Flexbox layout should be scrollable, but only its content should scroll while the rest of the layout remains fixed. The classic example is a dashboard with sidebar and main content, where only the main content should scroll.

The key to the solution lies in an often overlooked CSS property: min-width: 0 (or min-height: 0 for vertical layouts).

A complete example illustrates the problem and the solution:

.wrapper {
  display: flex;
  height: 100vh;
}

.sidebar {
  width: 250px;
}

.content {
  flex: 1;
  min-width: 0; /* allows shrinking below content width */
  overflow-y: auto;
}

Without min-width: 0, Flexbox blocks scrolling. The reason lies in the default behavior of Flexbox. Items have min-width: auto by default, which means they cannot become smaller than their content. So if the content area contains very wide content, such as a table or code block, the flex item would try to expand to that width instead of scrolling.

With min-width: 0, you override this behavior and allow the item to become smaller than its content. Only then can overflow-y: auto take effect and display a scrollbar.

This problem regularly appears in enterprise dashboards, admin panels, and complex applications. The solution is simple, but not intuitive, which is why it’s often overlooked and leads to hours of debugging.

Pattern 7: Flex-Wrapping for Responsive Layouts

A common task in modern websites is that items should be arranged next to each other when there’s enough space, but automatically wrap when the viewport becomes narrower. Flexbox offers an elegant solution with flex-wrap:

.wrap {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

.item {
  flex: 1 1 200px;
}

The behavior is intelligent and predictable. As long as there’s enough space for all items (based on the flex-basis of 200px plus gap), they are displayed next to each other. As soon as space becomes insufficient, the last item wraps to a new line. Items grow and shrink dynamically to optimally use the available space.

The result is a nice, fluid grid-like layout and this completely without CSS Grid. The advantage over Grid is that items can have different widths and flexibly adapt to content while still appearing in a structured grid.

This pattern is particularly useful when you don’t need a complete two-dimensional Grid structure, but a variable row layout with flexible widths. Typical use cases are tag lists, chip components, image galleries with different image sizes, or card layouts where the number of columns should depend on viewport width without defining explicit breakpoints.

Pattern 8: Solving Vertical Alignment Problems

A typical problem in forms and input layouts: Labels, inputs, buttons, and other form elements have different heights and baseline positions. This leads to unsightly optical jumps and an unprofessional appearance. Flexbox solves this problem elegantly:

.form-row {
  display: flex;
  align-items: center;
  gap: 1rem;
}

Through align-items: center, all elements are centered along the cross-axis (vertically in this case). A label with different height, an input field, an icon button. They are all perfectly aligned in the middle, regardless of their individual size.

The pattern doesn’t only work for forms. Wherever elements of different heights should stand horizontally next to each other, this pattern prevents optical inconsistencies. Navigation elements with icons and text, list entries with avatars and descriptions, toolbars with different button sizes. The pattern is universally applicable.

The alternative would be manual padding or margin tuning for each element. A maintenance nightmare that would need to be readjusted with every change in font size or content. With Flexbox, the alignment is dynamic and adapts automatically.

Pattern 9: Flexbox for Buttons or Tabs

A common UI pattern in modern interfaces: Buttons or tabs that form a group and share the available width equally. Each button should be the same width, but the group as a whole should remain flexible and adapt to the container:

.tabs {
  display: flex;
}

.tab {
  flex: 1;
  text-align: center;
  padding: 0.75rem;
}

With flex: 1, each tab receives exactly the same share of available space. Whether two, three, or five tabs. They always divide the width equally. The text-align: center ensures that the text appears centered within each tab.

This pattern is extremely robust for horizontal navigation elements. It works just as well on narrow mobile screens as on wide desktop monitors. The tabs automatically adapt to the container width without requiring media queries or JavaScript.

Variants of this pattern are found in tab navigations, segmented controls, button groups for view switching (list/grid), filter buttons, and all other scenarios where a group of options should be presented as equals. The equal distribution visually signals that all options have the same importance. An important UX detail that is harder to achieve with other layout methods.

Pattern 10: Aligning Content and Icon Cleanly

An everyday UI pattern that surprisingly often causes problems: Buttons or links that contain both text and an icon. Without special treatment, the icon often doesn’t sit correctly. It’s too high, too low, or doesn’t have the right spacing from the text. Flexbox solves this problem completely:

.button {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

Using inline-flex instead of flex is important here. The button behaves like an inline element in text flow, while its interior is Flexbox-based. align-items: center aligns icon and text perfectly in the middle, independent of font size or icon size. The gap property ensures consistent spacing between icon and text.

This pattern completely eliminates the notorious “icon is not sitting correctly” problem. Whether the icon is before or after the text, whether the font size changes, or whether you use different icon sizes. The alignment always remains perfect.

The pattern doesn’t only work for buttons. Navigation links with icons, list entries with status indicators, labels with badges, menu items with shortcuts. Wherever icon and text are combined, this pattern ensures professional, pixel-perfect alignment. The alternative would be manual tuning with relative positioning or vertical margins. Both maintenance-intensive and error-prone when changes occur in typography or icons.

Conclusion

These Flexbox patterns form the basis for very many UI components that we build daily. Whoever internalizes them solves recurring layout problems not only faster, but with greater stability and less CSS.


☕ Buy me a coffee

If you enjoy my articles and they help you in your work, I would appreciate a "coffee" and a few kind words from you.

Buy me a coffee

Previous Post
Door 7 – Grid Basics
Next Post
Door 5 – Flexbox Fundamentals

Comments