Blog
New CSS features in 2023
CSS made a lot of progress in 2022. Many new features were added, and existing ones were improved and made more usable. Working with CSS these days is exciting, and I have found my love for it again.
To keep an overview of what's new and what has changed, I will explain in detail in this blog post all you should know about the new CSS features in 2023.
Disclaimer:Ā the features I talk about in this blog post are not new in CSS in 2023; they will gain major browser support soon or already have it recently. This means they are usable without thinking about polyfills, and that's the real deal.
Table of Contents:
- Container Queries
- :focus-visible
- :has()
- subgrid
- accent-color
- Individual Transform Properties
- Sources
Container Queries
Container Queries allow us to modify an element and its behavior not based on the viewport size butĀ on the container it's within.
To use Container queries, you first have to define the container itself.
main {
container-type: inline-size;
}
Optionally you can also set the container-type
and define a container name all
at once.
main {
container: main / inline-size;
}
Next up, you have to write your container queries. This is possible by using several math operators. Using math operators in queries is also a great new addition!
The following query targets every paragraph inside our container with the name of main when the width of the container is greater or equal to 600px;
@container main (width >= 600px) {
p {
padding: 24px;
}
}
Here's another example on CodePen. If the container on the right is larger than 1200px, we make a grid out of the image and the text and position them next to each other.
CodePen - Container Queries Opens in new tabWhy do we need container queries when most of the layout changes can be done by listening to the viewport width? The answer isĀ context. Container Queries are such a perfect tool for components from whom we don't know beforehand in which context they will be used.
So we can define the appearance of our component based on the container width, and it adapts. No matter if this component is used in a header, a sidebar, or a modal, for example.
Another addition to container queries isĀ container query units. Container queries allow us to quickly implement responsive typography using container query units.
I've already written about responsive typography using clamp().
This is typically done by listening to viewport widths. However, with the addition of container query units, we can replace this now by listening to the container's width, height, inline size, block size, or the smaller or larger value of these.
Here's the spec for all the new units:Ā https://drafts.csswg.org/css-contain-3/#container-lengths Opens in new tab. It has yet to get full browser support, but container queries can be used in totally new ways if this lands.
Focus-visible
If you've been a web developer for a few years, chances are that your Project Manager or your Customers asked you to remove the "ugly" outlines around buttons when focused.
The following CSS achieves it:
button:focus {
outline: none;
}
Hint:Ā Never do that! Ā They are there for a reason Opens in new tab.
If you ever get asked that again, tell them there is now a better solution
:focus-visible
. This new pseudo-class
tells the browser when to show focus
rings based on heuristics.
This means it detects input modalities that require visible focus. So, for example, mouse users won't see them on click, but keyboard users will have them on tab.
This is an excellent addition to CSS, as it removes them for mouse users, who won't need it necessarily but keeps it for keyboard users, who heavily rely on it for accessibility reasons.
Try it out yourself:
CodePen - Focus-visible Opens in new tab:has()
:has()
is a new selector that, as the name says, gets applied styles if the
argument passed in matches at least one element. There are endless possibilities
for how to use this new selector. It opens up a lot of new ways to select an
element and apply styles to itĀ conditionally.
:has()
is one of the fourĀ functional pseudo-classesĀ along with :is()
,
:where()
, and :not()
, all of them can accept a selector list.
It's best explained by showcasing a lot of examples, so here we go:
/* selects the ul if it has a direct following li element */
ul:has(> li) {
margin-left: 1rem;
}
/* selects the a element if it has a direct following img element */
a:has(> img) {
border: 1px solid yellow;
}
/* selects the last li element if the ul element has li elements */
ul:has(li) li:last-child {
margin-bottom: 0;
}
:has()
can also be combined with the other pseudo-classes. And it enables us
to do logical operators like AND
and OR
.
/*
Selects the ul if it has a li element which has a direct a as a child
AND if it has a li which has a span as a direct child
*/
ul:has(li > a):has(li > span) {
color: lightblue;
}
/*
Selects the ul if it has a li element which has a direct a as a child
OR if it has a li which has a span as a direct child
*/
ul:has(li > a, li > span) {
color: lightblue;
}
/* Selects the section if it hasn't a direct child of h1, which has an h2 and a p as adjacent siblings */
section:not(:has(> h1 + h2 + p)) {
font-family: Times-New-Roman;
}
Yes, you could say that :has()
is aĀ parent selector. You can match an
ancestor element based on containing a specific descendant. But that's not all!
You can also target ascendant elements if the condition returns true on the initial selector. I've already shown that in the first example, but here are some more:
/*
Selects the p if the main has an h1 as a direct child, which is followed by an h2
AND if the main has an h2 as a direct child who is followed by an h3
AND if the main has an h3 as a direct child, which is followed by an h4
*/
main:has(> h1 + h2, > h2 + h3, > h3 + h4) p {
font-size: 2rem;
}
/* Selects the label inside a p element if the p contains a form control
that is required but not currently valid. */
p:has(:required:invalid) label {
color: red;
}
/* Selects the label inside any element if the element contains a form control
that is required but not currently valid. */
* :has(> label + :required:invalid) > label {
color: red;
}
The examples above are from
the fantastic blog post by Estelle Weyl Opens in new tab
and perfectly showcase theĀ usefulnessĀ of the :has()
selector.
This means :has()
is not solemnly a parent selector. It's aĀ relational
selector! As I said at the beginning, this new functional pseudo-class brings
endless possibilities. It's awesome. I'm under the impression that I haven't
even started to grasp the scope of what's possible now.
Subgrid
Before subgrid
existed, a grid inside another grid couldn't be aligned along
the tracks of the parent grid. Here's a CodePen with a grid inside another
grid:
Now with subgrid, you can tell the inner grid with
grid-template-columns: subgrid
that the columns should be aligned with the
ones of the parent.
Subgrids can be used without limitation downwards, so you can nest them endlessly as long as the parent has the grid property. This opens up many possibilities for defining grids; it's a beautiful addition!
Accent-Color
Styling form elements or adding the most minimalistic CSS changes were always a pain. You likely needed external libraries or packages to achieve that.
This changed recently with the introduction of accent-color Opens in new tab.
It allows you to set the accent-color
of user-interface controls.
It's currently usable on input type= "checkbox"
, input type= "radio"
,
input type="range"
, and <progress>
.
Here's a CodePen to showcase its usage of it:
CodePen - Accent-Color Opens in new tabIndividual Transform Properties
The transform
property was one of my favorite additions to CSS back when it
was introduced. I love to use it to create little animations and transitions.
It lets you define one or more transform functions at once. Here's an example:
.caption:hover {
transform: rotate(10deg), scale(1.2), translateX(-20px);
}
What happens here is that on hover
, our DOM element with the class of
.caption
will rotate by 10 degrees clockwise, will scale up to 1.2 of its
size, and will move 20px horizontally to the left.
Hi Friend!
If you enjoy my writings and learn something from them, you can consider to support me! One way of doing this is just as easy as buying me a Coffee!
Thanks so much! This means a lot to me and is a great way to support my work.
āļø Buy me a coffee āļøThere's one problem with it. If you want to change just one of the transform properties later on, like in a media or container query, you must write the whole definition again for all properties.
@media (min-width: 1200px) {
.caption:hover {
transform: rotate(10deg), scale(1.8), translateX(-20px);
}
}
We've just applied one change on the scale property but had to write it for all of them again. If we wouldn't, they would reset to the default.
But this is a thing of the past now! Introducing: individual transform properties.
scale()
, translate()
, and rotate()
can now be used individually without
having to define them inside a transform declaration. Very cool!
Here's our example from above with individual transform properties:
.caption:hover {
translate: -20px;
scale:1.2;
rotate: 10deg;
}
@media (min-width: 1200px) {
.caption:hover {
scale:1.8;
}
}
That's it for the new CSS features you can use in 2023! A lot of cool stuff landed in CSS and it's awesome to see it being improved continuously.
Sources
- State of CSS in 2022 - Adam Argyle Opens in new tab
- 2022 CSS Updates - Stephanie Eckles Opens in new tab
- Finer graind control over CSS transforms with individual transform properties - Bramus, L. David Baron Opens in new tab
- Container Queries - Stephanie Eckles Opens in new tab
- CSS Subgrid - Rachel Andrew Opens in new tab
- Standardizing Focus Styles with CSS Custom Properties - Stephanie Eckles Opens in new tab
- accent-color - mdn web docs Opens in new tab
- Level Up Your CSS Skills With The :has() Selector - Stephanie Eckles Opens in new tab
- CSS :has() - Estelle Weyl Opens in new tab
I hope you enjoyed this post and learned something new. If you have any questions, feel free to reach out to me via Email Opens in new tab.
If you want to support me, you can buy me a coffee. I would be very happy about it!
āļø Buy me a coffee āļøI wish you a wonderful day! Marco