 Hi, welcome back to Designing in the Browser, the series where we explore user interface design through the lens of modern web technology. It's been a really exciting year for CSS and front-end development, and there are a slew of new APIs on the horizon, bringing new web capabilities designers and developers could only dream of in the past. So in this season of Designing in the Browser, we're going to be exploring the APIs that let us create even more responsive designs and enter into the realm of intrinsic and user-focused design to build for the new responsive web of tomorrow. I'll cover how to use container queries, enabling different levels of UI control from macro to micro layouts, building beautiful dark themes and performant images in art direction, how to make the most of your responsive art board. And to kick it all off, today we're diving into container queries, an experimental API that enables so many of the topics we'll get into this season. Container queries are a capability that completely shifts how we think about responsive design today. Oh no. Did I say shift? Are we losing inline size of this frame? Wait, Sean, can we make sure the dino is still in the frame? That's important. Can we read just a layer of the frame? Thank you. Let's dive in. So what is a container query anyway? You can think of a container query like a media query, like at media, but instead of relying only on the viewport and global meta information to adjust styles, you can use the parent container of an element you're targeting to adjust its styles. This means that a card, like a plant shop card, can be placed into any part of the interface and readjust itself to the most optimal layout. You can use container queries as an entry point style anything, from backgrounds to borders, but in these examples, we're mostly shifting the layout. If this card was in a more narrow area, like a sidebar, it could get a vertical layout. If it's in a wider area, it can get a horizontal layout. If it's in a hero, it might get a completely different layout, and this would all shift based on the responsive page layout of the general UI. So let's take a look at what this might look like. So here I have a card, and here is the container set, and this is the card within the container, and as I readjust the space that this container has, the card inside of it shifts from smaller sizes, it could be this vertical layout to a more horizontal layout. I am using a container query here to give it a different layout at this min with sides. We'll get into that in a minute. The cool thing about container queries is that the component itself owns all of its own responsive information. This means that container queries play really well in with component-based architectures and environments. Colocating styles with component logic just makes a little bit more sense when you actually have component-level responsive styles. You don't need an additional higher-level file to manage that component's responsive styles or futz around trying to make it work elsewhere. Container queries let you divorce the idea that your page layout needs to perfectly tie into your component layout and designs. Now we can mentally break apart page layouts or macro layouts from component layouts or micro layouts, making interfaces much more flexible. If we take this card and we put it into a responsive grid like this, we can see that we have the exact same component, but it appears differently based on its individual available space. These are just cards within a responsive grid here with these grid template columns that are 30%, one fractional unit 20%, and the same component card that we just saw looking entirely different based on its individual available space. Creating flexibility like this simply isn't possible today without a ton of scripting. While we can use resize observer, the effects of doing so are heavy and can cause some weird layout shift jank. That being said, there is a polyfill that takes advantage of resize observer and unlocks container queries for use cross-browser today, and that is a huge win for intrinsic design. But ultimately, we're hoping to see container queries land natively in all browsers sometime in the near future. Additionally, relying on the global viewport just isn't as accurate in many cases because it's a much more blunt tool that doesn't give us component level flexibility. In this demo here, I'm using all of the exact same components all throughout the page in this product area, in the sidebar, in this hero area. It's the exact same component that uses the same logic, but it's restyling itself to fit best within the UI where it lives. The global viewport doesn't know where this card lives, and it would style them all identically if we only had that global entry point. That's why it makes a lot of sense to use container queries for component-owned microlayouts and apply media queries for more global page-based layouts. But we'll go into that a bit more in the next episode. For now, let's explore how container queries work and how we can use them. Container queries are enabled by CSS Containments. And the first step in getting container queries to work is setting containment on the parent element. CSS Containment provides predictable isolation of a DOM subtree from the rest of the page. In turn, this gives us a lot of rendering performance improvements and enables the browser's ability to isolate queries for container queries. It enables that in the first place. With Containment, a developer can tell the browser what parts of the page are encapsulated as a set of content, allowing the browser to reason about the content without needing to consider the state outside of that subtree. Knowing which bits of content or subtrees contain isolated content means the browser can make optimization decisions for page rendering. There are four types of CSS Containment, size, layout, style, and paint. You can use any of these properties individually or combined in a space-separated list of values. And to create a container query, you'll need to set style, layout, and size containment all at the same time. If we're only querying the width value for container queries and we want to set the block size so the element takes up space in the page without necessarily setting containment on that, we can set the containment to only be in the inline direction for size or inline size. But to make containment and setting container queries even easier, there is a proposed new CSS Container Type property with arguments that combine containment properties. And since we're only looking at the inline direction for the width of a parent container in these examples, all we need to set is container inline size on the parent and it will also get style and layout containment applied. If we want to query both the width and height, with being the inline and height being the block directions, you can set container size instead and it will query both, as well as providing that style and layout containment. Container type can be written in an even shorter form with the container shorthand. This shorthand also lets you add a container name, which is its own property as well. Container name is optional but can be very useful when referencing multi-level container queries and we'll get into that in a further demo. So now that we have a container, let's query it to set some styles on its children. You can do this with the app container media feature. Say we want a product card to show the product's meta information beneath the image until it has hit a specific size like 250 pixels and at that point we want to apply a horizontal grid layout to let it better fit the allotted space. This product card will go from a single column to two columns at the 250px or larger breakpoint. And keep in mind this is an intrinsic layout. It's not relying on the page size, it's relying on the card container size. Here's what that would look like. We have this card here and the product card container has containment set on it. We have container inline size sets on it. The product card is what we are going to be applying container styles to. So we even are already doing that with border styles and with text alignments. As I increase the available size for this container, the border is getting thicker, it's starting to readjust its styles. And then here we have hit 400 pixel mark and here at minimum with 400 pixels, which the product container is now 428. You can see this in DevTools if you hover over this class name where it's now also showing you that it's inline size. That is the containment that we're working with here. That's the containment set in the parents. At 428 pixels or anything above 400 pixels, we're going to set the display to grid and give it a grid template and readjust some styles that way. So this is going to be continuing to have this grid layout until I want this to be in a smaller position. And you can see how this works particularly well in a responsive grid. So as I scroll down, I have this demo with a grid and here is the grid. Here are the containers within that grid. If I increase the size and let this reshape itself, these will automatically resize and take up the available space to optimally fit the space available. Another way to look at it is from, you know, wide to small. Here I have a podcast episode clip. I want to show more detail when there is more wide space available. So as I resize this, this detail can appear or it can disappear. So here I have some text information. I have links, metadata for this card, but at these smaller sizes, I'm only showing the most important detailed information. So that's going to be a call to action to download the episode, the name of the episode, and then the length of it. And so we have the ability to control what details we show, what layouts we're showing. And again, you can change borders, backgrounds, really anything. Container queries are an entry point for styling. Now, did you notice that in the previous example with the baby clothes product card, the add to cart button was actually also responsive? Let me show you that again. It adjusted its own styles given its available space. So this is a micro layout. As I resize this, that available space is going to start decreasing here. And this add to cart button starts, instead of saying add to cart, it just says add. And it also has little plus sign that gets added if I have enough space to show that detail. But with less detail, this is going to readjust. And then here at the 100% width, it's going to get that full detail to plus the add to cart. And again, that's going to readjust based on how much space it has. So this is really interesting because I not only have a container with the card, but I have a container inside of the container. This product card has this cart button container within it. But another thing I want to do here is when this product card hits that 400 pixel mark, I want this to readjust and shift sizes. And I'm going to have to readjust the margins on the cart button container as well to do that. Here you see it's center aligned, but when it hits this point, I want it to be left aligned. So what I need to do here is set a named container. It's a bit like multitasking, trying to pat your head and rub your belly at the same time. And this is where those named containers come in handy. I don't know how long I have to do this. To get the button to do some container query multitasking, I gave the product card container a specific name of product card container. So this product card container property looks like this. Then I wrote a container query specific to the product card container and put the cart button inside of that. Now I have my regular container query to adjust styles in the button and a more specific named query. I set at container, product card container with a parameter like min with 400 pixels and adjusted the cart button margin styles within that. This enables the cart button to respond to both its intrinsic size and the product card without the product card being its direct parent, pretty cool. Another cool container query proposed feature is container query based unit values. Viewport relative units such as VH and VW are commonly used among UI design for sizing and spacing of elements. With the new container query spec, authors will want to use such units as container query width and height for container based sizing. These units are prefixed with CQ similar to how Viewport units are prefixed with V. You might notice the inline and block options here as well. These are logical property equivalents to width and height that enable more internationalization by default. If you wanna learn more about logical units and internationalization, there is a great module on the topic at web.dev slash learn slash CSS under logical properties. So when you wanna put it all together with containment and container queries, you can reuse the same components with its own intrinsic logic and use it all over your page in different parts of your UI and different pages of your UI for a more customized look. So I wanna show this plant demo again. This is just one of my examples that I like to show where I do have the same component all across the UI but it has a completely different look and I'm keeping that internal intrinsic logic with the card component itself with that product card. One of my favorite examples of container queries in action comes from Ahmad Shadeed who has a great article on the subject. In this demo, he shows a newsletter signup created with container queries and the different layouts it can shape to when it has more or less horizontal space. So now you can reuse a component like this in a sidebar card or in an interstitial at a wide view and feel confident that your design looks as intended. This is what that might look like when the signup area is presenting differently in the sidebar and in the main content section even though it's the exact same components and you can see it at the exact same time. So cool. That's all for now for our overview of the experimental CSS feature known as container queries. Stay tuned for the next episode where we put them into work with macro and micro layouts and check out the video links for more resources. I'm Yuna signing off. I'll see you online.