Strategies for using new CSS features

December 22, 2022

I was originally inspired to write this post after creating several solutions using container queries and the :has selector in August and September. The idea was to give some examples of how you could start utilizing these new CSS features now even though not all of the evergreen browsers supported them.

But both of these features will soon have evergreen support once Firefox 109 releases on January 17, 2023, and there is not as great a need to focus on specific solutions for these two features. So instead of just thinking of these examples of how you could implement these two specific features, I want it to serve as a case study for implementing newer features now and into the future.

I am a strong believer in progressive enhancement as an approach to building websites. I think it is important to provide a baseline of functionality to all users and then layer “enhancements” on top of it.

I don’t always follow through with this as much as I would like. I have gotten lazier when using CSS Grid now that it has been available for the last five years. I use always put grid declarations inside a feature query (@supports). But the nice thing about CSS is that if the browser does not support that syntax, it will just ignore it. And I have abandoned earlier strategies of creating the layout with floats or Flexbox and then adding Grid.


Case study 1: Container query to enhance a card

The first solution I want to look at was for a card layout for Real World Learning. Almost all the designs I build out are given to me in a desktop view mockup and then I have the freedom to determine how the layout will adjust to smaller screens. The mockup for the resources page contained a grid of resource cards. The individual cards had an icon on the left and text content on the right.

As I began exploring the mobile view of this layout, the card layout of the icon and the text did not work well because the icon took up too much space. It made sense to change the layout to have the icon on the top and the text content underneath.

After some experimentation, I determined that the two-column layout of the icon on the left did not work well until the card was at least 420 pixels wide. But I also noticed that the one-column layout broke down around 350 pixels wide.

When I was building this layout, container queries had not yet been implemented in any of the evergreen browsers. You could only find them in Chrome Canary or Safari Technology Preview. But I knew that they would be coming in the fall so I decided to implement a container query solution that would display the card in either a one-column or two-column layout depending on the width of the card.

Starting with a progressively enhanced approach, I coded the card to have a one-column layout on mobile. I added a breakpoint at 600px to change the layout of the card from flex-direction: column to flex-direction: row to achieve the two-column layout.

My usual practice has been to add grid columns using breakpoints. But I decided on this project to use a more flexible grid layout using minmax() and setting the grid to add another column at a minimum value.

For my default (browsers that do not support container queries), I set the minimum value to 420px, which I mentioned above as the point where the two-column layout seemed to work the best.

grid-template-columns: repeat(auto-fill, minmax(min(420px,100%), 1fr));

Then I added a feature query to see if the browser supported container queries. If there is support, I changed the minimum to 350px.

@supports (container-type: inline-size) {
  grid-template-columns: repeat(auto-fill, minmax(min(350px,100%), 1fr));
}

And then I added a container query to the card to make the layout flex-direction: column if the container was less than 420px wide. So the user will see a one-column layout when the container is 350px to 419px.

@supports (container-type: inline-size) {
    .resource-card {
        container-type: inline-size;
    }
    @supports (container-type: inline-size) {
        @container (max-width: 419px) {
            .resource-card .container {
                flex-direction: column;
            }
        }
    }
}

Here is the HTML for the card for reference:

<div class="resource-card">
    <div class="container">
        <i class="icon blog">...</i>
        <div class="text-block">...</div>
    </div>
</div>

Case study 2: :has selector to target the same link target in a card

The second example is purely progressive enhancement. It comes from the Energy Efficiency Hub project that LGND launched in mid-October. At the bottom of all the pages, we are using a “see more content” block.

For the video listing on the right side of the page, the individual cards have a thumbnail of the video on the left and a text block with the date the resource was added, the title of the video, which is linked to the video file, and a tag. The thumbnail is also a link to the video. I wanted to be able to highlight (the text changes from black to an orange color) the link in the video title when the user hovers over the thumbnail, just as the link would be highlighted when you hover over the title.

This enhancement would not be possible without Javascript in CSS before the :has selector. Now it is very easy to check if the thumbnail has a hover state and then target the link inside the heading.

.card-thumbnail:has(a:hover) + .text-block h3 a {
    color: $color-ember;
}

And the HTML for the card:

<article class="resource-card video-card">
    <figure class="card-thumbnail">
        <a class="video-link" href="https://youtu.be/Phr7ItAUcH0" data-video-id="Phr7ItAUcH0" aria-label="Watch Why is the Hub unique?"></a>
        <img decoding="async" class="video-thumbnail" src="https://img.youtube.com/vi/Phr7ItAUcH0/hqdefault.jpg" alt="Why is the Hub unique?">
        <img decoding="async" loading="lazy" class="play-btn" src="https://energyefficiencyhub.org/wp-content/themes/energy-efficiency-hub-v2/build/images/play-button.svg" width="54" height="54" alt="">
    </figure>
    <div class="text-block">
        <p class="post-date">January 26, 2022</p>
        <h3 class="card-heading"><a class="video-link" href="https://youtu.be/Phr7ItAUcH0" data-video-id="Phr7ItAUcH0">Why is the Hub unique?</a></h3>
        <ol class="tags">
            <li><a href="/resources/?_topics=energy-efficiency">Energy Efficiency</a><li>
        </ol>
    </div>
</article>

Because I am just enhancing the card, there is no need to think about fallbacks. On browsers, that don’t support the :has selector, the functionality still works but with it enhanced there is a nice visual cue that the link on the thumbnail is the same as the heading.


Both of these are examples of ways that you can take advantage of newer CSS features that may not be as widely supported. I hope they can serve as examples for the future and equip you with strategies to take advantage of newer features to progressively enhance your interfaces knowing that not all browsers will support them.


I was inspired to write this post after reading Stephanie Eckels’s 2002 CSS Updates on 12 Days of Web and having a discussion with one of my teammates about using new CSS features.

Comments are closed.