{}const=>[]async()letfn</>var
Development

Animations without JS: CSS already knows everything

New CSS features allow you to create complex animations without JavaScript. Let's analyze what has changed and how to use it.

К

Kodik

Author

3 min read

Until recently, "scrolling appearance" or "switching between screens" meant event handlers and a bunch of JS code. Today, browser engines take over the render, and we describe the intention in CSS. Pros: fewer dependencies, smoothness at the composer level, more understandable performance limitations.

🚀 Scroll-linked animations: @scroll-timeline

We link the progress of the animation with scrolling. The browser itself gives the "timeline" — it remains to attach keyframes to it.

@scroll-timeline fade-tl {
  source: auto;               /* ближайший скроллируемый контейнер */
  orientation: block;         /* по оси прокрутки */
  scroll-offsets: 0%, 100%;   /* начало/конец */
}

.section__item{
  animation: fade-in 1s both linear;
  animation-timeline: fade-tl;        /* ← магия */
  animation-range: entry 0% cover 60%;/* когда и как играться */
}

@keyframes fade-in {
  from { opacity: 0; transform: translateY(24px); }
  to   { opacity: 1; transform: translateY(0); }
}

Where to use: the appearance of cards, parallax, reading progress bar, sticky section headings.

🔥 100,000+ students already with us

Tired of reading theory?
Time to code!

Kodik — an app where you learn to code through practice. AI mentor, interactive lessons, real projects.

🤖 AI 24/7
🎓 Certificates
💰 Free
🚀 Start learning
Joined today

🔁 View Transitions API — "overflows" between states

Native transitions between pages/states without manual synchronization. JS starts the transaction, CSS executes it.

/* CSS */
::view-transition-old(root),
::view-transition-new(root){
  animation: fade .35s ease;
}

@keyframes fade {
  from { opacity: .001 }
  to   { opacity: 1 }
}

/* JS (одна строка в обработчике) */
// document.startViewTransition(() => router.navigate('/about'));

Feature: you can name elements through view-transition-name and make a "transition" of specific blocks (hero image, title).

📦 Container Queries + animations

Components respond to the width/height of the parent, not the entire viewport. You can smoothly "reassemble" the card when changing the area.

.card{
  container-type: inline-size; /* объявили контейнер */
}

@container (min-width: 520px){
  .card__media{ inline-size: 280px }
  .card__body{ animation: grow .4s ease }
}

@keyframes grow{
  from{ transform: scale(.96) }
  to  { transform: scale(1) }
}

🧲 :has() state selector without JS

The parent's reaction to the state/presence of child elements is a trigger for animation.

.accordion:has(input:checked) .accordion__panel{
  grid-template-rows: 1fr;          /* раскрываем */
  transition: grid-template-rows .3s ease;
}
.accordion:not(:has(input:checked)) .accordion__panel{
  grid-template-rows: 0fr;          /* скрываем */
}
.card:has(:hover){ transform: rotate(1.5deg) scale(1.03); transition:.25s }

🧩 Individual transform properties and animation composition

Instead of the "big" transform, independent translate, scale, rotate are available. And the animation-composition property allows you to add effects.

.chip{
  translate: 0 8px;        /* читаемее и безопаснее */
  rotate: 1deg;
  transition: translate .25s ease, rotate .25s ease;
}
.chip:hover{ translate: 0 0; rotate: 0deg }

.pulse{ animation: pulse 1.2s infinite ease; }
.float{ animation: float 3s infinite ease alternate; }
.pulse, .float{ animation-composition: add; } /* суммируем эффекты */

@keyframes pulse{ from{scale:1} 50%{scale:1.04} to{scale:1} }
@keyframes float{ from{translate:0 0} to{translate:0 -8px} }

📊 Before/After

Task

Earlier (JS)

Now (CSS)

Appearance when scrolling

Scroll handler, classes

@scroll-timeline, animation-range

Parallax

Wiretapping, miscalculation of positions

Scroll‑timeline on the container

Navigation between pages

Manual synchronization

View Transitions

Reaction to the state

Events/class switching

:has() on parent

Composing effects

Complex timelines in JS

animation-composition: add;

CSS has grown to a level where most interface animations are created declaratively and run faster. Use @scroll-timeline, View Transitions, :has(), Container Queries, and individual transform properties — and leave JS where you need logic, not a render.

📚 Do you want to delve into the topic?

In the attachment Code you will find detailed lessons on various topics, step-by-step exercises, error analysis and convenient practice right on your phone or browser.

And if you want to be aware of the news, new features and useful materials - subscribe to our Telegram channel. It's cozy, businesslike and with love for code ❤️

💬 What effects have you already moved from JS to CSS and what has given the most return?

🎯Stop procrastinating

Liked the article?
Time to practice!

In Kodik, you don't just read — you write code immediately. Theory + practice = real skills.

Instant practice
🧠AI explains code
🏆Certificate

No registration • No card