Wednesday, August 14, 2024
HomeProgramming“Good” Layouts With Container Queries

“Good” Layouts With Container Queries


Trendy CSS retains giving us a whole lot of new, simpler methods to unravel outdated issues, however typically the brand new options we’re getting don’t solely resolve outdated issues, they open up new potentialities as properly.

Container queries are a kind of issues that open up new potentialities, however as a result of they give the impression of being loads just like the outdated method of doing issues with media queries, our first intuition is to make use of them in the identical method, or no less than a really related method.

Once we try this, although, we aren’t benefiting from how “good” container queries are when in comparison with media queries!

Due to how essential media queries have been for ushering within the period of responsive net design I don’t wish to say something imply about them… however media queries are dumb. Not dumb when it comes to the idea, however dumb in that they don’t know very a lot. In actual fact, most individuals assume that they know greater than they do.

Let’s use this easy instance as an example what I imply:

html {
  font-size: 32px;
}

physique {
  background: lightsalmon;
}

@media (min-width: 35rem) {
  physique {
    background: lightseagreen;
  }
}

What would the viewport dimension be for the background colour to vary? Should you stated 1120px vast — which is the product of multiplying 35 by 32 for many who didn’t trouble doing the maths — you aren’t alone in that guess, however you’d even be flawed.

Keep in mind once I stated that media queries don’t know very a lot? There are solely two issues they do know:

  • the dimensions of the viewport, and
  • the browser’s font dimension.

And once I say the browser’s font dimension, I don’t imply the basis font dimension in your doc, which is why 1120px within the above instance was flawed.

The font dimension they take a look at is the preliminary font dimension coming from the browser earlier than any values, together with the consumer agent types, are utilized. By default, that’s 16px, although customers can change that of their browser settings.

And sure, that is on goal. The media question specification says:

Relative size items in media queries are primarily based on the preliminary worth, which implies that items are by no means primarily based on outcomes of declarations.

This would possibly seem to be a wierd choice, but when it didn’t work that method, what would occur if we did this:

html {
  font-size: 16px;
}

@media (min-width: 30rem) {
  html {
    font-size: 32px;
  }
}

If the media question appeared on the root font-size (like most assume it does), you’d run right into a loop when the viewport would get to 480px vast, the place the font-size would go up in dimension, then again down again and again.

Container queries are loads smarter

Whereas media queries have this limitation, and for good motive, container queries don’t have to fret about this kind of drawback and that opens up a whole lot of fascinating potentialities!

For instance, let’s say we now have a grid that must be stacked at smaller sizes, however three columns at bigger sizes. With media queries, we kind of must magic quantity our solution to the precise level the place this could occur. Utilizing a container question, we will decide the minimal dimension we would like a column to be, and it’ll all the time work as a result of we’re wanting on the container dimension.

Meaning we don’t want a magic quantity for the breakpoint. If I need three columns with a minimal dimension of 300px, I do know I can have three columns when the container is 900px vast. If I did that with a media question, it wouldn’t work, as a result of when my viewport is 900px vast, my container is, as a rule, smaller than that.

However even higher, we will use any unit we would like as properly, as a result of container queries, in contrast to media queries, can take a look at the font dimension of the container itself.

To me, ch is ideal for this kind of factor. Utilizing ch I can say “when I’ve sufficient room for every column to be a minimal of 30 characters vast, I need three columns.”

We will do the maths ourselves right here like this:

.grid-parent { container-type: inline-size; }

.grid {
  show: grid;
  hole: 1rem;

  @container (width > 90ch) {
    grid-template-columns: repeat(3, 1fr);
  }
}

And this does work fairly properly, as you may see on this instance.

As one other bonus, because of Miriam Suzanne, I lately realized that you may embody calc() inside media and container queries, so as an alternative of doing the maths your self, you may embody it like this: @container (width > calc(30ch * 3)) as you may see on this instance:

A extra sensible use case

One of many annoying issues about utilizing container queries is having to have an outlined container. A container can not question itself, so we want an additional wrapper above the component we wish to choose with a container question. You possibly can see within the examples above that I wanted a container on the surface of my grid for this to work.

Much more annoying is once you need grid or flex kids to vary their format relying on how a lot area they’ve, solely to appreciate that this doesn’t actually work if the mother or father is the container. As an alternative of getting that grid or flex container be the outlined container, we find yourself having to wrap every grid or flex merchandise in a container like this:

<div class="grid">
  <div class="card-container">
    <div class="card">
  </div>
  <div class="card-container">
    <div class="card">
  </div>
  <div class="card-container">
    <div class="card">
  </div>
</div>
.card-container { container-type: inline-size; }

It’s not that unhealthy within the grand scheme of issues, however it’s form of annoying.

Besides there are methods round this!

For instance, when you’re utilizing repeat(auto-fit, ...) you can use the principle grid because the container!

.grid-auto-fit {
  show: grid;
  hole: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(min(30ch, 100%)), 1fr);
  container-type: inline-size;
}

Realizing that the minimal dimension of a column is 30ch, we will leverage that data to restyle particular person grid objects relying on what number of columns we now have:

/* 2 columns + hole */
@container (width > calc(30ch * 2 + 1rem)) { ... }

/* 3 columns + gaps */
@container (width > calc(30ch * 3 + 2rem)) { ... }

I’ve used this on this instance to vary the types of the primary little one in my grid primarily based on whether or not we now have one, two, or three columns.

And whereas altering the background colour of one thing is nice for demos, we will, in fact, do far more with this:

The draw back to this strategy

The one draw back I’ve discovered utilizing this strategy is that we will’t use customized properties for the breakpoints, which might actually enhance the DX of this.

That ought to ultimately change contemplating customized media queries are within the spec editor’s draft of the Media Queries Stage 5 specs, however its been in there for some time with no motion from any browsers, so it may be a very long time earlier than we will use them.

And whereas my opinion is that having customized properties for these would each make them extra readable and simpler to replace, it opens up sufficient potentialities that it’s nonetheless value it with out them.

What about flexbox?

With flexbox, the flex objects are what outline the format, so it’s somewhat unusual in that the sizes we apply on the objects are what are essential within the breakpoints.

It can nonetheless work, however there’s a massive situation that may come up when you do that with flexbox. Earlier than we take a look at the difficulty, here’s a fast instance of how we will get this working with flexbox:

.flex-container {
  show: flex;
  hole: 1rem;
  flex-wrap: wrap;

  container-type: inline-size;
}

.flex-container > * {
  /* full-width at small sizes */
  flex-basis: 100%;
  flex-grow: 1;

  /* when there's room for 3 columns together with hole */
  @container (width > calc(200px * 3 + 2rem)) {
    flex-basis: calc(200px);
  }
}

On this case, I used px to indicate it really works as properly, however you may use any unit there, as I did with the grid examples.

This would possibly seem like one thing you should use a media question for as properly — you should use the calc() in them too! — however this is able to solely work in a single if the mother or father has a width that matches the viewport width, which more often than not isn’t the case.

This breaks if the flex objects have padding

Lots of people don’t notice it, however the flexbox algorithm doesn’t take padding or borders under consideration, even when you change your box-sizing. When you have padding in your flex objects, you’ll mainly must magic quantity your solution to getting it to work.

Right here’s an instance the place I added some padding however I haven’t modified anything, and also you’ll discover a kind of awkward two-columns with one stretched on the underside layouts at one level:

Due to this, I do typically discover myself utilizing this kind of strategy extra typically with grid than flexbox, however there are undoubtedly conditions the place it may possibly nonetheless work.

Like earlier than, as a result of we’re conscious of what number of columns we now have, we will leverage that to make extra dynamic and fascinating layouts relying on the area out there for a given component, or parts.

Opening up some fascinating potentialities

I’ve solely began taking part in round with this kind of factor, and I’ve discovered that it’s opened up some new potentialities that we by no means had with media queries, and that makes me excited to see what else is feasible!

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments