Skip to content

Commit 7dffda4

Browse files
Merge pull request #229 from brechtDR/article/container-query-length-units
[Article] Container Query Length Units
2 parents d51c11e + b6d9d2d commit 7dffda4

File tree

5 files changed

+389
-0
lines changed

5 files changed

+389
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,388 @@
1+
---
2+
title: 'Going beyond pixels and (r)ems in CSS - Container query length units'
3+
date: '2024-02-28'
4+
tags: ['frontend', 'css']
5+
images: ['/articles/going-beyond-pixels-and-rems-in-css/visual-pixel-containers.jpg']
6+
summary: 'In the third part of this series, we’ll look at length units based on the container. Yes, you heard that right, we can finally get some measurements based on a containing element and that just spells awesome in my book. Currently available in all evergreen browsers, these units open up a lot of opportunities to create some smart systems and once again, I will write this up packed with a bunch of demos and cool use cases.'
7+
authors: ['brecht-de-ruyte']
8+
theme: 'beige'
9+
serie: 'going-beyond-pixels-and-rems-in-css'
10+
---
11+
12+
As part of the containment spec, container queries are something to be reckoned with and in my personal opinion, they still aren’t used enough, but that’s a whole other discussion. What we’ll be covering today are the units that came with this awesome spec and once again, this article will be based on the [list at MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/length). First, we’ll get through the basics with a listing of the units, followed up with some more advanced usage.
13+
14+
## Prerequisites for using container query length units
15+
16+
Before we get started we will need to define a `container-type` for the container we’ll target. For our first example, let’s add a bit of HTML:
17+
18+
```html
19+
<div class="container">
20+
<div class="item">A cool container item</div>
21+
</div>
22+
```
23+
24+
Next up, let’s write a bit of CSS to define a `container-type` on our container and give it a `max-width`:
25+
26+
```css
27+
.container {
28+
container-type: inline-size;
29+
max-width: 800px;
30+
}
31+
```
32+
33+
This is the part that matters, but let’s add some presentational styling as well, to visualize what is going on:
34+
35+
```css
36+
.container {
37+
container-type: inline-size;
38+
max-width: 800px;
39+
width: 100%;
40+
text-align: center;
41+
border: 2px dotted #695958;
42+
}
43+
44+
.item {
45+
background: #271f30;
46+
color: white;
47+
}
48+
```
49+
50+
Ok, we’ve set our `container-type` and added some basic styling, It’s time to dig in and get started with those units:
51+
52+
## cqw
53+
54+
The `cwq` unit stands for **1% of the containing element's width**. It allows you to define element sizes and spacing relative to the width of their container in contrast to the `vw` unit, which defines the spacing relative to the viewport. But just as viewport and font units, it can be used in any property that accepts `<length>` values, such as `font-size`, `width`, `padding`, `margin`, etc. The latter counts for every unit we will tackle in this article.
55+
56+
Now, a demo says more than a thousand words, so let’s put it to the test. Let’s add a margin to our previous code for the `.item` inside of the container:
57+
58+
```css
59+
.item {
60+
/*previous code */
61+
margin: 5cqw;
62+
}
63+
```
64+
65+
Now the item will have a margin based on its container. This is what you should have now, resize the container to see this in full effect:
66+
67+
<iframe
68+
height="300"
69+
scrolling="no"
70+
class="simple-embed"
71+
title="Basic container unit example"
72+
src="https://codepen.io/utilitybend/embed/preview/jOJjbez?default-tab=result&theme-id=dark"
73+
frameborder="no"
74+
loading="lazy"
75+
allowtransparency="true"
76+
allowfullscreen="true"
77+
>
78+
See the Pen <a href="https://codepen.io/utilitybend/pen/jOJjbez">Basic container unit example</a>
79+
&nbsp; by utilitybend (<a href="https://codepen.io/utilitybend">@utilitybend</a>) on{' '}
80+
<a href="https://codepen.io">CodePen</a>.
81+
</iframe>
82+
83+
Now let’s make the effect stick out a bit more by making some other properties rely on the `cqw` unit.
84+
85+
```css
86+
.item {
87+
margin: 6cqw;
88+
padding: 1cqw;
89+
font-size: 5cqw;
90+
}
91+
```
92+
93+
Now we can see the effect on roids. If you add a few extra containers with different max-widths, it becomes a great little demo. Just resize the following and see the potential:
94+
95+
<iframe
96+
height="300"
97+
scrolling="no"
98+
class="simple-embed"
99+
title="Margins, padding and font-size with container units"
100+
src="https://codepen.io/utilitybend/embed/preview/dyrBYMB?default-tab=result&theme-id=dark"
101+
frameborder="no"
102+
loading="lazy"
103+
allowtransparency="true"
104+
allowfullscreen="true"
105+
>
106+
See the Pen{' '}
107+
<a href="https://codepen.io/utilitybend/pen/dyrBYMB">
108+
Margins, padding and font-size with container units
109+
</a>
110+
&nbsp; by utilitybend (<a href="https://codepen.io/utilitybend">@utilitybend</a>) on{' '}
111+
<a href="https://codepen.io">CodePen</a>.
112+
</iframe>
113+
114+
**Note: What happens if we don’t define a `container-type` on any of the parents?**
115+
116+
In that case, the container query unit will fall back to the viewport unit equivalent, in this case: `vw`.
117+
118+
## cqh
119+
120+
The `cqh` unit stands for (yes, you guessed it) **1% of the containing element's height**. It allows you to define element sizes and spacing relative to the height of their container
121+
We pretty much know what’s going on here by now, so let’s get to it. One thing we could do is create a quick test out of that previous demo and change our `.item` CSS to use the `cqh` unit:
122+
123+
```css
124+
.item {
125+
margin: 10cqh;
126+
padding: 10cqh;
127+
height: 80cqh;
128+
font-size: 12cqh;
129+
}
130+
```
131+
132+
Now this didn’t do that much, we’ll need to change our `container-type` as well to use the block axis as well, so for now, change it like this:
133+
134+
```css
135+
.container {
136+
container-type: size;
137+
}
138+
```
139+
140+
And instead of our width, we’ll change the containers to have different heights:
141+
142+
```css
143+
.container {
144+
height: 100px;
145+
}
146+
147+
.container-2 {
148+
height: 200px;
149+
}
150+
151+
.container-3 {
152+
height: 100px;
153+
}
154+
```
155+
156+
Now you can notice that the height of the container is taken into account.
157+
158+
<iframe
159+
height="300"
160+
class="simple-embed"
161+
scrolling="no"
162+
title="Untitled"
163+
src="https://codepen.io/utilitybend/embed/preview/wvOLMjY?default-tab=result&theme-id=dark"
164+
frameborder="no"
165+
loading="lazy"
166+
allowtransparency="true"
167+
allowfullscreen="true"
168+
>
169+
See the Pen <a href="https://codepen.io/utilitybend/pen/wvOLMjY">Untitled</a> by utilitybend (
170+
<a href="https://codepen.io/utilitybend">@utilitybend</a>) on{' '}
171+
<a href="https://codepen.io">CodePen</a>.
172+
</iframe>
173+
174+
We could do some practical examples, but I’d rather show them after the next part because the next two units are probably the most important ones.
175+
176+
## Going logical: use cqi and cqb
177+
178+
I believe that it’s always a good reflex to use logical variants by default. I use these a lot, but mostly for RTL writing modes, which doesn’t apply to this difference, but you never know what the future brings, so it’s good to make this a habit.
179+
180+
- The `cqi` unit stands for **1% of the containing element’s inline axis**, for western languages this is horizontal as our reading direction is from left to right.
181+
- The `cqb` unit stands for **1% of the containing element’s block axis**, for western languages this is vertical, but for example Mongolian, this is horizontal as their reading direction is from top to bottom.
182+
183+
Let’s create a practical example of the `cqi` unit by having a banner move from the main content to the sidebar and adjust sizes based on that.
184+
185+
The idea is the following, we create a 2-column grid where the children both have a container-type.
186+
187+
```html
188+
<div class="grid">
189+
<main></main>
190+
<aside></aside>
191+
</div>
192+
```
193+
194+
```css
195+
.grid {
196+
display: grid;
197+
grid-template-columns: 2fr 1fr;
198+
> * {
199+
container-type: inline-size;
200+
}
201+
}
202+
```
203+
204+
Next up, let’s create a little banner and put this in our main content
205+
206+
```html
207+
<div class="grid">
208+
<main>
209+
<div class="banner">
210+
<h2>This is an awesome banner</h2>
211+
<p>
212+
Depending on the container, this will adjust its font-size and paddings to fit perfectly
213+
</p>
214+
</div>
215+
</main>
216+
<aside></aside>
217+
</div>
218+
```
219+
220+
Let’s style our banner by using some container cqi units, as we want to work with the inline axis:
221+
222+
```css
223+
.banner {
224+
padding: 3cqi;
225+
background: #55673e;
226+
font-size: 3cqi;
227+
border-radius: 0.5rem;
228+
}
229+
230+
.banner h2 {
231+
font-size: 4cqi;
232+
margin: 0 0 1cqi;
233+
}
234+
```
235+
236+
With this basic setup, let's move (or duplicate) that banner to the sidebar. By using these smart units and some basic styling, we get the following:
237+
238+
![The banner in the sidebar now has a smaller font size and adjusts almost perfectly](/articles/going-beyond-pixels-and-rems-in-css/duplicated-banner.png)
239+
240+
This is the CodePen of that example with some extras:
241+
242+
<iframe
243+
height="300"
244+
scrolling="no"
245+
class="simple-embed"
246+
title="Multiple banners with container units"
247+
src="https://codepen.io/utilitybend/embed/preview/vYPqKoy?default-tab=result&theme-id=dark"
248+
frameborder="no"
249+
loading="lazy"
250+
allowtransparency="true"
251+
allowfullscreen="true"
252+
>
253+
See the Pen{' '}
254+
<a href="https://codepen.io/utilitybend/pen/vYPqKoy">Multiple banners with container units</a> by
255+
utilitybend (<a href="https://codepen.io/utilitybend">@utilitybend</a>) on{' '}
256+
<a href="https://codepen.io">CodePen</a>.
257+
</iframe>
258+
259+
Now, while all of this looks fine and dandy when it comes to paddings, our `font-size` does get a bit too low in the sidebar. We can adjust this by setting a minimum and maximum `font-size`. Yes, we’ll be adding some **fluid typography with container query units.** Let’s take our previous `font-size` values for the banner and update them by using the `clamp()` function:
260+
261+
```css
262+
.banner {
263+
font-size: clamp(1rem, 2cqi + 0.5rem, 1.5rem);
264+
}
265+
266+
.banner h2 {
267+
font-size: clamp(1.3rem, 3cqi + 0.5rem, 2.4rem);
268+
}
269+
```
270+
271+
For the banner, in general, we will take a `1rem` minimum font size and a maximum of `1.5rem`. This will make our general look and feel a lot better. Here is the updated CodePen for that:
272+
273+
<iframe
274+
height="300"
275+
class="simple-embed"
276+
scrolling="no"
277+
title="Banner with container units and clamp() function for font-sizes"
278+
src="https://codepen.io/utilitybend/embed/preview/xxBoRbr?default-tab=result&theme-id=dark"
279+
frameborder="no"
280+
loading="lazy"
281+
allowtransparency="true"
282+
allowfullscreen="true"
283+
>
284+
See the Pen{' '}
285+
<a href="https://codepen.io/utilitybend/pen/xxBoRbr">
286+
Banner with container units and clamp() function for font-sizes
287+
</a>
288+
&nbsp; by utilitybend (<a href="https://codepen.io/utilitybend">@utilitybend</a>) on{' '}
289+
<a href="https://codepen.io">CodePen</a>.
290+
</iframe>
291+
292+
We could, of course, apply this to margins and paddings as well. Resize the window to see how this behaves.
293+
294+
If you’re feeling brave, at the bottom of that demo, you can find a `writing-mode` property in a comment. Notice that, you still get that great layout in a “top to bottom and right to left” writing mode when enabling this. [It’s all about being logical](https://www.youtube.com/watch?v=pP8iUyb9Gn8). the stuff that CSS does is a miracle, beautiful and magical.
295+
296+
![The same banner is spaced the same in a top to bottom and right to left writing mode](/articles/going-beyond-pixels-and-rems-in-css/tb-rl-containers.png)
297+
298+
### cqb and declared height
299+
300+
When using container query units for the block size, there is a little gotcha. In that case, the container needs to have a declared height otherwise, it gets an overflow. This is unfortunately one of the limitations of the containment spec. But that doesn’t mean we can’t have some fun with it.
301+
302+
In the following example, we’ll create a little banner and set the font size based on the block height:
303+
304+
The following will be our HTML:
305+
306+
```html
307+
<section class="intro">
308+
<h1>Be<br />Query</h1>
309+
<img src="..." alt="" />
310+
</section>
311+
```
312+
313+
We want to have a nice little intro that is about `80%` of the viewport height, but we might want to change that later on for different pages. To make it versatile, we could do something like this:
314+
315+
```css
316+
.intro {
317+
display: flex;
318+
justify-content: space-between;
319+
container-type: size;
320+
background: rebeccapurple;
321+
block-size: 80dvb;
322+
}
323+
324+
h1 {
325+
font-family: 'Oswald', sans-serif;
326+
font-size: clamp(1rem, 20cqb + 0.5rem, 10rem);
327+
padding: 2cqi;
328+
line-height: 1.2;
329+
}
330+
```
331+
332+
Notice how we used the `cqb` in the `clamp()` function. Here is a little extended demo of this in action:
333+
334+
<iframe
335+
height="300"
336+
className="simple-embed"
337+
scrolling="no"
338+
title="cqb container unit example"
339+
src="https://codepen.io/utilitybend/embed/preview/JjzQbOp?default-tab=result&theme-id=dark"
340+
frameborder="no"
341+
loading="lazy"
342+
allowtransparency="true"
343+
allowfullscreen="true"
344+
>
345+
See the Pen <a href="https://codepen.io/utilitybend/pen/JjzQbOp">cqb container unit example</a> by
346+
utilitybend (<a href="https://codepen.io/utilitybend">@utilitybend</a>) on{' '}
347+
<a href="https://codepen.io">CodePen</a>.
348+
</iframe>
349+
350+
## cqmin and cqmax
351+
352+
In CSS, `cqmin` and `cqmax` are container query length units that offer dynamic sizing based on both the `width` and `height` of their containing element. These units let us define styles that adapt to different aspect ratios and container shapes.
353+
354+
- `cqmin`: Represents the **smaller** value of either cqi (1% of inline size) or cqb (1% of block size).
355+
- `cqmax`: Represents the **larger** value of either cqi or cqb.
356+
357+
This can be particularly handy if our container changes shape depending on the viewport. Let’s redo the banner example, but instead of using `cqi` for the padding, let’s use `cqmax`, taking the biggest value between block and inline size into account:
358+
359+
```css
360+
.banner {
361+
padding: 3cqmax;
362+
background: #55673e;
363+
font-size: clamp(1rem, 2cqi + 0.5rem, 1.5rem);
364+
border-radius: 0.5rem;
365+
}
366+
```
367+
368+
<iframe
369+
height="300"
370+
class="simple-embed"
371+
scrolling="no"
372+
title="Using cqmax for paddings - resize for effect"
373+
src="https://codepen.io/utilitybend/embed/preview/YzgoNgq?default-tab=result&theme-id=dark"
374+
frameborder="no"
375+
loading="lazy"
376+
allowtransparency="true"
377+
allowfullscreen="true"
378+
>
379+
See the Pen <a href="https://codepen.io/utilitybend/pen/YzgoNgq">Untitled</a> by utilitybend (
380+
<a href="https://codepen.io/utilitybend">@utilitybend</a>) on{' '}
381+
<a href="https://codepen.io">CodePen</a>.
382+
</iframe>
383+
384+
Now resize the window in as many ways as possible, changing aspect-ratios completely to notice the full effect. (Open the pen in a new window to make that easier).
385+
386+
## So that’s it for part 3.
387+
388+
One of the things that everybody should get a bit more familiar with during 2024 is probably container queries and the units that come with it. If you write CSS on a day-to-day basis, it’s something that you just need to have in your toolset for the future. We have this awesome new tool to create these kinds of micro-design systems that make our components work no matter the size of their containing element. Truth be told, I am still working on mastering all these new units, but the more I play around with them, the more I believe that having a strong foundation in them can make the difference between a CSS newbie and a CSS Ninja. For the last part, we will kinda end with a downer on absolute units, but just as in video games, I’m a bit of a completionist, so we just can’t ignore them. Happy unit-querying!

data/talks/the-future-of-ui-is-open.md

+1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ title: The future of UI is "open"
33
summary: When dealing with more advanced UI elements there are a lot of things that go wrong. They impact performance, accessibility and have the tendency to create frustrations along the way. In this talk, I will be introducing you to the W3C community around Open UI, while also taking a little detour with the Anchoring API. By combining these future specs we'll take a peek at the future of styling custom UI by only using HTML and CSS, giving you less frustration, performance boosts and basic accessibility out of the box.
44
tags: ['frontend', 'CSS', 'HTML', 'a11y', 'accessibility']
55
authors: ['brecht-de-ruyte']
6+
video: 'https://www.youtube.com/watch?v=fTifeplmyi8'
67
---
Loading
Loading
Loading

0 commit comments

Comments
 (0)