Sitemap
Pon.Tech.Talk

Here at Pon we have some great minds when it comes to everything Tech. What is information worth when it is not shared? Nothing. So we share with you our knowledge, experience, and insights. Contact one of writers if you want to know more.

Goodbye JavaScript, hello CSS?

5 min readSep 9, 2026

--

Press enter or click to view image in full size
Photo by Michael Dziedzic on Unsplash

As front-end developers we are constantly weighing interactive, beautiful user interfaces and maintaining performance standards. In the past, achieving both often meant relying on, often heavy, JavaScript libraries. Not anymore.

CSS has evolved at a blistering pace over the last few years. What used to require complex JavaScript, requestAnimationFrame loops, and complex DOM calculations can now be handled natively by the browser.

This post explores some of the most exciting new CSS functionalities such as sibling-index(), scroll-driven animations, animated gradients and the color-contrast() function. In this article you will get to know how they can dramatically improve both your application’s performance and accessibility, without taking a hit on accessibility or performance.

1. Scroll Driven Animations

We are all used to trigger animations based on a user’s scroll position by attaching event listeners to the window object with JavaScript. Doing so can hammer the performance of your website or application, resulting in clunky or laggy scrolling.

Introducing scroll-driven animations in CSS. By utilising animation-timeline we can connect an animation directly to the scroll progression of a scroll container (scroll()) or the visibility of an element within its scroller (view()). Because the browser handles this off the main thread, the result is an animation as smooth as butter.

The animation uses the scroll position of the user instead of a fixed duration. Therefore it is good to keep in mind that the animation will be shown in reverse when the user scrolls back up.

The scroll() value of animation-timeline is best used to track the scroll position of the whole page to animate progress bars (to indicate how much of an article has been read), parallax backgrounds or sticky headers.

You can use the view() value of animation-timeline to animate a specific element entering and leaving the viewport.

More information about the animation-timeline property and the browser support can be found on https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/animation-timeline

Please note this feature is not yet supported by Firefox.

2. Animated Gradients

For years, animating CSS gradients was impossible because the browser didn’t know how to interpolate (transition) between complex gradient strings. We had to use hacky workarounds like animating background-position on an oversized background to get a (somewhat) working example.

With the introduction of CSS Houdini’s @property rule, we can explicitly define custom properties (CSS variables) with a specific type (syntax). By telling the browser that a variable is an <angle>, it knows exactly how to smoothly animate it from 0deg to 360deg.

More information and examples can be found on https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@property

Get Chris de Groot’s stories in your inbox

Join Medium for free to get updates from this writer.

A note on accessibility: Continuous movement can trigger motion sickness or vestibular disorders. Always respect user system preferences by disabling or slowing down infinite animations using the prefers-reduced-motion media query (as included in the example). For more information on prefers-reduced-motion please have a look at https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@media/prefers-reduced-motion

3. Staggered Animations

Have you ever tried to create a staggered animation (e.g. where a list of items fades in one by one) without JavaScript? We used to rely on writing lots of :nth-child(n) selectors or using Sass loops to calculate animation-delay values.

The introduction of sibling-index() and sibling-count() in CSS changes everything. These functions allow an element to know its exact position among its siblings, enabling dynamic styling based on the DOM structure natively.

How it works

You can use sibling-index() to calculate an animation delay dynamically.

.list-item {
opacity: 0;
animation: fade-in 0.5s ease forwards;
/* Calculate delay dynamically based on index! */
animation-delay: calc(sibling-index() * 0.1s);
}

@keyframes fade-in {
to { opacity: 1; }
}

This keeps your CSS DRY (Don’t Repeat Yourself) and your HTML structure decoupled from your styling logic. It’s robust, performant, and it scales no matter how many elements you have.

The example below couples this new trick with the previously discussed @property:

More information can be found via the following link: https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/sibling-index

4. Adaptive Design

For years, web developers have wrestled with a common accessibility issue: how do you ensure text remains readable when the background color changes dynamically?

If your app uses user-generated themes, light/dark mode toggles, or dynamic UI components, you previously had to rely on JavaScript or even PHP to calculate the appropriate text color or you had to limit users to a predefined set of colors. With the introduction of the contrast-color() property this is a thing of the past.

With contrast-color() the browser automatically calculates and returns the color with the highest visibility (highest contrast ratio) for a specified color in real-time. The function commonly ensures the WCAG AA minimum contrast.

.button {
background-color: var(--bg-color);
color: contrast-color(var(--bg-color));
}

Currently, contrast-color() works in the latest versions of all modern browsers. However, for projects that need to maintain compatibility with past browser environments, applying progressive enhancement using @supports is safe.

.card {
background-color: var(--bg-color);
color: #ffffff; /* Fallback color */
}

@supports (color: contrast-color(#000)) {
.card {
color: contrast-color(var(--bg-color));
}
}

Wrapping Up

As developers, our goal should always be to deliver the best possible experience to all users. By migrating functionality from JavaScript to native CSS, we get massive performance benefits: smaller bundle sizes, less calculations on the main thread and hardware-accelerated animations.

More importantly, features like color-contrast() and the ease of implementing prefers-reduced-motion alongside @property animations show that CSS is becoming fundamentally geared towards accessibility.

The web is evolving by prioritizing inclusivity and performance right out of the box. Will you use any of the new functionalities mentioned above, or do you use other new properties? Let us know via the comments section below!

--

Pon.Tech.Talk
Pon.Tech.Talk

Published in Pon.Tech.Talk

Here at Pon we have some great minds when it comes to everything Tech. What is information worth when it is not shared? Nothing. So we share with you our knowledge, experience, and insights. Contact one of writers if you want to know more.