惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
DataBreaches.Net
S
Schneier on Security
T
The Exploit Database - CXSecurity.com
Webroot Blog
Webroot Blog
AI
AI
P
Palo Alto Networks Blog
Attack and Defense Labs
Attack and Defense Labs
WordPress大学
WordPress大学
月光博客
月光博客
阮一峰的网络日志
阮一峰的网络日志
Spread Privacy
Spread Privacy
T
Tor Project blog
罗磊的独立博客
小众软件
小众软件
S
Security Affairs
酷 壳 – CoolShell
酷 壳 – CoolShell
量子位
Apple Machine Learning Research
Apple Machine Learning Research
T
Threatpost
NISL@THU
NISL@THU
博客园_首页
PCI Perspectives
PCI Perspectives
大猫的无限游戏
大猫的无限游戏
IT之家
IT之家
N
News and Events Feed by Topic
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Forbes - Security
Forbes - Security
博客园 - 叶小钗
D
Darknet – Hacking Tools, Hacker News & Cyber Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Last Week in AI
Last Week in AI
L
LINUX DO - 热门话题
T
Threat Research - Cisco Blogs
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
腾讯CDC
Security Latest
Security Latest
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
The Cloudflare Blog
A
About on SuperTechFans
爱范儿
爱范儿
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
TaoSecurity Blog
TaoSecurity Blog
宝玉的分享
宝玉的分享
G
GRAHAM CLULEY
雷峰网
雷峰网
F
Full Disclosure
I
Intezer
Cloudbric
Cloudbric
博客园 - 三生石上(FineUI控件)
U
Unit 42

Ahmad Shadeed

Better fluid sizing with round() Use Cases for Field Sizing The Basics of Anchor Positioning Item Flow CSS Relative Colors Balancing Text In CSS Should masonry be part of CSS grid? CSS display contents CSS Grid Areas CSS Cap Unit An Interactive Guide to CSS Container Queries CSS :has() Interactive Guide CSS Nesting UX in DevTools CSS Nesting Future CSS: State Container Queries Rebuilding a comment component with modern CSS Conditional CSS with :has and :nth-last-child CSS Text balancing with text-wrap:balance CSS Masking Do we need CSS flex-wrap detection? My CSS Wishlist Conditional CSS CSS Style Queries Inside the mind of a frontend developer: Article layout Inside the mind of a frontend developer: Hero section CSS container queries are finally here The CSS behind Figma First Look At The CSS object-view-box Property Learn CSS Subgrid CSS :has Parent Selector Aligning Content In Different Wrappers Flexbox Dynamic Line Separator Hello, CSS Cascade Layers Building UI Components With SVG and CSS A Deep CSS Dive Into Radial And Conic Gradients Defensive CSS Building Real-life Components: Facebook Messenger Conditional Border Radius In CSS CSS Container Query Units Aligning a Button Label Vertically Comparing Design Mockups To Code Result Using HSL Colors In CSS Custom Scrollbars In CSS Let CSS Container Queries For Designers The State of CSS Cross-Browser Development Overflow Issues In CSS Inspect Element As A Way To Increase Your Curiosity Handling Text Over Images in CSS Digging Into CSS Logical Properties Clipping Scrollable Areas On The inline-start Side Understanding Clip Path in CSS The Art of Building Real-life Components Handling Short And Long Content In CSS CSS Scroll Snap A Deep Dive Into CSS Grid minmax() CSS Variables 101 Finding The Root Cause of a CSS Bug Learn CSS centering How to detect browser support for Flexbox Gap CSS Mistakes While On Autopilot Digging Into the Flex Property Understanding CSS Multiple Backgrounds Aligning Logo Images in CSS Grid for layout, Flexbox for components Colors in CSS Thinking About The In-between Design Cases min(), max(), and clamp() CSS Functions Image Techniques On The Web Everything About Auto in CSS Learn Box Alignment Let Learn CSS Positioning Intrinsic Sizing In CSS CSS Grid Template Areas In Action Hiding Elements On The Web Creating a Variable Color Font From Scratch Building a Football Ticket With CSS and SVG Blending Modes in CSS CSS Variables With Inline Styles Implementing Dark Mode For My Website Rebuilding Apple Music Header in HTML & CSS Accessible Checkbox Layout Flickering On Browser Resize Enhancing The Clickable Area Size Custom Underlines with SVG Part 3: The Process of Implementing A UI Design From Scratch Part 2: The Process of Implementing A UI Design From Scratch Building An Old Nav Design CSS Flexbox: 5 Real World Use Cases I Used CSS Inline Flex For The First Time The Process of Implementing A UI Design From Scratch Common CSS Issues For Front-End Projects Handling Long and Unexpected Content in CSS How to Build Web Form Layouts With CSS Grid Grid Layout Ah-ha Moment Enhancing Our Components with CSS :empty Building Resizeable Components with Relative CSS Units CSS Writing Mode The Journey of Learning Front End Web Development on a Daily Basis
Say Hello To CSS Container Queries
Ahmad Shadeed · 2021-04-13 · via Ahmad Shadeed

The Layout Maestro

I spent years teaching CSS layout on this blog. I put everything I know into The Layout Maestro course: 70+ lessons and 150+ interactive examples that teach you how to think CSS layouts, not just memorize syntax.

Get the course

I haven’t been more excited for a CSS feature like I’m now in the past six years I spent as a front-end developer. The prototype of container queries is now available behind a flag in Chrome Canary. Thanks to efforts from smart people like Miriam Suzanne and other folks.

I remember seeing a lot of jokes about the support for CSS container queries, but they are finally there. In this article, I will walk you through why we need container queries, how they will make your life easier, and most importantly, you will achieve more powerful components and layouts.

If you’re excited as I am, let’s dig in. Are you ready?

A web page consists of different sections and components, and we make them responsive by using CSS media queries. There is nothing wrong with that, but it has limitations. For example, we can use a media query to show the minimal version of a component on mobile versus desktop.

Oftentimes, responsive web design is not about the viewport or the screen size. It’s about the container size. Consider the following example:

We have a very typical layout with a card component. It has two variations:

  • The stacked (see the aside)
  • The horizontal (see the main)

There are multiple ways for implementing that in CSS, but the most common one is like the following. We need to create a base component, and then make variations of it.

.c-article {
  /* The default, stacked version */
}

.c-article > * + * {
  margin-top: 1rem;
}

/* The horizontal version */
@media (min-width: 46rem) {
  .c-article--horizontal {
    display: flex;
    flex-wrap: wrap;
  }

  .c-article > * + * {
    margin-top: 0;
  }

  .c-article__thumb {
    margin-right: 1rem;
  }
}

Notice that we created the class .c-article--horizontal to handle the horizontal version of the component. If the viewport width is greater than 46rem, then the component should switch to the horizontal variation.

This isn’t bad, but somehow it makes me feels a bit limited. I want the component to respond to its parent width, not the browser viewport or screen size.

Consider that we want to use the default .c-card in the main section. What will happen? Well, the card will expand to the width of its parent and thus it will be too large. See the following figure:

This is a problem, and we can solve it with CSS container queries (Yay, finally). Before diving into them, let me give you a glimpse of the result we want.

We need to tell the component that if its direct parent width is greater than 400px, then it needs to switch to the horizontal style. Here is how the CSS will look like:

<div class="o-grid">
  <div class="o-grid__item">
    <article class="c-article">
      <!-- content -->
    </article>
  </div>
  <div class="o-grid__item">
    <article class="c-article">
      <!-- content -->
    </article>
  </div>
</div>
.o-grid__item {
  container-type: inline-size;
}

.c-article {
  /* The default style */
}

@container (min-width: 400px) {
  .c-article {
    /* The styles that will make the article horizontal**
        ** instead of a card style.. */
  }
}

How CSS container queries will help us?

Warning: the CSS container queries are only supported in Chrome Canary under an experiment flag for now.

With CSS container queries, we can solve the above problem and make a fluid component. That means, we can throw the component in a narrow parent and it will turn into the stacked version, or to throw it in a wide one and it will turn into the horizontal version. Again, All of them that is independent of the viewport width.

Here is how I imagine it.

The purple outline represents the parent width. Notice how when it gets bigger, the component adapts to that. Isn’t that awesome? This is the power of CSS container queries.

How container queries works

We can now experiment with container queries Chrome canary. To enable it, go to chrome://flags and search for “container queries”, then enable it.

The first step is to add the container-type property. Since a component will adapt based on its parent width, we need to tell the browser to only repaint the affected area, not the whole page. With the container-type property, we can let the browser know about that ahead of time.

The value inline-size means to respond to the parent’s width changes only.

<div class="o-grid">
  <div class="o-grid__item">
    <article class="c-article">
      <!-- content -->
    </article>
  </div>
  <div class="o-grid__item">
    <article class="c-article">
      <!-- content -->
    </article>
  </div>
  <!-- other articles.. -->
</div>
.o-grid__item {
  container-type: inline-size;
}

This is the first step. We defined the element .o-grid__item as a containment parent for the .c-article within it.

The next step is to add the styles we want to make container queries work.

.o-grid__item {
  container-type: inline-size;
}

@container (min-width: 400px) {
  .c-article {
    display: flex;
    flex-wrap: wrap;
  }

  /* other CSS.. */
}

The @container is the .o-grid__item element, and the min-width: 400px is the width of it. We can even take it further and add more styles. Here is a video of what can be achieved for the card component:

The styles we have in there are:

  1. The default, a card-like look.
  2. A horizontal card with a small thumbnail.
  3. A horizontal card with a large thumbnail.
  4. If the parent is too large, the style will a hero-like to indicate that it’s a featured article.

Let’s dig into use cases for CSS container queries.

Use cases for CSS container queries

Container queries and CSS grid auto-fit

For some cases, using auto-fit in CSS grid can lead to unexpected results. For example, a component will be too wide and its content is hard to read.

To give you a bit of context, here is a visual that shows the difference between auto-fit and auto-fill in CSS grid.

Notice that when auto-fit is used, the items expanded to fill the available space. However, in case of auto-fill, the grid items won’t grow and we will have a free space instead (The dotted item on the far right).

You might be thinking now, what this has to do with CSS container queries? Well, each grid item is a container, and when it’s expanded (AKA we’re using auto-fit), we need the component to change based on that.

<div class="o-grid">
  <div class="o-grid__item">
    <article class="c-article"></article>
  </div>
  <div class="o-grid__item">
    <article class="c-article"></article>
  </div>
  <div class="o-grid__item">
    <article class="c-article"></article>
  </div>
  <div class="o-grid__item">
    <article class="c-article"></article>
  </div>
</div>
.o-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  grid-gap: 1rem;
}

When we have four elements, the result should look something like this.

That will change when the number of articles is less, here is what will happen. The less item we have, the wider they will become. The reason is that auto-fit is used. The first one looks good, but the last two (2 per row, 1 per row) doesn’t look good as they’re too wide.

What if each article component changes based on its parent width? That way, we can get the benefit of auto-fit very well. Here is what we need to do:

If the grid item width is greater than 400px, then the article should switch to the horizontal style.

Here is how we can do this:

.o-grid__item {
  container-type: inline-size;
}

@container (min-width: 400px) {
  .c-article {
    display: flex;
    flex-wrap: wrap;
  }
}

Also, we want to display the article with a hero section if it’s the only item in the grid.

.o-grid__item {
  container-type: inline-size;
}

@container (min-width: 700px) {
  .c-article {
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 350px;
  }

  .card__thumb {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
}

That’s it. We have a component that responds to its parent width, and it can work under any context. Isn’t that awesome?

Check out the demo on CodePen.

Oftentimes, we need to tweak a component to make it work in small width containers like an <aside>.

A perfect fit for this is a newsletter section. When the width is small, we need its items to stack, and when there is enough space, we need them to spread horizontally.

As you see in the figure, we have a newsletter that lives in two different contexts:

  • An aside section
  • The main section

Without container queries, this isn’t possible until we have a variation class in CSS, for example, .newsletter--stacked or something.

I’m aware that we can force the items to wrap in case there is no enough space with flexbox, but that’s not enough. I need much more control to do things like:

  • Hide specific elements.
  • Make the button full-width.
.newsletter-wrapper {
  container-type: inline-size;
}

/* The default, stacked version */
.newsletter {
  /* CSS styles */
}

.newsletter__title {
  font-size: 1rem;
}

.newsletter__desc {
  display: none;
}

/* The horizontal version */
@container (min-width: 600px) {
  .newsletter {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }

  .newsletter__title {
    font-size: 1.5rem;
  }

  .newsletter__desc {
    display: block;
  }
}

Here is a video of the result.

Check out the Demo on CodePen.

I found pagination to be a good fit for using container queries. Initially, we can have “Previous” and “Next” buttons, then we can hide them and show the full pagination if there is enough space.

Consider the following figure.

To handle the states above, we need to work on the default style first (the stacked buttons), and then work on the other two states.

.wrapper {
  container-type: inline-size;
}

@container (min-width: 250px) {
  .pagination {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
  }

  .pagination li:not(:last-child) {
    margin-bottom: 0;
  }
}

@container (min-width: 500px) {
  .pagination {
    justify-content: center;
  }

  .pagination__item:not(.btn) {
    display: block;
  }

  .pagination__item.btn {
    display: none;
  }
}

Check out the Demo on CodePen.

Profile card

Here is another use case that is ideal for being used in multiple contexts. The small state works for small viewport sizes, and contexts like a sidebar. The larger can works for much bigger contexts like placing it within a 2-col grid.

.p-card-wrapper {
  container-type: inline-size;
}

.p-card {
  /* Default styles */
}

@container (min-width: 450px) {
  .meta {
    display: flex;
    justify-content: center;
    gap: 2rem;
    border-top: 1px solid #e8e8e8;
    background-color: #f9f9f9;
    padding: 1.5rem 1rem;
    margin: 1rem -1rem -1rem;
  }

  /* and other styles */
}

With that, we can see how the component words in different contexts without using a single media query.

Check out the Demo on CodePen.

Form Elements

I didn’t go deep into use-cases for forms yet, but the one that I got in mind is switching from labels from being horizontal to being stacked.

.form-item {
  container-type: inline-size;
}

.input-group {
  @container (min-width: 350px) {
    display: flex;
    align-items: center;
    gap: 1.5rem;

    input {
      flex: 1;
    }
  }
}

Try it yourself in the demo below. Check out the demo on CodePen.

Testing components

Now that we’ve explored a couple of use-cases where CSS container queries can be useful, how can we test a component? Thankfully, we can do that with the CSS resize property on the parent of the component.

.parent {
  container-type: inline-size;
  resize: horizontal;
  overflow: auto;
}

I learned about this technique from reading this great write-up by Bramus Van Damme.

The short answer is no. You can’t see something like @container (min-width: value). I think it’s just a matter of time and this will be supported.

Is it possible to provide a fallback?

Yes! Sure thing. It’s possible to provide a fallback in certain ways. Here are two great articles that explain how to do that:

Conclusion

I enjoyed learning about CSS container queries and playing with them in the browser. I know they’re not officially supported yet, but this is a great time to play with it in the browser.

As front-end developers, a part of our job is to test and help the folks who work on implementing such features. The more we test an experiment, the fewer problems we will see once this is supported in all major browsers.

Thank you for reading.

I wrote an ebook

I’m excited to let you know that I wrote an ebook about Debugging CSS.

If you’re interested, head over to debuggingcss.com for a free preview…