A practical guide to combining Flexbox and Grid to build responsive interfaces without relying on complicated positioning hacks.
Modern CSS provides powerful tools for building responsive interfaces without relying on complicated positioning hacks or excessive JavaScript.
Among the most important tools are Flexbox and CSS Grid. Understanding when to use each one can make layouts easier to build, maintain, and adapt to different screen sizes.
This article explores how these layout systems work together and how to build responsive interfaces with a simpler CSS architecture.
Flexbox is designed primarily for arranging elements along a single axis: either a row or a column.
A common example is a navigation bar:
.nav {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
}
The main properties you'll use frequently are:
display: flexflex-directionjustify-contentalign-itemsgapflex-wrapFor example, justify-content controls how items are distributed along the main axis, while align-items controls their alignment on the cross axis.
Flexbox is particularly useful for:
CSS Grid is designed for layouts where both rows and columns matter.
Consider a dashboard with multiple cards:
.dashboard {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5rem;
}
This creates three equally sized columns.
Grid becomes especially useful when the relationship between rows and columns is important.
For example:
.dashboard {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 1.5rem;
}
Using minmax(0, 1fr) can help prevent content from forcing grid tracks to become wider than expected.
A responsive layout should adapt to the available space instead of being designed around a specific screen size.
Avoid excessive use of fixed widths such as:
.card {
width: 400px;
}
Instead, let the layout determine the available width:
.card {
width: 100%;
max-width: 400px;
}
For collections of components, Grid can often handle responsiveness without manually specifying every breakpoint.
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1.5rem;
}
This allows the browser to determine how many columns can fit.
As the viewport changes, the cards automatically move between columns.
Automatic layouts are powerful, but some design changes require explicit breakpoints.
For example, a navigation menu might need to switch from horizontal to vertical:
.navigation {
display: flex;
gap: 1rem;
}
@media (max-width: 768px) {
.navigation {
flex-direction: column;
}
}
Media queries should generally represent layout requirements, not specific devices.
Instead of thinking:
"I need a breakpoint for tablets."
Think:
"At this width, the current layout stops working."
This approach produces more resilient responsive designs.
clamp() for Fluid TypographyResponsive typography does not always require multiple media queries.
CSS clamp() allows you to define a minimum, preferred, and maximum value:
.title {
font-size: clamp(2rem, 5vw, 4rem);
}
The browser automatically calculates a value between the defined limits.
This can produce smoother scaling across screen sizes.
The same technique can be useful for:
For example:
.section {
padding: clamp(2rem, 5vw, 6rem);
}
Large applications often become difficult to maintain when every component uses arbitrary spacing values.
Instead of having dozens of unrelated values:
margin: 13px;
margin: 19px;
margin: 27px;
margin: 31px;
define a small spacing system:
:root {
--space-1: 0.25rem;
--space-2: 0.5rem;
--space-3: 0.75rem;
--space-4: 1rem;
--space-6: 1.5rem;
--space-8: 2rem;
}
Components can then use these variables consistently:
.card {
padding: var(--space-6);
gap: var(--space-4);
}
This makes the design easier to change globally.
Not every layout should expand indefinitely on large screens.
Long lines of text can become difficult to read when containers become extremely wide.
A common approach is to constrain the main content:
.container {
width: min(100% - 2rem, 1200px);
margin-inline: auto;
}
This provides horizontal padding on smaller screens while limiting the maximum width on larger screens.
For text-heavy content, an even narrower reading width can be useful:
.article {
max-width: 70ch;
margin-inline: auto;
}
The ch unit is particularly useful when controlling the approximate number of characters per line.
Flexbox and Grid are not competing technologies.
They solve different problems and can be combined within the same application.
For example, Grid can define the overall page structure:
.page {
display: grid;
grid-template-columns: 240px 1fr;
}
While Flexbox can control the contents of individual components:
.header {
display: flex;
align-items: center;
justify-content: space-between;
}
A useful rule of thumb is:
Responsive design is not simply about making a desktop interface fit on a phone.
Content should remain usable regardless of viewport size.
Test your interface with:
A layout that works only with the exact content used during development is fragile.
Good responsive design anticipates variation.
As an application grows, CSS complexity can become a significant maintenance problem.
Prefer simple selectors and avoid deeply nested rules:
.page .content .sidebar ul li a span {
/* difficult to maintain */
}
A simpler component-oriented approach is easier to understand:
.sidebar-link {
display: flex;
align-items: center;
gap: 0.5rem;
}
The goal is to make it clear which component owns a particular style.
Modern CSS provides enough capabilities to build sophisticated responsive interfaces without relying on excessive JavaScript or complicated positioning techniques.
Use Flexbox when the problem is primarily one-dimensional. Use Grid when rows and columns matter. Combine them when appropriate, and let the browser handle as much of the responsive behavior as possible.
More importantly, design layouts around content and constraints rather than specific devices.
A well-designed CSS architecture should make the interface adapt naturally as screen sizes, content, and requirements change.
You are in reading mode. Open the discussions tab to explore threads about this article.