New CSS features I Like most
In the last few years there are a lot of new CSS features I want to talk about. Most of them are strongly supported, but it would be a nice approach to always make some reasonable fallbacks…
Animation timeline
animation-timeline is a new CSS property that allows you to specify the timeline for an animation.
It is useful for creating smooth animations that are not affected by the scroll position.
Imho most useful values are view() (when it gets into the view) and scroll() (based on the
scrolling position). It can pretty easily remove the need of usin IntersectionObserver API!
.scroll-progress {
animation: scroll-progress linear both;
animation-timeline: scroll(root block);
}
@keyframes scroll-progress {
from {
transform: scaleY(0);
}
to {
transform: scaleY(1);
}
}
Output of this code you can see in the Table of contents in the top right corner of this site, if you are not on the phone.
Scroll target group
scroll-target-group is a new CSS property that allows you to group elements that are linked to the
same target. This is how I realized the active state in the Table of contents in the top right
corner of this site if you are not on the phone :-)
@supports (scroll-target-group: auto) {
nav.toc {
scroll-target-group: auto;
a:target-current {
opacity: 1;
color: var(--color-link-active-rgb);
}
}
}
View transitions
view-transition is a new CSS property that allows you to create transitions between different
views. The most simple way to use it is to add the following to your CSS: it will automatically
animate the page when you navigate to a new page with a nice smooth fade in and fade out (as you can
see on my website).
@view-transition {
navigation: auto;
}
Starting style
@starting-style is a very powerfull feature! Everytime when the element is going to be rendered,
you can show some nice cool animation!
sibling-index is a new CSS function that returns the index of the current element in its parent.
It is useful for nice smooth animations. A real life example you can see in Notes - the
animated list of notes, or in Contact as animated form.
You can wind here usage of sibling-index() - and here is even sibling-count()…
@starting-style: MDN,
CanIUse,
sibling-index(): MDN,
CanIUse.
.in-animation {
transition:
opacity 0.5s ease,
transform 0.5s ease;
transition-delay: calc(sibling-index() * 50ms);
@starting-style {
opacity: 0;
transform: translateY(-20px);
}
}
Corner shape
corner-shape is a new CSS property that allows you to specify the shape of the corners of an
element.
.box {
border-radius: 1.2rem;
corner-shape: squircle;
}
vs.
Show DEMO code
<button class="btn">corner-shape: squircle;</button> or.<button class="message btn">
click/hover me!
</button>
.btn {
padding: 2rem 4rem;
margin: 2rem;
background: orange;
border: 3px solid saddlebrown; /*to demonstrate shape change*/
transition: all 0.2s ease;
&:not(.message) {
border-radius: 2rem;
corner-shape: squircle;
}
}
.message {
border-radius: 1rem;
anchor-name: --card;
&::before {
scale: 0;
content: "1";
position: absolute;
position-anchor: --card;
position-area: top right;
translate: -50% 50%;
background: firebrick;
color: white;
height: 2.5rem;
width: 2.5rem;
transition: all 0.2s ease;
border-radius: 50%;
}
/*not hover, cause of mobile devices*/
&:focus,
&:hover {
border-top-right-radius: 2rem;
corner-top-right-shape: scoop;
&::before {
scale: 1;
}
}
}
Layer
@layer is a new CSS at-rule that allows you to group CSS rules into different layers. It is useful
for organizing your CSS code - or while refactoring the old design of the app. It helps to “break
the competition” between different CSS files.
@import "props/colors" layer(base);
@layer base {
body {
font-family: "Noto Sans Mono", monospace;
color: var(--color-text); /* <- from props/colors; ONLY inside @layer base */
}
}
Dark/Light mode switching
@light-dark is a thing I like, but I am not using it on this web, because I have a little
different approach here, already. It is a new CSS at-rule that allows you to define different styles
for light and dark themes.
:root {
--color-text: light-dark(#ffffff, #000000);
}
html {
&:has(#darkMode:checked) {
color-scheme: dark;
}
}
New color models
oklch() is a new CSS function that converts a color from sRGB to the OKLAB color space. It is
useful for creating color palettes. I strongly recommend paying attention to these new color
formats - it’s a very strong tool. Here is a lot of options: lch(), oklch(), lab(), oklab(),
rgb(), rgba(), hsl(), hsla(), hwb(), hwba(), color()…
--primary-color: red;
.red-element {
color: oklch(from var(--primary-color) calc(l - 0.25) c h); //little darker red
background-color: oklch(from var(--primary-color) l c h / 50%); //-> rgba(255, 0, 0, 0.5)
}
Color mixing
color-mix() allows you to mix two colors together. Here is actualy a lot of new CSS functions that
can make the code more clean and readable… you should check them out!
.color-mix {
background-color: color-mix(in oklab, var(--color-primary), transparent 50%);
color: color-mix(
in oklab,
var(--color-primary) 90%,
color-mix(in oklab, var(--color-secondary), black 50%)
);
}
Details tag
Yes - this was one of my first experiments with jQuery back in the days. It is a new element that allows you to create a collapsible section - without JS! Real implementation is a bit tricky, the browser using shadow elements, but here is a way how to animate it properly :-)
DEMO:
Click me
I am a collapsible section 01
Click me
I am a collapsible section 02
Click me
I am a collapsible section 03
Show DEMO code
<details name="accordion">
<summary>Click me</summary>
<p>I am a collapsible section 01</p>
</details>
<details name="accordion">
<summary>Click me</summary>
<p>I am a collapsible section 02</p>
</details>
<details name="accordion">
<summary>Click me</summary>
<p>I am a collapsible section 03</p>
</details>
:root {
interpolate-size: allow-keywords; /*we want to use keywords in the CSS */
}
details {
overflow: hidden;
&[name="accordion"] {
&::details-content {
height: 0;
transition:
height 0.2s,
content-visibility 0.2s;
transition-behavior: allow-discrete;
}
&[open]::details-content {
height: auto;
}
}
* {
margin: 0;
}
}
transition-behavior: allow-discrete; enables transitions for otherwise non-animatable properties likedisplay. On close, the visual transition (e.g. shrinkingheightto 0) runs first, and the element is only hidden (display: none) after the transition completes.
MDN, CanIUse.
interpolate-size: allow-keywords;means that we can use keywords in the CSS - likeheight: auto- and the browser will interpolate the value -> we can animate it!
MDN, CanIUse.
Text trimming
text-box-trim is a solution on a problem we once had in our company - it was almost impossible to
make a proper placing of the font inside the element (without JS). It is a new CSS property that
allows you to trim the text inside the element - and solve the problem in ONE LINE OF CSS!