Scroll Reveal Section
A section whose blocks arrive as the reader scrolls to them — no JavaScript.
Why it is timed this way
The reasoning
Driven by animation-timeline: view() rather than a timer, so the motion follows the reader instead of firing once on load and being missed. The whole scroll-reveal category of JavaScript libraries exists to do this; CSS now does it natively, with no observer and no scroll listener. Browsers without it play the same animation on load, which is why the fallback matters more than the effect — a scroll-driven fade with no fallback leaves the content invisible.
9 elements move, the first at 0ms and the last starting at 320ms — the whole scene settles by 1220ms. Every bar below is one element's animation window.
The code
Everything the scene needs, in whichever format you ship. Entrances compile to@keyframesand hover states totransition, with a reduced-motion guard on both.
.scroll-section {
transform: translate3d(0px, 0px, 0);
width: 960px;
height: 480px;
transform-origin: 480px 184px;
}
.section-copy {
transform: translate3d(0px, 0px, 0);
height: 228px;
transform-origin: 296px 114px;
}
.aside {
transform: translate3d(0px, 0px, 0);
width: 232px;
height: 272px;
transform-origin: 116px 136px;
}
.row-1 {
transform: translate3d(0px, 0px, 0);
height: 32px;
background: #171a24;
border-radius: 18px;
transform-origin: 45px 36px;
}
.row-2 {
transform: translate3d(0px, 0px, 0);
height: 32px;
background: #171a24;
border-radius: 18px;
transform-origin: 45px 36px;
}
.row-3 {
transform: translate3d(0px, 0px, 0);
height: 32px;
background: #171a24;
border-radius: 18px;
transform-origin: 45px 36px;
}
.section-heading {
transform: translate3d(0px, 0px, 0);
height: 44px;
background: #00000000;
color: #eceef4;
font-size: 36px;
font-weight: 800;
animation: section-heading-anim 1220ms linear 0ms 1 both;
will-change: transform, opacity;
}
@keyframes section-heading-anim {
0% {
transform: translate3d(0px, 48px, 0);
opacity: 0;
animation-timing-function: ease-out;
}
57.38% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
100% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
}
@supports (animation-timeline: view()) {
.section-heading {
animation-timeline: view();
animation-range: entry 0% cover 40%;
}
}
.section-sub {
transform: translate3d(0px, 0px, 0);
height: 24px;
background: #00000000;
color: #98a1b5;
font-size: 17px;
font-weight: 500;
animation: section-sub-anim 1220ms linear 0ms 1 both;
will-change: transform, opacity;
}
@keyframes section-sub-anim {
0% {
transform: translate3d(0px, 48px, 0);
opacity: 0;
}
7.38% {
transform: translate3d(0px, 48px, 0);
opacity: 0;
animation-timing-function: ease-out;
}
64.75% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
100% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
}
@supports (animation-timeline: view()) {
.section-sub {
animation-timeline: view();
animation-range: entry 0% cover 40%;
}
}
.row-1-mark {
transform: translate3d(0px, 0px, 0);
width: 32px;
height: 32px;
background: #6366f1;
border-radius: 10px;
animation: row-1-mark-anim 1220ms linear 0ms 1 both;
will-change: transform, opacity;
}
@keyframes row-1-mark-anim {
0% {
transform: translate3d(0px, 48px, 0);
opacity: 0;
}
9.84% {
transform: translate3d(0px, 48px, 0);
opacity: 0;
animation-timing-function: ease-out;
}
67.21% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
100% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
}
@supports (animation-timeline: view()) {
.row-1-mark {
animation-timeline: view();
animation-range: entry 0% cover 40%;
}
}
.row-1-line {
transform: translate3d(0px, 0px, 0);
height: 10px;
background: #272c3a;
border-radius: 999px;
animation: row-1-line-anim 1220ms linear 0ms 1 both;
will-change: transform, opacity;
}
@keyframes row-1-line-anim {
0% {
transform: translate3d(0px, 48px, 0);
opacity: 0;
}
13.11% {
transform: translate3d(0px, 48px, 0);
opacity: 0;
animation-timing-function: ease-out;
}
70.49% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
100% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
}
@supports (animation-timeline: view()) {
.row-1-line {
animation-timeline: view();
animation-range: entry 0% cover 40%;
}
}
.row-2-mark {
transform: translate3d(0px, 0px, 0);
width: 32px;
height: 32px;
background: #22d3ee;
border-radius: 10px;
animation: row-2-mark-anim 1220ms linear 0ms 1 both;
will-change: transform, opacity;
}
@keyframes row-2-mark-anim {
0% {
transform: translate3d(0px, 48px, 0);
opacity: 0;
}
16.39% {
transform: translate3d(0px, 48px, 0);
opacity: 0;
animation-timing-function: ease-out;
}
73.77% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
100% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
}
@supports (animation-timeline: view()) {
.row-2-mark {
animation-timeline: view();
animation-range: entry 0% cover 40%;
}
}
.row-2-line {
transform: translate3d(0px, 0px, 0);
height: 10px;
background: #272c3a;
border-radius: 999px;
animation: row-2-line-anim 1220ms linear 0ms 1 both;
will-change: transform, opacity;
}
@keyframes row-2-line-anim {
0% {
transform: translate3d(0px, 48px, 0);
opacity: 0;
}
19.67% {
transform: translate3d(0px, 48px, 0);
opacity: 0;
animation-timing-function: ease-out;
}
77.05% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
100% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
}
@supports (animation-timeline: view()) {
.row-2-line {
animation-timeline: view();
animation-range: entry 0% cover 40%;
}
}
.row-3-mark {
transform: translate3d(0px, 0px, 0);
width: 32px;
height: 32px;
background: #6366f1;
border-radius: 10px;
animation: row-3-mark-anim 1220ms linear 0ms 1 both;
will-change: transform, opacity;
}
@keyframes row-3-mark-anim {
0% {
transform: translate3d(0px, 48px, 0);
opacity: 0;
}
22.95% {
transform: translate3d(0px, 48px, 0);
opacity: 0;
animation-timing-function: ease-out;
}
80.33% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
100% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
}
@supports (animation-timeline: view()) {
.row-3-mark {
animation-timeline: view();
animation-range: entry 0% cover 40%;
}
}
.row-3-line {
transform: translate3d(0px, 0px, 0);
height: 10px;
background: #272c3a;
border-radius: 999px;
animation: row-3-line-anim 1220ms linear 0ms 1 both;
will-change: transform, opacity;
}
@keyframes row-3-line-anim {
0% {
transform: translate3d(0px, 48px, 0);
opacity: 0;
}
26.23% {
transform: translate3d(0px, 48px, 0);
opacity: 0;
animation-timing-function: ease-out;
}
83.61% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
100% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
}
@supports (animation-timeline: view()) {
.row-3-line {
animation-timeline: view();
animation-range: entry 0% cover 40%;
}
}
.aside-panel {
transform: translate3d(0px, 0px, 0);
width: 232px;
height: 272px;
background: #1f2331;
border-radius: 18px;
animation: aside-panel-anim 1220ms linear 0ms 1 both;
will-change: transform, opacity;
}
@keyframes aside-panel-anim {
0% {
transform: translate3d(64px, 0px, 0);
opacity: 0;
}
16.39% {
transform: translate3d(64px, 0px, 0);
opacity: 0;
animation-timing-function: ease-out;
}
73.77% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
100% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
}
@supports (animation-timeline: view()) {
.aside-panel {
animation-timeline: view();
animation-range: entry 0% cover 40%;
}
}
@media (prefers-reduced-motion: reduce) {
.section-heading,
.section-sub,
.row-1-mark,
.row-1-line,
.row-2-mark,
.row-2-line,
.row-3-mark,
.row-3-line,
.aside-panel {
animation: none;
transition: none;
}
}More scenes
Launch Hero
A product hero whose copy, buttons and panel arrive in sequence.
Three-Plan Pricing
Three plans that pop in, with the featured column raised and hover lifts on every card.
Feature Tile Grid
Six tiles arriving as a wave across the grid, each lifting on hover.