Friday, April 26, 2024
HomeCSSCSS Fashion Queries - Ahmad Shadeed

CSS Fashion Queries – Ahmad Shadeed


For me, 2022 is the most effective yr ever for CSS. We bought quite a lot of new stuff supported in steady browsers and it’s identical to dwelling a dream. From CSS subgrid, :has selector, container queries, and the brand new viewport models. So many issues to understand, I perceive – however I’m certain we agree that that is thrilling, isn’t it?

Lately, the Chrome crew launched experimental assist for a brand new proposed CSS spec, fashion queries. In brief, they allow us to question the fashion of a container, slightly than the scale solely. This may be useful in circumstances the place querying the container measurement isn’t sufficient.

Let’s dig in.

Container measurement queries

Earlier than going into the small print of fashion queries, I wish to have a fast reminder of container measurement queries first. As a substitute of counting on the viewport measurement to alter the fashion of a part, we will merely question in opposition to the container measurement as a substitute.

Let’s check out an instance.

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

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

@container (min-width: 400px) {
  .c-article {
    /* The kinds that may make the article horizontal**
	** as a substitute of a card fashion.. */
  }
}

First, we have to outline container-type on the container itself. Then, we will use @container and begin querying. As soon as that situation is met, the CSS will apply to the part inside that container.

Introducing fashion queries

In easy phrases, fashion queries allow us to question a CSS property or CSS variable for a container.

Fashion queries are nonetheless experimental and at present are applied solely in Chrome Canary. To check them, go to chrome://flags and activate the “Experimental Internet Platform options” toggle.

As an example, we will verify if the container has show: flex and magnificence the kid based mostly on that.

.page-header {
  show: flex;
}

@container fashion(show: flex) {
  .page-header__start {
    flex: 1;
    show: flex;
    align-items: middle;
    border-right: 1px strong lightgrey;
  }
}

Ideally, the above ought to work, however the present fashion queries prototype in Chrome Canary is restricted to CSS variables solely. Fashion queries are anticipated to ship in Chrome M111.

For now, we will verify if the variable --boxed: true is added to the container and if sure, we will change the kid ingredient fashion based mostly on that.

Take into account the next determine.

Discover that the principle distinction between container queries and magnificence queries is that the primary question is for the scale and the latter question is for the fashion.

.card-container {
  --boxed: true;
}

@container fashion(--boxed: true) {
  .card {
    /* boxed kinds */
  }
}

The issue

Earlier than diving into the place we will use fashion queries, I need to emphasize the query: what do fashion queries resolve? Aren’t measurement queries sufficient already?

That’s a very good query to begin with. In measurement queries, we will management the styling of a part based mostly on its mother or father width, and that’s very helpful. In some circumstances, we’d not want to question the scale in any respect. As a substitute, we need to question the computed fashion of a container.

To offer you a greater thought, let’s have a look at the next determine.

That is an article physique that’s coming from a CMS. We’ve a default fashion for the determine and one other fashion that appears featured.

Right here is the HTML markup.

<determine>
  <img src="cheesecake.jpg" alt="" />
  <figcaption>....</figcaption>
</determine>
figcaption {
  font-size: 13px;
  padding: 4px 8px;
  background: lightgrey;
}

After we begin styling the featured one, we have to override the above and have a CSS class that we will fashion with.

.featured-figure {
  show: flex;
  flex-wrap: wrap;
}

.featured-figure figcaption {
  font-size: 16px;
  padding: 16px;
  border-left: 3px strong;
  margin-left: -6rem;
  align-self: middle;
}

Cool, that works. Can we do higher? Sure! With fashion queries, we will add show: flex or a CSS variable --featured: true to the determine, and magnificence based mostly on that.

<determine>
  <img src="cheesecake.jpg" alt="" />
  <figcaption>....</figcaption>
</determine>
determine {
  container-name: determine;
  --featured: true;
}

/* Featured determine fashion. */
@container determine fashion(--featured: true) {
  img {
    /* Customized styling */
  }

  figcaption {
    /* Customized styling */
  }
}

And if --featured: true isn’t there, we’ll default to the bottom determine design. We are able to use the not key phrase to verify when the determine doesn’t have show: flex.

/* Default determine fashion. */
@container determine not fashion(--featured: true) {
  figcaption {
    /* Customized styling */
  }
}

A number of particulars to know

Each ingredient is a method container by default

So there isn’t a must outline a method container in any respect. It’s there for you by default.

Can’t we resolve that with a category identify?

Sure, we will. The purpose of fashion queries is to make CSS extra readable and simpler to change. The above logic might be written as one part CSS with out including all these kinds to a conditional class.

Demo

Much less CSS specificity points

What I like about utilizing fashion queries is that it’ll scale back CSS specificity as a result of we’ll rely much less on CSS variation lessons or HTML knowledge attributes to fashion a part variation.

Within the following CSS, now we have a primary styling for a piece. Nothing fancy.

.part {
  background-color: lightgrey;
}

.section__title,
.section__desc {
  coloration: #222;
}

We’d like a option to have a unique theme for it, so we used a variation class.

.section--dark {
  background-color: #222;
}

.section--dark .section__title,
.section--dark .section__desc {
  coloration: #fff;
}

With fashion queries, we will use a container across the .part part, after which we tag the title and outline with out creating extra specificity in CSS.

@container fashion(--theme: darkish) {
  .part {
    background-color: #222;
  }

  .section__title,
  .section__desc {
    coloration: #fff;
  }
}

That appears a lot cleaner to me.

Let’s discover just a few use circumstances the place fashion queries might be useful.

Use circumstances & examples

Context-based styling

This can be a widespread use case the place now we have the identical part used in another way in the identical wrapper. Within the apart, now we have an article part which may embrace a quantity or not.

At present, we’d use a brand new CSS class to handle the styling, or possibly a variation class on the article part itself.

.most-popular {
  counter-reset: record;
}

.most-popular article {
  /* customized styling */
}

Or we’d use knowledge attributes within the HTML.

.most-popular[data-counter="true"] {
  counter-reset: record;
}

.most-popular[data-counter="true"] .article {
  /* customized styling */
}

With CSS fashion queries, we will add a CSS variable to the mother or father ingredient, and magnificence the article accordingly. Take a look at that:

.most-popular {
  --counter: true;
}

@container fashion(--counter: true) {
  .articles-list {
    counter-reset: record;
  }

  .article {
    show: flex;
    align-items: flex-start;
  }

  .article:earlier than {
    counter-increment: record;
    content material: counter(record);
  }
}

We don’t even must have a variation class on the article part. CSS nesting isn’t wanted, too.

Demo

Part-level theme switching

Some parts we constructed want a unique theme based mostly on particular situations. Within the following instance, now we have a dashboard with completely different stats parts.

Primarily based on the wrapper, we have to swap the theme of the part.

At present, we will fashion the customized stats part based mostly on their container with a particular class.

.special-wrapper .stat {
  background-color: #122c46;
}

.special-wrapper .stat__icon {
  background-color: #2e547a;
}

.special-wrapper .stat__title {
  background-color: #b3cde7;
}

The above isn’t unsuitable or dangerous in any respect, however it will increase the specificity as a result of we nested the CSS. Let’s discover how we will implement the above with fashion queries.

First, we have to outline a toggle on the particular wrapper. Then, we will verify if that toggle is lively, and magnificence the stat part accordingly.

.special-wrapper {
  --theme: darkish;
  container-name: stats;
}

@container stats fashion(--theme: darkish) {
  .stat {
    /* Add the darkish kinds. */
  }
}

What’s helpful about fashion queries in that context is that it’ll make sense to have the above fashion in a single place within the CSS.

/* stat.css */
.stat {
  /* default styling */
}

@container stats fashion(--theme: darkish) {
  .stat {
    /* customized styling */
  }
}

Article part

Dimension container queries are so highly effective, they supplied us with a option to question a part in opposition to its container. Right here is a well-liked instance from my article https://ishadeed.com/article/say-hello-to-css-container-queries/.

In CSS, we have to outline a measurement container, after which question the article part based mostly on that.

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

.c-article {
  /* Default card fashion */
}

/* Horizontal fashion */
@container (min-width: 400px) {
  .c-article {
    show: flex;
    flex-wrap: wrap;
  }
}

And the featured or hero fashion.

/* Featured/Hero fashion */
@container (min-width: 700px) {
  .c-article {
    show: flex;
    justify-content: middle;
    align-items: middle;
    min-height: 350px;
  }

  .card__thumb {
    place: absolute;
    inset: 0;
    object-fit: cowl;
  }
}

That’s very helpful. The place fashion queries can assist us? That’s an excellent query. In some circumstances, we is perhaps solely in making use of one fashion based mostly on the container measurement, and different kinds is perhaps conditional, or as per our want.

That is the place fashion queries turn out to be useful. We are able to mix a measurement and magnificence question for that objective.

Take into account the next CSS.

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

@container (min-width: 400px) and fashion(--featured: true) {
  /* Horizontal fashion */
}

That method, the horizontal fashion will solely work if the --horizontal variable is about to true on the container. You possibly can identify the variable and the worth as you would like, for instance --horizontal: please.

Within the determine, the container measurement is identical, however what differentiates them is that the one on the fitting has --horizontal: true

Demo

Group of avatars

On this instance, now we have a bunch of consumer avatars. We have to lay them out in another way based mostly on a CSS variable that’s set on the mother or father. I picked that instance from the Atlassian design system.

Take into account the next determine.

<div class="avatars-wrapper">
  <div class="avatars-list">
    <div class="avatar"></div>
    <!-- extra avatars -->
  </div>
</div>

In CSS, I added a reputation to the container and outlined the --appearance: default variable;

.avatars-wrapper {
  container-name: avatars;
}

.avatars-list {
  show: flex;
  flex-wrap: wrap;
  hole: 0.25rem;
}

With that, we will use fashion queries to alter the structure based mostly on the --appearance variable.

@container avatars fashion(--appearance: stack) {
  .avatar {
    box-shadow: 0 0 0 2px #fff;
  }

  .avatar + .avatar {
    margin-inline-start: -0.5rem;
  }
}

@container avatars fashion(--appearance: grid) {
  .avatars-list {
    hole: 0.5rem;
    max-width: 200px;
  }
}

I think about this type of logic inside a design system. So useful and clear (my opinion, simply saying).

Demo

Conditional ornamental kinds

In some situations, we’d want so as to add a conditional ornamental fashion to textual content parts, based mostly on the place they’re within the HTML.

Take into account the next determine:

The heading and paragraph have a rotated background impact beneath them. That is accomplished through a pseudo-element.

<div class="content material">
  <h2><!-- Title right here --></h2>
  <p><!-- Description --></p>
</div>

To fashion them, we will use a CSS variable and verify if it’s toggled or not, and add the kinds accordingly. Within the instance, the :after pseudo-element is added to each baby of the .content material container.

.content material {
  --decorated: true;
}

@container fashion(--decorated: true) {
  :after {
    content material: "";
    place: absolute;
    inset: 0;
    background-color: var(--dec-color, inexperienced);
    opacity: 0.1;
    z-index: -1;
    rework: rotate(-1.5deg);
  }
}

Demo

RTL styling: Card part

When writing RTL kinds, step one is so as to add dir=rtl to the <html> ingredient. As soon as that’s added, the path CSS property for each ingredient will turn out to be path: rtl.

With the rise of logical properties, we don’t must do a whole rewrite of the CSS. Take into account the next instance:

.merchandise {
  margin-inline-start: 1rem;
}

For left-to-right layouts, the above will compute to margin-left. And for right-to-left layouts, it will likely be margin-right. Cool, proper? However we nonetheless don’t have the logical CSS that may verify a gradient path.

Fashion queries can turn out to be useful for that drawback. Take into account the next instance:

We’ve a part that consists of two parts, each of which ought to change path based mostly on the doc:

  • The gradient: it’s going from left to proper for LTR layouts.
  • Arrow path: it’s pointing to the fitting.

The above can’t be managed with logical CSS. At present, we do one thing like this:

html[dir="rtl"] .card {
  background: linear-gradient(to left, ...);
}

html[dir="rtl"] .card__cta {
  rework: scaleX(-1);
}

With fashion queries, we will question the container and verify if the path is the same as rtl, and alter the kinds accordingly.

.card {
  --bg-angle: to proper;
  background: linear-gradient(var(--bg-angle), #5521c3, #5893eb);
}

@container card fashion(path: rtl) {
  .card {
    --bg-angle: to left;
  }

  .card__cta {
    rework: scaleX(-1);
  }
}

Please take into account that the present prototype of fashion queries doesn’t assist CSS properties throughout the fashion() question. Because of this, I used a CSS variable in my demo as a substitute.

I wrote an in-depth information about RTL styling in CSS, in case you have an interest.

Demo

Information modules

What makes me enthusiastic about exploring this use case is that it’s an actual drawback that I noticed on bbc.com. Initially, now we have the next information part.

Primarily based on its container, the styling ought to change a bit. Take into account the next determine:

Discover how the part now has two modifications:

  • A white background.
  • The title and outline container are padded from all sides.

Right here is how the CSS seems to be on BBC.com.

.media--padded {
  background: #fff;
}

.media--padded .media__content {
  padding: 0.75rem 0.75rem 3rem 0.75rem;
}

How we will resolve that through fashion queries? Merely, we’d like a option to inform the part that if you happen to reside inside this container, the cardboard fashion must be padded.

.special-container {
  --card--padded: true;
}

@container fashion (--card-padded: true) {
  .media {
    background: #fff;
  }

  .media__content {
    padding: 0.75rem 0.75rem 3rem 0.75rem;
  }
}

From the identical web site, I noticed one other potential use case. See the next determine:

There are two variations:

  • Textual content coloration is white.
  • The information part content material is padded.

The present CSS seems to be like this:

.module--reel p {
  coloration: white;
  font-size: 18px;
  margin-top: 10px;
  margin-bottom: 20px;
}

With fashion queries, it’s a unique story. No must duplicate any CSS. We simply must activate the CSS variables that we’d like.

.module--reel {
  /* The earlier fashion question will work simply high-quality. */
  --card--padded: true;
  --light-on-dark: true;
}

@container fashion (--card-padded: true) {
}

@container fashion (--light-on-dark: true) {
  p {
    coloration: white;
    font-size: 18px;
    margin-top: 10px;
    margin-bottom: 20px;
  }
}

That’s neat, proper?

Debug mode

In Sass pre-processor, we used to have a mixin that we inject into any CSS part or web page, and it’ll add CSS define to all baby parts.

@mixin debug {
  * {
    define: strong 1px purple;
  }
}

After which we will use the mixin like the next:

.some-element {
  @embrace debug;
}

With fashion queries, we will use a CSS variable for that which permit us to debug any part we’d like.

@container fashion(--debug: true) {
  * {
    define: strong 1px purple;
  }
}

.site-header {
  --debug: true;
}

Demo

Block hyperlinks is the best way of forcing a hyperlink to fill its mother or father, even when the precise hyperlink is a straightforward title.

Take into account the next instance.

“The “Learn extra” hyperlink within the card part is clickable, however we will enhance the consumer expertise by making your entire mother or father ingredient clickable as effectively.”

The draw back of a block hyperlink is that the textual content received’t be selectable, and in case now we have different hyperlinks (e.g: creator identify), it received’t work.

So why not toggle them based mostly on the cardboard container? That is the place fashion queries turn out to be useful.

.card {
  place: relative;
  container-name: card;
  --block-link: true;
}

@container card fashion(--block-link: true) {
  a:after {
    content material: "";
    place: absolute;
    inset: 0;
    define: strong 2px;
  }
}

Helpful, isn’t it?

Demo

Obtain card

In my container queries lab, I revealed an instance of a obtain card that adjustments based mostly on the container measurement. With fashion queries, we will make it even higher.

For instance, I need to change the cardboard fashion if the utmost width is 220px and the --card: true variable is accessible.

.download-wrapper {
  /* Defining the container identify and measurement */
  container: obtain / inline-size;
  --card: true;
}

@container obtain fashion(--card: true) and (max-width: 220px) {
  .c-download {
    flex-direction: column;
    align-items: middle;
    text-align: middle;
  }

  svg {
    order: -1;
  }
}

Demo

Outro

It was good to work on this text. I get pleasure from this type of work the place there’s a new CSS characteristic and my job is only doing intensive analysis on how we will use it.

CSS fashion queries are a strong addition to CSS. I can’t wait to see what others from the online neighborhood will do with them, too. Oh, and I can also’t resist the urge to create a brand new listing in iShadeed lab for fashion queries. Keep tuned!

If in case you have any suggestions or query, I’m on Mastodon on front-end.social/@shadeed9, and Twitter (@shadeed9) if you happen to’re nonetheless round.

Additional studying

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments