In this blog post, I’d like to talk about CSS: I wish it supported inner breakpoints – breakpoints not for viewports or containers but for HTML elements inside viewports or containers.
Media queries were an important initial foundation for making web page layouts responsive: They could adapt dynamically to different viewport sizes (viewport means “part of the web page that is visible on screen”).
article {
/* Desktop mode */
flex-direction: row;
}
@media (width < 40rem) {
article {
/* Mobile mode */
flex-direction: column;
}
}
In desktop mode, we have more horizontal space and use “row” as a flex direction. In mobile mode, we go with “column”.
One important recent next step were container queries:
.parent {
container-name: parent;
container-type: inline-size;
}
article {
/* Desktop mode */
flex-direction: row;
}
@container parent (width < 40rem) {
article {
/* Mobile mode */
flex-direction: column;
}
}
Instead of reacting to viewport size changes, we can react to size changes of HTML elements. With media queries, the whole page was responsive. With container queries, individual user interface elements can be responsive, too.
CSS now lets us nest rules. That makes container queries (and media queries) even more convenient:
.parent {
container-name: parent;
container-type: inline-size;
}
article {
/* Desktop mode */
flex-direction: row;
@container parent (width < 40rem) {
/* Mobile mode */
flex-direction: column;
}
}
I love using grids for responsive layouts because they give you a lot of freedom when it comes to rearranging things. Consider the following example: A layout with content in .main-col
and a fixed .sidebar
.
Layout on wide screens:
+------------------------+-------+
| .main-col | .side |
| | bar |
+------------------------+-------+
Layout on narrow screens:
+-------------+
| .main-col |
| |
+-------------+
| .side |
| bar |
+-------------+
We can implement it as follows, via a container query with a breakpoint and a grid layout (see GitHub repository rauschma/sidebar-via-grid
):
HTML:
<body>
<div class="sidebar-layout">
<div class="main-col">
main-col
<ul>
<li>First</li>
<li>Second</li>
<li>Third</li>
</ul>
</div>
<div class="sidebar">
sidebar
</div>
</div>
</body>
CSS:
body {
container-name: sidebar-layout-container;
container-type: inline-size;
}
.sidebar-layout {
display: grid;
grid-template-columns: 1fr 15rem;
grid-template-rows: 1fr;
grid-template-areas: /*A*/
"main-col sidebar"
;
@container sidebar-layout-container (width < 40rem) {
grid-template-columns: 1fr;
grid-template-rows: auto;
grid-template-areas: /*B*/
"main-col"
"sidebar"
;
}
}
.main-col {
grid-area: main-col;
background: red;
}
.sidebar {
grid-area: sidebar;
background: green;
}
I love how easy it is two switch between a horizontal layout (line A) and a vertical layout (line B) – thanks to grid-template-areas
.
This approach has one significant downside: We are actually not interested in the whole width of the container, only in the width of .main.col
. Since, in this case, the sidebar is fixed, we could do some calculations but even that is not enough if we want the sidebar to change its size in response to the size of its content.
This is a solution based on “The Sidebar” layout by “Every Layout”. Check out the GitHub repository rauschma/sidebar-layout
to see it online.
body {
display: flex;
flex-wrap: wrap;
}
.sidebar {
width: 8rem; /*A*/
display: flex;
flex-direction: column;
}
.main-col {
flex-grow: 1; /*B*/
display: flex;
flex-direction: column;
}
In this case, we can specify precisely what we want:
.sidebar
should have a fixed width (line A)..main-col
should have its minimum size dictated by its content and take up any additional horizontal space if the width increases (line B).If there is not enough space to the right of the main column then the sidebar is wrapped and moves below it.
Both approaches have pros and cons:
What if we could use approach #1 but specify breakpoints for sizes of HTML elements inside the container? I would find that most intuitive. I personally never disliked breakpoints, only the fact that they were not the breakpoints I pictured in my mind.
My knowledge of CSS is limited so I don’t know if my idea makes sense and if it could even be implemented.
Feedback welcome: You can reach me via Mastodon, Bluesky and Disqus (add a comment below)
Material on container queries: