For me, 2022 is the very best 12 months ever for CSS. We acquired plenty of new stuff supported in secure browsers and it’s similar 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 positive we agree that that is thrilling, isn’t it?
Just lately, the Chrome staff launched experimental assist for a brand new proposed CSS spec, type queries. Briefly, they allow us to question the type of a container, somewhat than the scale solely. This may be useful in circumstances the place querying the container dimension isn’t sufficient.
Let’s dig in.
Container dimension queries
Earlier than going into the main points of fashion queries, I want to have a fast reminder of container dimension queries first. As an alternative of counting on the viewport dimension to vary the type of a element, we are able to merely question towards the container dimension as an alternative.
Let’s check out an instance.
.o-grid__item {
container-type: inline-size;
}
.c-article {
}
@container (min-width: 400px) {
.c-article {
}
}
First, we have to outline container-type
on the container itself. Then, we are able to use @container
and begin querying. As soon as that situation is met, the CSS will apply to the element inside that container.
Introducing type queries
In easy phrases, type queries allow us to question a CSS property or CSS variable for a container.
Fashion queries are nonetheless experimental and at present are carried out solely in Chrome Canary. To check them, go to chrome://flags and activate the “Experimental Internet Platform options” toggle.
As an example, we are able to verify if the container has show: flex
and magnificence the kid primarily based on that.
.page-header {
show: flex;
}
@container type(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 type queries prototype in Chrome Canary is restricted to CSS variables solely. Fashion queries are anticipated to ship in Chrome M111.
For now, we are able to verify if the variable --boxed: true
is added to the container and if sure, we are able to change the kid ingredient type primarily based on that.
Take into account the next determine.
Discover that the primary distinction between container queries and magnificence queries is that the primary question is for the scale and the latter question is for the type.
.card-container {
--boxed: true;
}
@container type(--boxed: true) {
.card {
}
}
The issue
Earlier than diving into the place we are able to use type queries, I need to emphasize the query: what do type queries clear up? Aren’t dimension queries sufficient already?
That’s an excellent query to start out with. In dimension queries, we are able to management the styling of a element primarily based on its father or mother width, and that’s very helpful. In some circumstances, we would not want to question the scale in any respect. As an alternative, we need to question the computed type of a container.
To present 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 now have a default type for the determine and one other type 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 are able to type 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 type queries, we are able to add show: flex
or a CSS variable --featured: true
to the determine, and magnificence primarily based on that.
<determine>
<img src="cheesecake.jpg" alt="" />
<figcaption>....</figcaption>
</determine>
determine {
container-name: determine;
--featured: true;
}
@container determine type(--featured: true) {
img {
}
figcaption {
}
}
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
.
@container determine not type(--featured: true) {
figcaption {
}
}
A couple of particulars to know
Each ingredient is a mode container by default
So there is no such thing as a must outline a mode container in any respect. It’s there for you by default.
Can’t we clear up that with a category title?
Sure, we are able to. The purpose of fashion queries is to make CSS extra readable and simpler to switch. The above logic might be written as one element CSS with out including all these kinds to a conditional class.
Much less CSS specificity points
What I like about utilizing type queries is that it’ll cut back CSS specificity as a result of we’ll rely much less on CSS variation courses or HTML knowledge attributes to type a element variation.
Within the following CSS, now we have a primary styling for a piece. Nothing fancy.
.part {
background-color: lightgrey;
}
.section__title,
.section__desc {
shade: #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 {
shade: #fff;
}
With type queries, we are able to use a container across the .part
element, after which we tag the title and outline with out creating extra specificity in CSS.
@container type(--theme: darkish) {
.part {
background-color: #222;
}
.section__title,
.section__desc {
shade: #fff;
}
}
That appears a lot cleaner to me.
Let’s discover a couple of use circumstances the place type queries might be useful.
Use circumstances & examples
Context-based styling
It is a frequent use case the place now we have the identical element used in a different way in the identical wrapper. Within the apart, now we have an article element that may embody a quantity or not.
At present, we would use a brand new CSS class to deal with the styling, or perhaps a variation class on the article element itself.
.most-popular {
counter-reset: checklist;
}
.most-popular article {
}
Or we would use knowledge attributes within the HTML.
.most-popular[data-counter="true"] {
counter-reset: checklist;
}
.most-popular[data-counter="true"] .article {
}
With CSS type queries, we are able to add a CSS variable to the father or mother ingredient, and magnificence the article accordingly. Have a look at that:
.most-popular {
--counter: true;
}
@container type(--counter: true) {
.articles-list {
counter-reset: checklist;
}
.article {
show: flex;
align-items: flex-start;
}
.article:earlier than {
counter-increment: checklist;
content material: counter(checklist);
}
}
We don’t even must have a variation class on the article element. CSS nesting isn’t wanted, too.
Element-level theme switching
Some parts we constructed want a unique theme primarily based on particular circumstances. Within the following instance, now we have a dashboard with totally different stats parts.
Primarily based on the wrapper, we have to swap the theme of the element.
At present, we are able to type the customized stats element primarily based 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 flawed or dangerous in any respect, however it will increase the specificity as a result of we nested the CSS. Let’s discover how we are able to implement the above with type queries.
First, we have to outline a toggle on the particular wrapper. Then, we are able to verify if that toggle is lively, and magnificence the stat element accordingly.
.special-wrapper {
--theme: darkish;
container-name: stats;
}
@container stats type(--theme: darkish) {
.stat {
}
}
What’s helpful about type queries in that context is that it’ll make sense to have the above type in a single place within the CSS.
.stat {
}
@container stats type(--theme: darkish) {
.stat {
}
}
Article element
Measurement container queries are so highly effective, they supplied us with a option to question a element towards its container. Right here is a well-liked instance from my article on container queries.
In CSS, we have to outline a dimension container, after which question the article element primarily based on that.
.o-grid__item {
container-type: inline-size;
}
.c-article {
}
@container (min-width: 400px) {
.c-article {
show: flex;
flex-wrap: wrap;
}
}
And the featured or hero type.
@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 type queries will help us? That’s an excellent query. In some circumstances, we is perhaps solely in making use of one type primarily based on the container dimension, and different kinds is perhaps conditional, or as per our want.
That is the place type queries turn into useful. We are able to mix a dimension and magnificence question for that function.
Take into account the next CSS.
.o-grid__item {
container-type: inline-size;
--horizontal: true;
}
@container (min-width: 400px) and type(--horizontal: true) {
}
That means, the horizontal type will solely work if the --horizontal
variable is about to true
on the container. You may title the variable and the worth as you want, for instance --horizontal: please
.
Within the determine, the container dimension is identical, however what differentiates them is that the one on the correct has --horizontal: true
Group of avatars
On this instance, now we have a gaggle of person avatars. We have to lay them out in a different way primarily based on a CSS variable that’s set on the father or mother. 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>
</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 are able to use type queries to vary the structure primarily based on the --appearance
variable.
@container avatars type(--appearance: stack) {
.avatar {
box-shadow: 0 0 0 2px #fff;
}
.avatar + .avatar {
margin-inline-start: -0.5rem;
}
}
@container avatars type(--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).
Conditional ornamental kinds
In some eventualities, we would want so as to add a conditional ornamental type to textual content components, primarily based 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></h2>
<p></p>
</div>
To type them, we are able to 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 type(--decorated: true) {
:after {
content material: "";
place: absolute;
inset: 0;
background-color: var(--dec-color, inexperienced);
opacity: 0.1;
z-index: -1;
remodel: rotate(-1.5deg);
}
}
RTL styling: Card element
When writing RTL kinds, step one is so as to add dir=rtl
to the <html>
ingredient. As soon as that’s added, the course
CSS property for each ingredient will turn into course: 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, will probably be margin-right
. Cool, proper? However we nonetheless don’t have the logical CSS that may verify a gradient course.
Fashion queries can turn into helpful for that downside. Take into account the next instance:
We now have a element that consists of two components, each of which ought to change course primarily based on the doc:
- The gradient: it’s going from left to proper for LTR layouts.
- Arrow course: it’s pointing to the correct.
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 {
remodel: scaleX(-1);
}
With type queries, we are able to question the container and verify if the course
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 type(course: rtl) {
.card {
--bg-angle: to left;
}
.card__cta {
remodel: scaleX(-1);
}
}
Please remember the fact that the present prototype of fashion queries doesn’t assist CSS properties inside the type()
question. In consequence, I used a CSS variable in my demo as an alternative.
I wrote an in-depth information about RTL styling in CSS, in case you have an interest.
Information modules
What makes me enthusiastic about exploring this use case is that it’s an actual downside that I noticed on bbc.com. Initially, now we have the next information element.
Primarily based on its container, the styling ought to change a bit. Take into account the next determine:
Discover how the element now has two modifications:
- A white background.
- The title and outline container are padded from all sides.
Right here is how the CSS appears on BBC.com.
.media--padded {
background: #fff;
}
.media--padded .media__content {
padding: 0.75rem 0.75rem 3rem 0.75rem;
}
How we are able to clear up that through type queries? Merely, we’d like a option to inform the element that in case you dwell inside this container, the cardboard type must be padded.
.special-container {
--card--padded: true;
}
@container type (--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 shade is white.
- The information element content material is padded.
The present CSS appears like this:
.module--reel p {
shade: white;
font-size: 18px;
margin-top: 10px;
margin-bottom: 20px;
}
With type queries, it’s a unique story. No must duplicate any CSS. We simply must activate the CSS variables that we’d like.
.module--reel {
--card--padded: true;
--light-on-dark: true;
}
@container type (--card-padded: true) {
}
@container type (--light-on-dark: true) {
p {
shade: 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 element or web page, and it’ll add CSS define
to all baby components.
@mixin debug {
* {
define: strong 1px purple;
}
}
After which we are able to use the mixin like the next:
.some-element {
@embody debug;
}
With type queries, we are able to use a CSS variable for that which permit us to debug any element we’d like.
@container type(--debug: true) {
* {
define: strong 1px purple;
}
}
.site-header {
--debug: true;
}
Block hyperlink card
Block hyperlinks is the best way of forcing a hyperlink to fill its father or mother, even when the precise hyperlink is an easy title.
Take into account the next instance.
“The “Learn extra” hyperlink within the card element is clickable, however we are able to enhance the person expertise by making the complete father or mother 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 title), it received’t work.
So why not toggle them primarily based on the cardboard container? That is the place type queries come in useful.
.card {
place: relative;
container-name: card;
--block-link: true;
}
@container card type(--block-link: true) {
a:after {
content material: "";
place: absolute;
inset: 0;
define: strong 2px;
}
}
Helpful, isn’t it?
Obtain card
In my container queries lab, I printed an instance of a obtain card that modifications primarily based on the container dimension. With type queries, we are able to make it even higher.
For instance, I need to change the cardboard type if the utmost width is 220px and the --card: true
variable is on the market.
.download-wrapper {
container: obtain / inline-size;
--card: true;
}
@container obtain type(--card: true) and (max-width: 220px) {
.c-download {
flex-direction: column;
align-items: middle;
text-align: middle;
}
svg {
order: -1;
}
}
Outro
It was good to work on this text. I take pleasure in this type of work the place there’s a new CSS function and my job is solely doing intensive analysis on how we are able to use it.
CSS type queries are a robust addition to CSS. I can’t wait to see what others from the net 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 type queries. Keep tuned!
When you’ve got any suggestions or query, I’m on Mastodon on front-end.social/@shadeed9, and Twitter (@shadeed9) in case you’re nonetheless round.