Original text: ishadeed.com/article/con… Author: Ahmad Shadeed
Web design work involves dealing with designs of different screen sizes, based on which the developer monitors viewport width or height using CSS media queries, and then changes the design based on that. This is how we’ve designed web layouts for the last 10 years, and it’s about to get better, and I have some good news for you.
CSS container queries, long a dream for web developers, are coming to CSS, now as an experimental feature for Chrome Canary. In this article, I’ll detail what it is, how it will change a designer’s workflow, and more. I don’t care if you’re a designer who knows how to code, because the point of this article is to introduce this concept in preparation for the next article. If you come across CSS bits (concepts) that you don’t understand at all, you can just skip them and continue learning.
Without further ado, let’s begin!
The state of responsive design
Now, it is still possible to design on multiple versions of the same web layout to show how the interior will change depending on the viewport width, and we designed it in different sizes, such as phones, tablets, and desktops.
In the image above, the designer created three different representations of the same design style, so developers know how to develop accordingly, and so far, so good.
Now, I’ll show you a more detailed design and its variations, so I can illustrate the problems that CSS container queries will solve for us.
Notice that this is the same component with three styles, default, Card and Featured, and as a designer, you’ve used multiple versions of the layout to show it, which is like saying, “This is how the article component looks on the phone, and this is how it looks on the tablet.”
In CSS, developers need to create three styles for the component, and each style is unique. Refer to the following basic styles:
.c-media {
/* Default style */
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
@media (min-with: 400px) {
.c-media--card {
display: block;
}
.c-media--card img {
margin-bottom: 1rem; }}@media (min-with: 1300px) {
.c-media--featured {
position: relative;
/* Other styles */
}
.c-media--featured .c-media__content {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%; }}Copy the code
The above style differences depend on the media query or viewport width, meaning we cannot control them based on their parent container width. Now you might be thinking, what’s wrong with that? Well, that’s a good question.
The problem is that developers are limited to using a particular style class of a component only when the viewport width is greater than a particular value. For example, if I wanted to use a “featured” class on a tablet, it wouldn’t work. Why? Because its media query starts when the viewport width is greater than or equal to 1300px.
Not only that, but we can also have less content than expected. Sometimes, the author will only add one article to a design that contains three, in which case either we have a blank area or the article will be expanded to fill the available space, as shown below:
In the first case, the article is too wide causing the image being used to be destroyed (stretched), while in the second case, the effect is the same, but there are more grid items that are expanding to fill the available space, which is not very good.
With container queries, we can solve these problems by querying the parent container to determine how to display specific components. Take a look at the following figure, which shows how we can use container queries to solve this problem.
So what happens if we shift the solution to the component’s parent container? In other words, what if we query its parent to determine the appearance of the component based on its width or height? Let’s take a look at the concept of container queries.
What is a container query
First, let me define a container, an element that contains other child elements, sometimes called a wrapper. If you’re interested in learning more about containers, I have a full article.
Container queries are now enabled in the Chrome Canary browser under Flag. Thanks to Miriam Suzanne and others.
When a component is placed in a container, it is contained in that container, which means that we can query the width of its parent container and modify it based on that. See the picture below:
Notice that each card has a yellow outline that represents the parent container of each component. With CSS container queries, we can modify components based on the width of their parent components. To illustrate this more clearly, here is the HTML code for the above:
<div class="o-grid">
<div class="o-grid__item">
<article class="c-media"></article>
</div>
<! -- + more items -->
</div>
Copy the code
The child component has the.c-media class and its parent container is the.o-grid__item element. In CSS, we can do this:
.o-grid__item {
contain: layout inline-size style;
}
.c-media {
/* Default style */
}
@container (min-width: 320px) {
.c-media {
/ * * /}}@container (min-width: 450px) {
.c-media {
/ * * /}}Copy the code
First, we tell the browser that every element with the.o-Grid__item class is a container. Next, we tell the browser that if the parent element is 320px or larger in width, it should render a different layout, even for 450px queries. This is how CSS container queries work.
In addition, we can define them anywhere, which means we can query them on the top-level container if we need to. Now that you understand the basic concepts of CSS container queries, I want to show you the following image.
On the left, this is a viewport that is resizing, and on the right, a component (layout) changes according to the width of its parent component, which is where container queries are powerful and useful.
If you want to learn more about the CSS details of container queries, I’ve written a detailed article about it.
Design with container queries in mind
As a designer, you need to get used to this revolutionary CSS feature because it will improve the way we design web pages and write CSS. We design not only for screen size, but also for how components should fit when their container widths change.
As design systems become more popular, design teams build a set of rules and components on which other members can build pages, and with the advent of CSS container queries, we also need to consider how components should fit with their parent container widths when designing them.
Consider the following design:
Note that we have a title bar, article section, introduction, and newsletter, each of which should fit the viewport or parent container width.
I can envision the components being divided into the following parts:
- Viewport (Media Enquiries)
- Parent container (Container query)
- Generic: Unaffected components, such as buttons, labels, paragraphs.
For the sample user interface, we can divide the components like this.
When we design the user interface in this way of thinking, we can start to consider the different variations of components, depending on the width of their parent container, which we’ll explore.
In the figure below, notice how each change in the article component works in a particular width.
As a designer, thinking about how to design based on the width of the parent container may seem a bit strange at first, but that’s the way it’s going to go. We provide the details and variations of each component to the forward developers, who can code with them.
Not only that, we might have a component layout that is only displayed in a specific context, such as an event list page, in which case it is important to be clear where to use this layout.
The question is, how do you tell designers where to use these components?
Communicate with developers
Good communication is an important factor in the success of a project, and as a designer, you are expected to provide guidance on where different adaptations of components should be used. This can be a complete page design or a simple picture showing how each component is used.
Let’s apply this to the article component we discussed earlier.
Notice how I map each change to a specific context, not the viewport. To further prove the point, I want to show you how this component looks when used with a CSS Grid.
In a CSS Grid layout, we can use the auto-fit keyword to tell the browser that we want it to extend if the number of columns is less than expected (you can read more about it here). This feature is powerful because it allows us to display different changes in the same environment. See the picture below:
It’s very useful to have a component that ADAPTS to the width of its parent container, as you just saw when we look at a page at desktop size and have different sections, each with a different number of columns.
Avoid complications when designing responsive components
It’s important to remember that the internal composition of a component is like a Lego game. You can sort them based on current changes, but there’s a limit to everything, and sometimes it’s better for front-end developers to implement a whole new component than to implement adaptation with container queries.
Consider the following points.
It has the following points:
- Head portrait
- The name of the
- button
- Key/value pairs
If the internal structure remains the same, or at least does not contain the new structure, we can modify the component and have the following different layouts.
Use cases of CSS container query
Let’s explore some examples that can be implemented using CSS container queries.
Chat list
I’ve seen this pattern in Facebook Messenger, where chat lists vary according to viewport width, and we can do this using CSS container queries.
When there is enough space, the list expands to show each user’s name, and the parent element of the chat list can be an element that is dynamically resized (for example, by using CSS viewport units, or CSS comparisons).
Here’s how we do this in CSS.
<div class="content">
<aside>
<ul>
<li>
<img src="shadeed.jpg" alt="Ahmad Shadeed" />
<span class="name">Ahmad Shadeed</span>
</li>
</ul>
</aside>
<main>
<h2>Main content</h2>
</main>
</div>.content { display: grid; The grid - the template - the columns: 0.4 fr 1 fr; } aside { contain: layout inline-size style; } @container (min-width: 180px) { .name { display: block; }}Copy the code
Note that the sidebar is 0.4f wide, so it’s a dynamic width. I also added the contain property, and if the container is larger than 180px, it will display the user name.
Another example of this is the side navigation bar, where we can switch the position of the navigation item label from a new line or next to the icon.
Notice how the navigation item label switches to a new row when the container (sidebar) is small, and next to the navigation icon when there is enough space.
demo
The accordion
Accordion mode can be used for scenarios like FAQs. In some cases, we may need to add a list of FAQs in a sidebar or a small area in the user interface. Container queries can help!
Here’s how we can do this using CSS container queries.
@container (min-width: 180px) {
.faq-title {
display: flex;
justify-content: space-between;
font-size: 1.25 rem;
}
.faq__icon {
width: 60px;
height: 60px;
background-color: #4f96e7; }}Copy the code
demo
The search box
This can be useful when we use the generic search box in multiple places, for example, in a main graph (on the right) or in a smaller scope, such as the sidebar (on the left).
Activity list
I personally like the use case for container queries, where we can use the same component in multiple situations. In the figure above, we have simple, medium, and large layouts shown. Here is an example of how to use them.
Again, this is the same component that fits the width of its parent container, isn’t that great? For me, yes.
Author’s brief introduction
Author profiles are a common part of blogging, and as you can see from the above, it can be used in a variety of situations, so it should be adaptive.
Social sharing
Most of the time WHEN I implement a social sharing component, I need to create a version (for example, a sidebar) that can be used when the viewport is large but the parent container width is small, which can be easily solved by adapting the parent container width through container queries.
The small version is used when the component is used in the sidebar (on the left), and the full version is used when the parent container is large (for example, the main area).
Thanks for reading 🙂