Ever wanted to add slick scroll animations without JavaScript? In today’s post, we’re diving deep into how you can trigger animation purely with CSS, using modern browser APIs like @keyframes
, position: sticky
, and the lesser-known :has()
pseudo-class.
This is perfect for performance-minded developers or those working in JS-restricted environments (like email clients or AMP pages).
🧠 Category: Best fit →
frontend-lab
🚀 What You'll Learn
- How to create scroll-based effects like fade-in, slide-up, and zoom without any JavaScript
- When to use
position: sticky
vs Intersection Observer (JS) - Secrets of using
:has()
andscroll-timeline
(experimental) - Creative use of
@media (prefers-reduced-motion)
for accessibility
🔧 Prerequisites
You should already be comfortable with:
- CSS animations and transitions
- CSS positioning (
absolute
,sticky
, etc.) - Responsive design thinking
- Experimental features in DevTools
🔹 Step 1: Basic Page Layout Structure
We'll build a clean vertical scroll layout to host our animated elements.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Scroll Animation (CSS Only)</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<section class="section intro">
<h1>Scroll Down to Animate</h1>
</section>
<section class="section reveal-on-scroll">
<h2>This will fade in</h2>
<p>And slide up using CSS-only scroll animation.</p>
</section>
<section class="section reveal-on-scroll">
<h2>More Content</h2>
<p>This section uses a similar animation delay.</p>
</section>
</body>
</html>
🧠 What’s Happening Here?
- We use multiple
<section>
blocks to simulate a scrolling page. .reveal-on-scroll
is the class that will be animated as it enters view.
Want to style this layout beautifully? Check out our Frontend Lab tutorials for design tips.
🔹 Step 2: Set Up the Initial CSS Layout
We'll define base styles and set up the scrollable layout with enough height spacing.
/* style.css */
body {
margin: 0;
font-family: system-ui, sans-serif;
background: #f8f9fa;
color: #333;
scroll-behavior: smooth;
}
.section {
padding: 100px 20px;
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.intro {
background: #333;
color: #fff;
}
🧠 What’s Happening Here?
- Each section takes full viewport height (
100vh
) for vertical spacing. .intro
stands out with a dark background.- This layout creates enough space to observe scrolling changes visually.
🔹 Step 3: Add the Reveal Animation (with @keyframes)
Now we’ll define the animation logic for the .reveal-on-scroll
class using opacity
and transform
.
.reveal-on-scroll {
opacity: 0;
transform: translateY(50px);
transition: opacity 0.8s ease-out, transform 0.8s ease-out;
will-change: opacity, transform;
}
🧠 Why opacity
+ transform
?
- These are GPU-accelerated properties.
- They allow smooth transitions and are less layout-intensive.
Bonus:
will-change
tells the browser to optimize animation performance.
🔹 Step 4: Trigger Animation on Scroll (with :has()
or sticky
)
Now we use :has()
(currently supported in most modern browsers) to detect if a parent container is in a scrolled state.
/* Container wrapper for sticky detection */
body:has(.reveal-on-scroll.sticky-in-view) .reveal-on-scroll.sticky-in-view {
opacity: 1;
transform: translateY(0);
}
But we need to make .reveal-on-scroll
sticky so it can "stick" and trigger :has()
.
.reveal-on-scroll.sticky-in-view {
position: sticky;
top: 80vh;
}
⚠️ Important:
:has()
is not supported in all versions of Firefox yet, so this part is progressive enhancement.
🔹 Step 5: Animate on Scroll with Scroll Timeline (Optional + Experimental)
CSS now supports scroll-linked animation using scroll-timeline
(behind flags in some browsers).
@keyframes fadeInSlideUp {
from {
opacity: 0;
transform: translateY(40px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.reveal-on-scroll {
animation: fadeInSlideUp linear both;
animation-timeline: view();
animation-range: entry 20% cover 30%;
}
🧪 Note
This only works in browsers with support for Scroll-Linked Animations. You can enable them in Chrome Canary via DevTools > Experimental Features.
Curious about automating this detection with JS? Explore our automation & AI tutorials for hybrid approaches.
💡 Best Practices & Accessibility Tips
- ✅ Use
prefers-reduced-motion
media query for accessibility.
@media (prefers-reduced-motion: reduce) {
.reveal-on-scroll {
transition: none !important;
animation: none !important;
}
}
- ✅ Stick to
transform
andopacity
for performance. - ✅ Avoid layout-altering animations (e.g.,
width
,height
,top
,left
).
📈 SEO & Marketing Insight
Adding scroll animations can increase time-on-page, boost engagement, and enhance storytelling — especially for landing pages and product showcases. However, keep them minimal to avoid hurting performance, especially on mobile devices.
🧩 Wrapping It All Together
To see the full effect, you'll need to:
✨ Combine the above snippets into a working HTML + CSS file. Try adjusting the
top
value in sticky mode or tweaking keyframes for different effects.
Have fun experimenting with scroll magic powered entirely by CSS — no JavaScript needed!
🔄 Related Tutorials
- Animate Elements on Scroll Using Intersection Observer (JS)
- Responsive Design With CSS Grid
- Automate Scroll Animations with Python & HTML
🙌 Stay Connected with Tech Talker 360
👉 Have questions or want more scroll magic? Drop a comment or request your next CSS tutorial!
0 Comments