CSS: subgrid, container queries, has()

リン (linh)
Goalist Blog
Published in
5 min readMar 30, 2024

--

I. What is Baseline

If you access to MDN, Can I Use, or web.dev t search for a web feature, you may see something like this. So what is it?

According to Google’s new definition,

Web Platform Baseline brings clarity to information about browser support for web platform features.

Web Platform Baseline gives you clear information about which web platform features are safe to use in your projects today. When reading an article, or choosing a library for your project, if the features used are all part of Baseline, you can trust the level of browser compatibility. By aligning with Baseline, there should be no surprises when testing your site.

So, in general it’s just a piece of information to let you know wether the feature is compatible with what browser.

It has 2 phases:

  • Newly available: The feature becomes supported by the last of the core browsers, and is therefore interoperable.
  • Widely available: 30 months has passed since the newly interoperable date. The feature can be used by most sites without worrying about support.

You can checkout details post and previous definition of Baseline here.

II. What’s new

Features that are in Baseline newly available will also show a badge, along with the year that they became available. So, anything that became interoperable across the core browser set last year is part of Baseline 2023.

There are many features, but i don’t think i’ll ever use all of them, so i’d like to introduce some that might actually be helpful.

1/ Subgrid

Source: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Container_queries

The doc might be a little too detailed, but subgrid is basically that when you declare grid template on the grid-container, then, in the grid-item declare the grid template using subgrid, children elements of grid-item will be placed gridly based on the grid-container.

For example:
Without subgrid, we’ll dedclare grid template once on grid-container (black line), and once in grid-item (green line). If we do this, children elements (yellow line) will be placed gridly base on grid-item level. Because of this, the height of those children elements on each card is not align, the longer the content, the bigger height it gets.

With subgrid, children elements of grid-item will be placed gridly based on the grid-container. so it can be aligned.

The code is something like this.

<div class="grid">
<div class="item">
<div class="subitem1">subitem1 subitem1 subitem1 subitem1 subitem1 subitem1 </div>
<div class="subitem2">subitem2 </div>
<div class="subitem3">subitem3 </div>
</div>
<div class="item">
<div class="subitem1">subitem1 </div>
<div class="subitem2">subitem2 </div>
<div class="subitem3">subitem3 subitem3 subitem3 </div>
</div>
<div class="item">
<div class="subitem1">subitem1 </div>
<div class="subitem2">subitem2 subitem2 subitem2 subitem2 subitem2 subitem2 subitem2 subitem2 subitem2 subitem2 subitem2 subitem2 subitem2 subitem2 </div>
<div class="subitem3">subitem3 </div>
</div>
</div>
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(4, minmax(50px, auto));
gap: 16px;
padding: 16px;
color: black;
}

.item {
display: grid;
grid-row: 1 / 4;
grid-template-columns: subgrid;
grid-template-rows: subgrid;
}

.subitem1 {
background-color: #EED3D9;
color: black;
text-align: center;
}
.subitem2 {
background-color: #EEC759;
color: black;
text-align: center;
}
.subitem3 {
background-color: #9BB8CD;
color: black;
text-align: center;
}

Output:

2/ Container queries

Source: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Container_queries

The name says it all, unlike media queries, which mean your elements are responsive to view port, container queries means elements are responsive to their container.

Below is the syntax we can use,

@container (width > 400px) and (height > 400px) {
/* <stylesheet> */
}

@container (width > 400px) or (height > 400px) {
/* <stylesheet> */
}

@container not (width < 400px) {
/* <stylesheet> */
}

For example: we have a post container and a card inside it. To adjust the text size of the card base on the width of post. Do this:

.card {
font-size: 20px;
}
.post {
container-type: inline-size;
container-name: post;
}

@container post (max-width: 700px) {
.card {
font-size: 14px;
}
}

Please note that:

  • We don’t need to have container name if you have only 1 container query, but since containers are elements, we can have many containers, so it’s better to have container name.
  • If you query with height, please be noted that it only work with container-type: size

2/ has() — the family selector

Source: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Container_queries

If you have ever used Tailwind, you must be familiar with groupand peer, which are used to style other elements when parent/same-level element is hover/focus/…

Now you can do similar thing, or even more with has()
It is literaly means that if an element has a child element which is hovered/focused/any-other-action-or-state, then do something with other child elements.

Here’s the simpliest example, in which i turn the text content to red when title is hovered.

<li class="card">
<h2 class="card__title">
<a href="#">Some Awesome Article</a>
</h2>
<p class="card__blurb">Here's a description for this awesome article.</p>
<small class="card__author">Chrome DevRel</small>
</li>
/* ... refer to https://developer.chrome.com/blog/has-m105 */
.card:has(.card__title:hover) .card__blurb {
color: red;
}

Although this seems almighty, there are some note-taking point below:

  • You can’t :has() a :has(). But you can chain a :has(). css :has(.a:has(.b)) { }
  • No pseudo element usage within :has() css :has(::after) {} :has(::first-letter) { }
  • Restrict use of :has() inside pseudos accepting only compound selectors css ::slotted(:has(.a)) { } :host(:has(.a)) { } :host-context(:has(.a)) { } ::cue(:has(.a)) { }
  • Restrict use of :has() after pseudo element css ::part(foo):has(:focus) { }
  • Use of :visited will always be false css :has(:visited) { }

More details here!

III. Conclusion

I have been usign SCSS for so long, i didn’t realize CSS has become a lot more cool now. Although these features are not widely availale yet, most devices have latest browser version and has no problem using them.

I hope you’ll have a different look on CSS now and have fun with it!

🙇‍♀️

--

--

リン (linh)
Goalist Blog

A career-changed-non-tech-background point of view.