Tag: Container

A Few Times Container Size Queries Would Have Helped Me Out

CSS Container Queries are still gaining traction and many of us are getting our hands wet with them, even if it’s for little experiments or whatnot. They’ve got great, but not quite full, browser support — enough to justify using them in some projects, but maybe not to the extent where we might be tempted to start replacing media queries from past projects with shiny new container size queries.

They sure are handy though! In fact, I’ve already run into a few situations where I really wanted to reach for them but just couldn’t overcome the support requirements. If I had been able to use them, this is how it would have looked in those situations.

All of the following demos will be best viewed in Chrome or Safari at the time of this writing. Firefox plans to ship support in Version 109.

Case 1: Card grid

You kind of had to expect this one, right? It’s such a common pattern that all of us seem to run into it at some point. But the fact is that container size queries would have been a huge time-saver for me with a better outcome had I been able to use them over standard media queries.

Let’s say you’ve been tasked with building this card grid with the requirement that each card needs to keep it’s 1:1 aspect ratio:

A four-by-three grid of card elements as a grayscale mockup.

It’s tougher than it looks! The problem is that sizing a component’s contents on the viewport’s width leaves you at the mercy of how the component responds to the viewport — as well the way any other ancestor containers respond to it. If, for example, you want the font size of a card heading to reduce when the card hits a certain inline size there’s no reliable way to do it.

You could set the font size in vw units, I suppose, but the component is still tied to the browser’s viewport width. And that can cause problems when the card grid is used other in contexts that may not have the same breakpoints.

In my real-world project, I landed on a JavaScript approach that would:

  1. Listen for a resize event.
  2. Calculate the width of each card.
  3. Add an inline font size to each card based on its width.
  4. Style everything inside using em units.

Seems like a lot of work, right? But it is a stable solution to get the required scaling across different screen sizes in different contexts.

Container queries would have been so much better because they provide us with container query units, such as the cqw unit. You probably already get it, but 1cqw is equal to 1% of a container’s width. We also have the cqi unit that’s a measure of a container’s inline width, and cqb for a container’s block width. So, if we have a card container that is 500px wide, a 50cqw value computes to 250px.

If I had been able to use container queries in my card grid, I could have set up the .card component as a container:

.card {    container: card / size; }

Then I could have set an inner wrapper with padding that scales at 10% of the .card‘s width using the cqw unit:

.card__inner {    padding: 10cqw;  } 

That’s a nice way to scale the spacing between the card’s edges and its contents consistently no matter where the card is used at any given viewport width. No media queries required!

Another idea? Use cqw units for the font size of the inner contents, then apply padding in em units:

.card__inner {    font-size: 5cqw;    padding: 2em; } 

5cqw is an arbitrary value — just one that I settled on. That padding is still equal to 10cqw since the em unit is relative to the .card__inner font size!

Did you catch that? The 2em is relative to the 5cqw font size that is set on the same container. Containers work different than what we’re used to, as em units are relative to the same element’s font-size value. But what I quickly noticed is that container query units relate to the nearest parent that is also a container.

For example, 5cqw does not scale based on the .card element’s width in this example:

.card {    container: card / size;    container-name: card;    font-size: 5cqw;  }

Rather, it scales to whatever the nearest parent that’s defined as a container. That’s why I set up a .card__inner wrapper.

Case 2: Alternating layout

I needed yet another card component in a different project. This time, I needed the card to transition from a landscape layout to a portrait layout… then back to landscape, and back to portrait again as the screen gets smaller.

Showing four states of a card element changing between portrait and landscape layouts at various breakpoints.

I did the dirty work of making this component go to portrait at those two specific viewport ranges (shout out to the new media query range syntax!), but again, the problem is that it is then locked to the media queries set on it, its parent, and anything else that might respond to the viewport’s width. We want something that works in any condition without worrying about wondering where the content is going to break!

Container queries would have made this a breeze, thanks to the @container rule:

.info-card {   container-type: inline-size;   container-name: info-card; }  @container info-card (max-width: 500px) {   .info-card__inner {     flex-direction: column;   } }

One query, infinite fluidity:

But hold on! There’s something you might want to watch out for. Specifically, it could be difficult to use a container query like this within a prop-based design system. For example, this .info-card component could contain child components that rely on props to change their appearance.

Why’s that a big deal? The card’s portrait layout might require the alternate styling but you can’t change JavaScript props with CSS. As such, you risk duplicating the required styles. I actually touched on this and how to work around it in another article. If you need to use container queries for a significant amount of your styling, then you may need to base your entire design system around them rather than trying to shoehorn them into an existing design system that’s heavy on media queries.

Case 3: SVG strokes

Here’s another super common pattern I’ve recently used where container size queries would have resulted in a more polished product. Say you have an icon locked up with a heading:

<h2>   <svg>     <!-- SVG stuff -->   </svg>    Heading </h2>

It’s pretty straightforward to scale the icon with the title’s size, even without media queries. The problem, though, is that the SVG’s stroke-width might get too thin to be noticed all that well at a smaller size, and perhaps catch too much attention with a super thick stroke at a larger size.

I’ve had to create and apply classes to each icon instance to determine its size and stroke width. That’s OK if the icon is next to a heading that’s styled with a fixed font size, I guess, but it’s not so great when working with fluid type that constantly changes.

A lockup of a hexagon icon and heading at three different sizes, from large to small.

The heading’s font size might be based on the viewport’s width, so the SVG icon needs to adjust accordingly where its stroke works at any size. You could make the stroke width relative to the heading’s font-size by setting it in em units. But if you have a specific set of stroke sizes that you need to stick to, then this wouldn’t work because it otherwise scales linearly — there’s no way to adjust it to a specific stroke-width value at certain points without resorting to media queries on the viewport width.

But here’s what I would have done if I had the luxury of container queries at that time:

.icon {   container: icon / size;    width: 1em;    height: 1em;  }  .icon svg {   width: 100%;    height: 100%;    fill: none;    stroke: #ccc;    stroke-width: 0.8;  }  @container icon (max-width: 70px) {   .icon svg {     stroke-width: 1.5;    } } @container icon (max-width: 35px) {   .icon svg {     stroke-width: 3;   } }

Compare the implementations and see how the container query version snaps the SVG’s stroke to the specific widths I want based on the container’s width.

Bonus: Other types of container size queries

OK, so I haven’t actually run into this on a real project. But as I was combing through information on container queries, I noticed that there are additional things we can query on a container that are related to the container’s size or physical dimensions.

Most examples I’ve seen query the width, max-width, and min-width, height, block-size, and inline-size as I’ve been doing throughout this article.

@container info-card (max-width: 500px) {   .info-card__inner {     flex-direction: column;   } }

But MDN outlines two more things we can query against. One is orientation which makes perfect sense because we use it all the time in media queries. It’s no different with container queries:

@media screen (orientation: landscape) {    .info-card__inner {     /* Style away! */   } }   @container info-card (orientation: landscape) {    .info-card__inner {     /* Style away! */   } } 

The other? It’s aspect-ratio, believe it or not:

@container info-card (aspect-ratio: 3/2) {    .info-card__inner {     /* Style away! */   } } 

Here’s an editable demo to play around with both examples:

I haven’t really found a good use case for either of these yet. If you have any ideas or feel like it could’ve helped you in your projects, let me know in the comments!

A Few Times Container Size Queries Would Have Helped Me Out originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.


, , , , ,

Digging Deeper Into Container Style Queries

I wrote up some early thoughts on container style queries a little while back. It’s still early days. They’re already defined in the CSS Containment Module Level 1 specification (currently in Editor’s Draft status) but there’s still a couple of outstanding discussions taking place.

The basic idea is that we can define a container and then apply styles conditionally to its descendants based on its computed styling.

@container <name>? <conditions> {   /* conditional styles */ }

The best example I’ve seen so far is removing italics from something like <em>, <i>, and <q> when they are used in a context where content is already italicized:

em, i, q {   font-style: italic; /* default UA behavior */ }  /* When the container's font-style is italic, remove italics from these elements. */ @container style(font-style: italic) {   em, i, q {     font-style: normal;   } }

That’s the general idea. But if you didn’t know it, Miriam Suzanne, who is an editor of the spec, keeps an ongoing and thorough set of personal notes on container style queries that is publicly available. It was updated the other day and I spent some time in there trying to wrap my head around more nuanced aspects of style queries. It’s unofficial stuff, but I thought I’d jot down some things that stood out to me. Who knows? Maybe it’s stuff we can eventually look forward to!

Every element is a style container

We don’t even need to explictly assign a container-name or container-type to define a style container because everything is a style container by default.

So, you see that example above that removes italics? Notice it doesn’t identify a container. It jumps right to the query using the style() function. So, what container is being queried? It’s going to be the direct parent of the elements receiving the applied styles. And if not that, then it’s the next nearest relative container that takes precedence.

I like that. It’s very CSS-y for the query to search up for a match, then continue to bubble up until it finds a matching condition.

It was hard for my little brain to understand why we can get away with an implicit container based on styles but not so much when we’re dealing with dimensional queries, like size and inline-size. Miriam explains it nicely:

Dimensional queries require css containment on the size, layout, and style of the container in order to prevent layout loops. Containment is an invasive thing to apply broadly, so it was important that authors have careful control over what elements are (or are not) size containers.

Style-based queries don’t have the same limitation. There is already no way in CSS for descendant styles to have an impact on the computed styles of an ancestor. So no containment is required, and there are no invasive or unexpected side-effects in establishing an element as a style query container.

(Emphasis mine)

It all comes down to consequences — of which there are none as far as everything being a style query container right out of the box.

  • If a container is found: conditions are resolved against that container.
  • If multiple containers match: the nearest relative container takes precedence.
  • If no matches are found: unknown returned.

That’s the same “forgiving” spirit as the rest of CSS.

A container can support both dimensional and style queries

Let’s say we want define a style query without an explicit container-name:

@container style(font-style: italic) {   em {     font-style: normal;   } }

This works because all elements are style containers, no matter the container-type. That’s what allows us to implicitly query styles and rely on the nearest match. And this is totally fine since, again, there are no adverse side effects when establishing style containers.

We have to use an explicit container-type for dimensional queries, but not so much for style queries since every element is a style query. That also means this container is both a style and dimensional query:

.card-container {   container: card / inline-size; /* implictly a style query container as well */ }

Excluding a container from being queried

Perhaps we don’t want a container to participate in the matching process. That’s where it might be possible to set container-type: none on an element.

.some-element {   container-type: none; }

Explicit style query containers offer more control of what gets queried

If, say, we were to write a style query for padding , there is no reliable way to determine the best matching container, regardless of whether we’re working with an explicitly named container or the nearest direct parent. That’s because padding is not an inherited property.

So, in those instances, we ought to use container-name to explictly inform the browser which containers they can pull from. We can even give a container multiple explicit names to make it match more conditions:

.card {   container-name: card layout theme; }

Oh, and container-name accepts any number of optional and reusable names for a container! That’s even more flexibility when it comes to helping the browser make a choice when searching for matches.

.theme {   container-name: theme; } .grid {   container-name: layout; } .card {   container-name: card layout theme; }

I sort of wonder if that might also be considered a “fallback” in the event that one container is passed over.

Style queries can be combined

The or and and operators allow us to combine wueries to keep things DRY:

@container bubble style(--arrow-position: start start) or style(--arrow-position: end start) {   .bubble::after {     border-block-end-color: inherit;     inset-block-end: 100%;   } }  /* is the same as... */ @container bubble style(--arrow-position: start start) {   /* etc. */ } @container bubble style(--arrow-position: end start) {   /* etc. */ }

Toggling styles

There’s a little overlap between container style queries and Tab Atkins’ unofficial proposal for CSS Toggles. For example, we can cycle through two font-style values, say italic and normal:

em, i, q {   font-style: italic; }  @container style(font-style: italic) {   em, i, q {     font-style: normal;   } }

Cool. But the proposal for CSS Toggles suggests that the toggle() function would be a simpler approach:

em, i, q {   font-style: toggle(italic, normal); }

But anything beyond this sort of binary use case is where toggle() is less suitable. Style queries, though, are good to go. Miriam identifies three instances where style queries are more suitable than a toggle():

/* When font-style is italic, apply background color. */ /* Toggles can only handle one property at a time. */ @container style(font-style: italic) {   em, i, q {     background: lightpink;   } }  /* When font-style is italic and --color-mode equals light */ /* Toggles can only evaluate one condition at a time */ @container style((font-style: italic) and (--color-mode: light)) {   em, i, q {     background: lightpink;   } }  /* Apply the same query condition to multiple properties */ /* Toggles have to set each one individually as separate toggles */ @container style(font-style: italic) {   em, i, q {     /* clipped gradient text */     background: var(--feature-gradient);     background-clip: text;     box-decoration-break: clone;     color: transparent;     text-shadow: none;   } }

Style queries solve the “Custom Property Toggle Hack”

Notice that style queries are a formal solution for the “CSS custom property toggle trick”. In there, we set an empty custom property (--foo: ;) and use the comma-separated fallback method to “toggle” properties on and off when then custom property is set to a real value.

button {   --is-raised: ; /* off by default */      border: 1px solid var(--is-raised, rgb(0 0 0 / 0.1));   box-shadow: var(     --is-raised,     0 1px hsl(0 0% 100% / 0.8) inset,     0 0.1em 0.1em -0.1em rgb(0 0 0 / 0.2)   );   text-shadow: var(--is-raised, 0 -1px 1px rgb(0 0 0 / 0.3)); }  button:active {   box-shadow: var(--is-raised, 0 1px 0.2em black inset); }  #foo {   --is-raised: initial; /* turned on, all fallbacks take effect. */ } 

That’s super cool, also a lot of work that style container queries makes trivial.

Style queries and CSS generated content

For generated content produced by the content property of ::before and ::after pseudo-elements, the matching container is the element on which the content is generated.

.bubble {   --arrow-position: end end;   container: bubble;   border: medium solid green;   position: relative; }  .bubble::after {   content: "";   border: 1em solid transparent;   position: absolute; }  @container bubble style(--arrow-position: end end) {   .bubble::after {     border-block-start-color: inherit;     inset-block-start: 100%;     inset-inline-end: 1em;   } }

Style queries and web components

We can define a web component as a container and query it by style. First, we have the <template> of the component:

<template id="media-host">   <article>     <div part="img">       <slot name="img">…</slot>     </div>     <div part="content">       <slot name="title">…</slot>       <slot name="content">…</slot>     </div>   </article> </template>

Then we use the :host pseudo-element as a container to set a container-name, a container-type, and some high-level attributes on it:

:host {   container: media-host / inline-size;   --media-location: before;   --media-style: square;   --theme: light; }

Elements inside the <media-host> can query the parameters of the <media-host> element:

@container media-host style(--media-style: round) {   [part='img'] {     border-radius: 100%;   } }

What’s next?

Again, all the stuff I’ve jotted down here is based on Miriam’s notes, and those notes are not a substitute for the official spec. But they are an indication of what’s being discussed and where things could land in the future. I appreciate Miriam linked up a handful of outstanding discussions still taking place that we can follow to stay on top of things:

Digging Deeper Into Container Style Queries originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.


, , , , ,

Early Days of Container Style Queries

We’re still in suuuuuper early days with container queries. Too early for broad browser support, but Chromium already supports it, Safari started supporting it in version 16, and Firefox is presumably not far behind.

Most early days conversations revolving around container queries usually compare the syntax to media queries.

/* Stacked flex container */ .post {   display: flex;   flex-direction: column; }  /* Change direction when viewport is 600px or wider */ @media(min-width: 600px) {   .post {     flex-direction: row;   } }

/* Define the container */ .posts {   container-name: posts;   container-type: inline-size; }  .post {   display: flex;   flex-direction: column; }  /* Query the container's min-width */ @container posts (min-width: 600px) {   /* Change styles when `posts` container is 600px or wider */   .post {     flex-direction: row;   } }

Both of these are making queries for min-width: 600. The difference is that the media query is looking at the viewport’s width to trigger those style changes while the container query is looking at the computed width of the .posts element. Sweet!

But after listening to CSS Podcast Episode 59, Una and Adam poked at the future of container queries: style queries! The current working draft of the CSS Containment Module Level 3 spec defines container style queries:

container style query allows querying the computed values of the query container. It is a boolean combination of individual style features (<style-feature>) that each query a single, specific property of the query container.

But no examples on syntax just yet — only a brief description:

The syntax of a <style-feature> is the same as for a declaration, and its query is true if the computed value of the given property on the query container matches the given value (which is also computed with respect to the query container), unknown if the property or its value is invalid or unsupported, and false otherwise. The boolean syntax and logic combining style features into a style query is the same as for CSS feature queries. (See @supports.)

So, yes, given time we should expect to pull off something like this:

.posts {   container-name: posts; }  @container posts (background-color: #f8a100) {   /* Change styles when `posts` container has an orange background */   .post {     color: #fff;   } }

That’s a pretty dumb example. One thing to note is that the container-type is no longer based on the container’s inline-size but by style. We could delcare that like so:

.posts {   container-name: posts;   container-type: style; /* unnecessary */ }

…but all container queries are style queries by default. Well. at least as it stands today. Miriam Suzanne has a nice outline of the possible issues that might pop up with that.

Where might querying a container’s styles come in handy? I don’t know yet! But my mind gos to a few places:

  • Custom property values: We’ve seen custom properties used like state indicators, such as the DRY-switching method Ana covered a while back. The value changes, and so do styles.
  • Alternate dark mode approach: Instead of basing it all on a body class change that re-assigns custom property values, maybe we can change an entire color palette if, say, the body background changes color.
  • More complex query conditions: Like, say, we want to apply styles when the size and style conditions for a container are met.

Una also mentioned in the CSS Podcast that container style queries could help prevent some awkward styling situations, like if we happen to have italicized text in an already italicized blockquote:

blockquote {   container-name: quote; }  @container quote (font-style: italic) {   em, i, q, address {     font-style: normal;   } }

Early Days of Container Style Queries originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.


, , , ,

iShadeed’s Container Queries Lab

Ahmad Shadeed got an early jump on container queries and has a growing collection of examples based on everyday patterns.

And, if you missed it, his latest post on container queries does a wonderful job covering how they work since landing in Chrome 105 this month (we’ll see them in Safari 16 soon). Some choice highlights and takeaways:

  • Containers are defined with the container-type property. Previous demos and proposals had been using contain instead.
  • Container queries are very much like the media queries we’ve been writing all along to target the viewport size. So, rather than something like @media (min-width: 600px) {}, we have @container (min-width: 600px) {}. That should make converting many of those media queries to container queries fairly straightfoward, minus the work of figuring out the new breakpoint values.
  • We can name containers to help distinguish them in our code (e.g. container-name: blockquote).

Great job, Ahmad! And thanks for sharing!

To Shared LinkPermalink on CSS-Tricks

iShadeed’s Container Queries Lab originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.


, ,

Conditionally Styling Selected Elements in a Grid Container

Calendars, shopping carts, galleries, file explorers, and online libraries are some situations where selectable items are shown in grids (i.e. square lattices). You know, even those security checks that ask you to select all images with crosswalks or whatever.


I found a neat way to display selectable options in a grid. No, not recreating that reCAPTCHA, but simply being able to select multiple items. And when two or more adjoining items are selected, we can use clever :nth-of-type combinators, pseudo elements, and the :checked pseudo-class to style them in a way where they look grouped together.

The whole idea of combinators and pseudos to get the rounded checkboxes came from a previous article I wrote. It was a simple single-column design:

This time, however, the rounding effect is applied to elements along both the vertical and horizontal axes on a grid. You don’t have to have read my last article on checkbox styling for this since I’m going to cover everything you need to know here. But if you’re interested in a slimmed down take on what we’re doing in this article, then that one is worth checking out.

Before we start…

It’ll be useful for you to take note of a few things. For example, I’m using static HTML and CSS in my demo for the sake of simplicity. Depending on your application you might have to generate the grid and the items in it dynamically. I’m leaving out practical checks for accessibility in order to focus on the effect, but you would definitely want to consider that sort of thing in a production environment.

Also, I’m using CSS Grid for the layout. I’d recommend the same but, of course, it’s only a personal preference and your mileage may vary. For me, using grid allows me to easily use sibling-selectors to target an item’s ::before and ::after pseudos.

Hence, whatever layout standard you might want to use in your application, make sure the pseudos can still be targeted in CSS and ensure the layout stays in tact across different browsers and screens.

Let’s get started now

As you may have noticed in the earlier demo, checking and unchecking a checkbox element modifies the design of the boxes, depending on the selection state of the other checkboxes around it. This is possible because I styled each box using the pseudo-elements of its adjacent elements instead of its own element.

The following figure shows how the ::before pseudo-elements of boxes in each column (except the first column) overlap the boxes to their left, and how the ::after pseudo-elements of boxes in each row (except the first row) overlap the boxes above.

Two grids of checkboxes showing the placement of before and after pseudos.

Here’s the base code

The markup is pretty straightforward:

<main>   <input type=checkbox>    <input type=checkbox>    <input type=checkbox>   <!-- more boxes --> </main>

There’s a little more going on in the initial CSS. But, first, the grid itself:

/* The grid */ main {   display: grid;   grid:  repeat(5, 60px) / repeat(4, 85px);   align-items: center;   justify-items: center;   margin: 0; }

That’s a grid of five rows and four columns that contain checkboxes. I decided to wipe out the default appearance of the checkboxes, then give them my own light gray background and super rounded borders:

/* all checkboxes */ input {   -webkit-appearance: none;   appearance: none;   background: #ddd;   border-radius: 20px;   cursor: pointer;   display: grid;   height: 40px;   width: 60px;   margin: 0; }

Notice, too, that the checkboxes themselves are grids. That’s key for placing their ::before and ::after pseudo-elements. Speaking of which, let’s do that now:

/* pseudo-elements except for the first column and first row */ input:not(:nth-of-type(4n+1))::before, input:nth-of-type(n+5)::after {   content: '';           border-radius: 20px;   grid-area: 1 / 1;   pointer-events: none; }

We’re only selecting the pseudo-elements of checkboxes that are not in the first column or the first row of the grid. input:not(:nth-of-type(4n+1)) starts at the first checkbox, then selects the ::before of every fourth item from there. But notice we’re saying :not(), so really what we’re doing is skipping the ::before pseudo-element of every fourth checkbox, starting at the first. Then we’re applying styles to the ::after pseudo of every checkbox from the fifth one.

Now we can style both the ::before and ::after pseudos for each checkbox that is not in the first column or row of the grid, so that they are moved left or up, respectively, hiding them by default.

/* pseudo-elements other than the first column */ input:not(:nth-of-type(4n+1))::before {    transform: translatex(-85px); }  /* pseudo-elements other than the first row */ input:nth-of-type(n+5)::after {  transform: translatey(-60px);  }

Styling the :checked state

Now comes styling the checkboxes when they are in a :checked state. First, let’s give them a color, say a limegreen background:

input:checked { background: limegreen; }

A checked box should be able to re-style all of its adjacent checked boxes. In other words, if we select the eleventh checkbox in the grid, we should also be able to style the boxes surrounding it at the top, bottom, left, and right.

A four-by-five grid of squares numbered one through 20. 11 is selected and 7, 10, 12, and 15 are highlighted.

This is done by targeting the correct pseudo-elements. How do we do that? Well, it depends on the actual number of columns in the grid. Here’s the CSS if two adjacent boxes are checked in a 5⨉4 grid:

/* a checked box's right borders (if the element to its right is checked) */ input:not(:nth-of-type(4n)):checked + input:checked::before {    border-top-right-radius: 0;    border-bottom-right-radius: 0;    background: limegreen; } /* a checked box's bottom borders (if the element below is checked) */ input:nth-last-of-type(n+5):checked + * + * + * + input:checked::after {   border-bottom-right-radius: 0;   border-bottom-left-radius: 0;   background: limegreen; } /* a checked box's adjacent (right side) checked box's left borders */ input:not(:nth-of-type(4n)):checked + input:checked + input::before {            border-top-left-radius: 0;    border-bottom-left-radius: 0;    background: limegreen; } /* a checked box's adjacent (below) checked box's top borders */ input:not(:nth-of-type(4n)):checked + * + * + * +  input:checked + input::before {    border-top-left-radius: 0;    border-top-right-radius: 0;    background: limegreen; }

If you prefer you can generate the above code dynamically. However, a typical grid, say an image gallery, the number of columns will be small and likely a fixed number of items, whereas the rows might keep increasing. Especially if designed for mobile screens. That’s why this approach is still an efficient way to go. If for some reason your application happens to have limited rows and expanding columns, then consider rotating the grid sideways because, with a stream of items, CSS Grid arranges them left-to-right and top-to-bottom (i.e. row by row).

We also need to add styling for the last checkboxes in the grid — they’re not all covered by pseudo-elements as they are the last items in each axis.

/* a checked box's (in last column) left borders */ input:nth-of-type(4n-1):checked + input:checked {   border-top-left-radius: 0;   border-bottom-left-radius: 0; } /* a checked box's (in last column) adjacent (below) checked box's top borders */ input:nth-of-type(4n):checked + * + * + * + input:checked {   border-top-left-radius: 0;   border-top-right-radius: 0; }

Those are some tricky selectors! The first one…

input:nth-of-type(4n-1):checked + input:checked

…is basically saying this:

A checked <input> element next to a checked <input> in the second last column.

And the nth-of-type is calculated like this:

4(0) - 1 = no match 4(1) - 1 = 3rd item 4(2) - 1 = 7th item 4(3) - 1 = 11th item etc.

So, we’re starting at the third checkbox and selecting every fourth one from there. And if a checkbox in that sequence is checked, then we style the checkboxes adjacent, too, if they are also checked.

And this line:

input:nth-of-type(4n):checked + * + * + * + input:checked

Is saying this:

An <input> element provided that is checked, is directly adjacent to an element, which is directly adjacent to another element, which is also directly adjacent to another element, which, in turn, is directly adjacent to an <input> element that is in a checked state.

What that means is we’re selecting every fourth checkbox that is checked. And if a checkbox in that sequence is checked, then we style the next fourth checkbox from that checkbox if it, too, is checked.

Putting it to use

What we just looked at is the general principle and logic behind the design. Again, how useful it is in your application will depend on the grid design.

I used rounded borders, but you can try other shapes or even experiment with background effects (Temani has you covered for ideas). Now that you know how the formula works, the rest is totally up to your imagination.

Here’s an instance of how it might look in a simple calendar:

Again, this is merely a rough prototype using static markup. And, there would be lots and lots of accessibility considerations to consider in a calendar feature.

That’s a wrap! Pretty neat, right? I mean, there’s nothing exactly “new” about what’s happening. But it’s a good example of selecting things in CSS. If we have a handle on more advanced selecting techniques that use combinators and pseudos, then our styling powers can reach far beyond the styling one item — as we saw, we can conditionally style items based on the state of another element.

Conditionally Styling Selected Elements in a Grid Container originally published on CSS-Tricks. You should get the newsletter.


, , , , ,

A New Container Query Polyfill That Just Works

There is now a polyfill for Container Queries that behaves as perfectly as a polyfill should:

  1. You conditionally load it when you detect the browser doesn’t support Container Queries.
  2. You write CSS as you normally would, including current-spec-compliant Container Queries syntax code.
  3. It just works.

It’s pretty great to have a container query polyfill that is this easy to use and from Chrome itself, the first-movers as far as early test implementations. Looks like Surma put it together — thanks Surma!

There was a Container Query polyfill from Jonathan Neal called cqfill that predates this. I’m not sure if it’s officially deprecated, but it required extra non-spec CSS to work and PostCSS processing, so I’d consider it deprecated in favor of this newer polyfill.

Loading the polyfill is like this:

// Support Test const supportsContainerQueries = "container" in document.documentElement.style;  // Conditional Import if (!supportsContainerQueries) {   import("https://cdn.skypack.dev/container-query-polyfill"); }

You can pull it from npm or use as a <script>, but this way seems best to me to keep things light and easy.

Then you’re free to use the syntax for a container query in CSS. Say you have a weather widget in HTML. You’ll need an extra wrapper element for your queries. That’s just the rule: you can’t query the thing you style.

<div class="weather-wrap">   <dl class="weather">     <div>       <dt>Sunday</dt>       <dd>         <b>26°</b> 7°       </dd>     </div>     <div>       <dt>Monday</dt>       <dd>         <b>34°</b> 11°       </dd>     </div>     <!-- etc -->   </dl> </div>

The wrapper is instantiated as a container:

.weather-wrap {   container: inline-size / weather-wrapper;   /* Shorthand for: */   /* container-type: inline-size; */   /* container-name: weather-wrapper; */    /* For quick testing, do this to get a resize handle on desktop: */   /* resize: both; */   /* overflow: hidden; */ }

Then you write any global styling for that component, as well as container query scoped styles:

.weather {   display: flex; } @container weather-wrapper size(max-width: 700px) {   .weather {     flex-direction: column;   } }

Container Queries polyfill example

Here’s that slightly more fleshed-out demo of the Container Query polyfill using an actual weather widget:

I first saw this over on Bramus’ blog, and he’s got a classic card demo going with this Container Query polyfill. Scroll up and down. You’ll see a row of bear cards at the top (if your browser window is wide enough), and then similar bear cards in different layout positions below that change into nicer formats when they can, based on the container query.

Container Query polyfill browser support

The polyfill docs say:

The polyfill relies on ResizeObserverMutationObserver and :is(). Therefore, it should work in all modern browsers, specifically Chrome/Edge 88+, Firefox 78+ and Safari 14+.

There are all sorts of other minor little caveats covered in those docs, including what it does and doesn’t support. Seems like mostly niche stuff to me — the main/typical use cases are covered.

A game changer?

As I write, we’ve seen behind-flag support for Container Queries in Chrome, and it is an official spec draft now:

That’s extremely exciting and points heavily toward browsers actually shipping with Container Queries, even if the syntax changes a bit on the way (it already has a number of times). But, of course, we have no idea if/when Container Queries do ship — and when that magical threshold is crossed, we also don’t know where we can use them without much worry, like we can with flexbox and grid now.

That “just use it” date is probably a decent ways off, but if you’re into the idea of polyfilling and being careful with progressive enhancement, I’d say the date for using Container Queries could be right now-ish. Looks to me like the polyfill script comes across the wire at 2.8kb, so it’s fairly trivial in size for something so important.

I suspect this polyfill will skyrocket usage of Container Queries in this coming year.


The fact that your styles only correctly apply after a JavaScript file is downloaded and executed puts sites into Flash of Unstyled Content (FOUC) territory. Here’s a video recording where I can see it on my own demo. I’m not sure there is a way around this other than intentionally delaying rendering, which is generally considered a no-no. Similar to loading web fonts, FOUC is probably a good thing as it means your content is never hidden or delayed, even if the shifts aren’t ideal. The FOUC should go away once browser support lands and the polyfill stops loading at all.

Have fun polyfilling container queries! I’d love to see more demos of it.

GitHub Repo for the Container Query Polyfill

A New Container Query Polyfill That Just Works originally published on CSS-Tricks. You should get the newsletter and become a supporter.


, , , ,

Container Units Should Be Pretty Handy

Container queries are going to solve this long-standing issue in web design where we want to make design choices based on the size of an element (the container) rather than the size of the entire page. So, if a container is 600px wide, perhaps it has a row-like design, but any narrower than that it has a column-like design, and we’ll have that kind of control. That’s much different than transitioning between layouts based on screen size.

We can already size some things based on the size of an element, thanks to the % unit. For example, all these containers are 50% as wide as their parent container.

The % here is 1-to-1 with the property in use, so width is a % of width. Likewise, I could use % for font-size, but it will be a % of the parent container’s font-size. There is nothing that lets me cross properties and set the font-size as a % of a container’s width.

That is, unless we get container units! Here’s the table of units per the draft spec:

unit relative to
qw 1% of a query container’s width
qh 1% of a query container’s height
qi 1% of a query container’s inline size
qb 1% of a query container’s block size
qmin The smaller value of qi or qb
qmax The larger value of qi or qb

With these, I could easily set the font-size to a percentage of the parent container’s width. Or line-height! Or gap! Or margin! Or whatever!

Miriam notes that we can actually play with these units right now in Chrome Canary, as long as the container queries flag is on.

I had a quick play too. I’ll just put a video here as that’ll be easier to see in these super early days.

And some great exploratory work from Scott here as well:

Ahmad Shadeed is also all over this!

Query units can save us effort and time when dealing with things like font-sizepadding, and margin within a component. Instead of manually increasing the font size, we can use query units instead.

Ahmad Shadeed, “CSS Container Query Units”

Maybe container queries and container units will drop for real at the same time. 🤷

The post Container Units Should Be Pretty Handy appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.


, , , ,

Media Queries in Times of @container

Max Böck took me up on my challenge to look through a codebase and see how many of the @media queries could ultimately become @container queries.

I took the bait and had a look at some of my projects – and yes, most of what I use @media for today can probably be accomplished by @container at some point. Nevertheless, I came up with a few scenarios where I think media queries will still be necessary.

Max didn’t say exactly how many would be replaced, but I got the impression it was 50/50ish.

A combination of both techniques will probably be the best way forward. @media can handle the big picture stuff, user preferences and global styles; @container will take care of all the micro-adjustments in the components themselves.

A perfect team!

I also think there will be a big difference between what we do when refactoring an existing CSS codebase to what we do when we are building from scratch. And it will be different what we do when we first get container queries to what we do years from now when new patterns have settled in. I’ve long been bullish on components being the right abstraction for front-end development. It feels like everything lately pushes us in that direction, from JavaScript frameworks and to native components, to container queries and style scoping.

Direct Link to ArticlePermalink

The post Media Queries in Times of @container appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.


, , ,

A Cornucopia of Container Queries

I don’t know about y’all, but my feeds have been flooded with articles about CSS Container Queries these past few weeks. The buzz about container queries actually started back in December after Miriam Suzanne posted a proposal (picking up on David Baron’s proposal) but it was news in a late-March tweet from Una Kravets that they dropped in Chrome Canary 91.0.4459.0 behind the #enable-container-queries flag in chrome://flags.

So much about container queries has already been covered in so many places in such a short amount of time — and the specification isn’t even final! I’m just pleased as punch to see so much excitement about a CSS feature and wanted to bottle some it up. Chris also just to happened to be collecting a pile of links on the topic, so here’s a roundup of everything that’s crossed our desks.

Container Queries Explainer & Proposal

Miriam’s article is an excellent starting point to kick things off. This is sort of like the elevator pitch that introduces the idea while providing a bunch of examples and resources that are worth checking out.

Container Queries: a Quick Start Guide

David Herron jumps right into the concept over on the Oddbird blog, which is fitting since that’s where Miriam Suzanne works as well. This is a great introduction to container queries that gets into the syntax with an example that looks at a card component.

A Primer on CSS Container Queries

Stephanie Eckles goes super deep into container queries over on Smashing Magazine. I love that the article starts off by stating what container queries solves before jumping into the syntax and how-to.

Container Queries are actually coming

Andy Bell has wanted container queries as long as anyone. He wasted no time jumping into them with a card example of his own. And hey, he can finally retire his sticker.

Say Hello To Container Queries

I always appreciate both the way Ahmed Shadeed explains things in the simplest possible terms, and that his demos go beyond common examples and into interesting use cases.

CSS Container Queries: A First Look + Demo

OK, this is cheating since Bramus published this at the end of March. But it was really after this post when I started seeing others pour in.

Next Gen CSS: @container

Yes, CSS-Tricks added to the chatter as well! Una Kravets has what might be my favorite demo of container queries so far: a calendar that adjusts everything from font sizes to layout

Container Queries in Web Components

Max Böck does what I love best: take two ideas and smash ’em together! He made a stellar demo of a web component for displaying books and integrates @container.

Component-level art direction with CSS Container Queries

Sara Soueidan shows how container queries can be used to art direct images, including gotchas that come with using the <picture> element with @container.

Susy and Sass, CSS Layers and CSS compatibility, Container Queries and CSSWG

Listen to Bruce Lawson and Vadim Makeev discuss container queries (among other things) with Miriam.

Container Queries are going to be a game changer!

Watch Kevin Powell demo how those fancy auto-fill/minmax() grids are a nice use case for components styling themselves based on how big they are at any given point.

CSS Container Queries Polyfill FIRST LOOK

Scott Tolinski looks at cqfill. Bramus does the same here in this blog post. The best part of Scott’s video is adding transitions on the changed properties.

Can We Create a “Resize Hack” With Container Queries?

Jhey Tompkins was already feeling there is too many card demos for container queries and wanted to do something super different.

Container Queries & The Future of CSS

There’s no such thing as too much when it comes to learning about containers from Miriam Suzanne. Here’s a conference video.

Container Queries for Designers

Ahmad Shadeed says designers might want to start thinking about container queries. Having a document that outlines breakpoints for a single component seems like the way to go for now.

CSS Container Queries: Use-Cases And Migration Strategies

Adrian Bece covers the basics here, and pointed out a few things I didn’t know. One, there are no DevTools for for container queries yet, making them tricky to debug.

The new responsive: Web design in a component-driven world

Una Kravets connects not just container queries, but other concepts to facilitate this component-driven world. Sounds like native scoped styles might have a bit of traction again!

All Them Switches: Responsive Elements and More

Brian Kardell’s article is more about a possible switch() function (and keyword friends) that look very useful, even independent of container queries.

Quite a bit, right? Before we sign off, Chris has a challenge for all of us he wanted to share:

A common refrain, from me included, has been that if we had container queries we’d use them for the vast majority of what we use media queries for today. The challenge is: look through your CSS codebase now with fresh eyes knowing how the @container queries currently work. Does that refrain hold up? Which media queries will you replace (once we reasonably can) and which ones have to remain? Blog that.

The post A Cornucopia of Container Queries appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.


, ,

Can We Create a “Resize Hack” With Container Queries?

If you follow new developments in CSS, you’ve likely heard of the impending arrival of container queries. We’re going to look at the basics here, but if you’d like another look, check out Una’s “Next Gen CSS: @container” article. After we have a poke at the basics ourselves, we’re going to build something super fun with them: a fresh take on the classic CSS meme featuring Peter Griffin fussing with window blinds. 😉

So, what is a container query? It’s… exactly that. Much like we have media queries for querying things such as the viewport size, a container query allows us to query the size of a container. Based on that, we can then apply different styles to the children of said container.

What does it look like? Well, the exact standards are being worked out. Currently, though, it’s something like this:

.container {   contain: layout size;   /* Or... */   contain: layout inline-size; }  @container (min-width: 768px) {   .child { background: hotpink; } }

The layout keyword turns on layout-containment for an element. inline-size allows users to be more specific about containment. This currently means we can only query the container’s width. With size, we are able to query the container’s height.

Again, we things could still change. At the time of writing, the only way to use container queries (without a polyfill) is behind a flag in Chrome Canary (chrome://flags). I would definitely recommend having a quick read through the drafts over on csswg.org.

The easiest way to start playing would be to whip up a couple quick demos that sport a resizable container element.

Try changing the contain values (in Chrome Canary) and see how the demos respond. These demo uses contain: layout size which doesn’t restrict the axis. When both the height and width of the containers meet certain thresholds, the shirt sizing adjusts in the first demo. The second demo shows how the axes can work individually instead, where the beard changes color, but only when adjusting the horizontal axis.

@container (min-width: 400px) and (min-height: 400px) {   .t-shirt__container {     --size: "L";     --scale: 2;   } }

That’s what you need to know to about container queries for now. It’s really just a few new lines of CSS.

The only thing is: most demos for container queries I’ve seen so far use a pretty standard “card” example to demonstrate the concept. Don’t get me wrong, because cards are a great use case for container queries. A card component is practically the poster child of container queries. Consider a generic card design and how it could get affected when used in different layouts. This is a common problem. Many of us have worked on projects where we wind up making various card variations, all catering to the different layouts that use them.

But cards don‘t inspire much to start playing with container queries. I want to see them pushed to greater limits to do interesting things. I‘ve played with them a little in that t-shirt sizing demo. And I was going to wait until there was better browser support until I started digging in further (I’m a Brave user currently). But then Bramus shared there was a container query polyfill!

And this got me thinking about ways to “hack” container queries.

⚠️ Spoiler alert: My hack didn’t work. It did momentarily, or at least I thought it did. But, this was actually a blessing because it prompted more conversation around container queries.

What was my idea? I wanted to create something sort of like the “Checkbox Hack” but for container queries.

<div class="container">   <div class="container__resizer"></div>   <div class="container__fixed-content"></div> </div>

The idea is that you could have a container with a resizable element inside it, and then another element that gets fixed positioning outside of the container. Resizing containers could trigger container queries and restyle the fixed elements.

.container {   contain: layout size; }  .container__resize {   resize: vertical;   overflow: hidden;   width: 200px;   min-height: 100px;   max-height: 500px; }  .container__fixed-content {   position: fixed;   left: 200%;   top: 0;   background: red; }  @container(min-height: 300px) {   .container__fixed-content {     background: blue;   } }

Try resizing the red box in this demo. It will change the color of the purple box.

Can we debunk a classic CSS meme with container queries?

Seeing this work excited me a bunch. Finally, an opportunity to create a version of the Peter Griffin CSS meme with CSS and debunk it!

You’ve probably seen the meme. It’s a knock on the Cascade and how difficult it is to manage it. I created the demo using cqfill@0.5.0… with my own little touches, of course. 😅

Moving the cord handle, resizes an element which in turn affects the container size. Different container breakpoints would update a CSS variable, --open, from 0 to 1, where 1 is equal to an “open” and 0 is equal to a “closed” state.

@container (min-height: 54px) {   .blinds__blinds {     --open: 0.1;   } } @media --css-container and (min-height: 54px) {   .blinds__blinds {     --open: 0.1;   } } @container (min-height: 58px) {   .blinds__blinds {     --open: 0.2;   } } @media --css-container and (min-height: 58px) {   .blinds__blinds {     --open: 0.2;   } } @container (min-height: 62px) {   .blinds__blinds {     --open: 0.3;   } } @media --css-container and (min-height: 62px) {   .blinds__blinds {     --open: 0.3;   } }

But…. as I mentioned, this hack isn’t possible.

What’s great here is that it prompted conversation around how container queries work. It also highlighted a bug with the container query polyfill which is now fixed. I would love to see this “hack” work though.

Miriam Suzanne has been creating some fantastic content around container queries. The capabilities have been changing a bunch. That’s the risk of living on the bleeding edge. One of her latest articles sums up the current status.

Although my original demo/hack didn’t work, we can still kinda use a “resize” hack to create those blinds. Again, we can query height if we use contain: layout size. Side note: it’s interesting how we’re currently unable to use contain to query a container’s height based on resizing its child elements.

Anyway. Consider this demo:

The arrow rotates as the container is resized. The trick here is to use a container query to update a scoped CSS custom property.

.container {   contain: layout size; }  .arrow {   transform: rotate(var(--rotate, 0deg)); }  @container(min-height: 200px) {   .arrow {     --rotate: 90deg;   } }

We‘ve kinda got a container query trick here then. The drawback with not being able to use the first hack concept is that we can’t go completely 3D. Overflow hidden will stop that. We also need the cord to go beneath the window which means the windowsill would get in the way.

But, we can almost get there.

This demo uses a preprocessor to generate the container query steps. At each step, a scoped custom property gets updated. This reveals Peter and opens the blinds.

The trick here is to scale up the container to make the resize handle bigger. Then I scale down the content to fit back where it’s meant to.

This fun demo “debunking the meme” isn’t 100% there yet, but, we’re getting closer. Container queries are an exciting prospect. And it’ll be interesting to see how they change as browser support evolves. It’ll also be exciting to see how people push the limits with them or use them in different ways.

Who know? The “Resize Hack” might fit in nicely alongside the infamous “Checkbox Hack” one day.

The post Can We Create a “Resize Hack” With Container Queries? appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.


, , , ,