GODRICH
#css-animation#button#loader#transition#scroll#dashboard#ui#design-trends

9 Website Scroll Effects — Apple-Style, CSS Only

Website scroll effects, done with no scroll library at all, feel the way Apple's product pages do.

This collection covers horizontal panels, pinned scene swaps, word-by-word fills, and section theme shifts. Copy, paste, and it runs.

Auto-plays · click a tile to jump to its section · all nine in one zip

The nine follow the order you meet them on the page. It starts with what appears the moment the page opens (01), moves to what you find when the article ends (02), continues through cards stacking and sentences filling in as you read (03–07), and closes with a list that reacts to speed and a single image waiting to be revealed (08–09). It is the same path an Apple-style page takes from top to bottom, css parallax scrolling and all. On the same axis, the bar that clings and drops is 9 CSS Sticky Header Extras, and scenes that pull a story along are 9 Scrollytelling CSS Section Patterns.

01Horizontal story panels

What this css scroll animation shows

Scrolling vertically slides panels horizontally inside a pinned screen — the signature Apple product-page layout. A scroll-timeline reads the scroller's position and pushes the track, while position: sticky holds the screen.

Horizontal story panels
Open in a new tab

01 · Horizontal story panels — Measured area 51.539% · moving frames 23/23Original by GODRICH · SCSS and React ship in the zip · See the password

animation-timeline: scroll()scroll-timeline: --hp-scrollposition: sticky

Where to look in the code

Use it for product feature stories or portfolio walkthroughs.

.hp__scroller {
  overflow-y: auto;
  scroll-timeline: --hp-scroll block;
}
.hp__inner { height: 300%; }          // sticky area three screens deep
.hp__pin {
  position: sticky;
  top: 0;
  height: calc(100% / 3);
  overflow: hidden;
}
.hp__track {
  display: flex;
  width: 300%;                        // 3 panels = 300% of the screen
  animation: hp-slide linear both;
  animation-timeline: --hp-scroll;
}
@keyframes hp-slide {
  from { transform: translateX(0); }
  to   { transform: translateX(-66.6667%); } // two panels over track width
}

02Curtain-reveal footer

What happens on screen

The content panel travels over the footer and steps aside at the end of the scroll, revealing the footer like a curtain. The footer sits last in the document but sticks to the viewport bottom from the start with position: sticky; bottom: 0.

Curtain-reveal footer
Open in a new tab

02 · Curtain-reveal footer — Measured area 16.541% · moving frames 13/23Original by GODRICH · SCSS and React ship in the zip · See the password

z-indexposition: stickySafari에서도 그대로

How to read the code

Use it for contact footers or closing greetings.

.fc__main {
  position: relative;
  z-index: 1;                    // content travels above the footer
  min-height: calc(100% + 64px); // covers the footer from the start
  margin-bottom: 64px;           // opens the footer slot at the end
  background: #fff;
}
.fc__foot {
  position: sticky;
  bottom: 0;
  z-index: 0;
  height: 64px;
  background: linear-gradient(120deg, #b9f0d8, #ffd6e8);
}

03Stacking cards

What moves

Every card is sticky, so each new one slides up and covers the last while earlier cards stay stacked in place. Stepping the top value one notch deeper per card leaves room for the overlap.

Stacking cards
Open in a new tab

03 · Stacking cards — Measured area 30.731% · moving frames 15/23Original by GODRICH · SCSS and React ship in the zip · See the password

position: stickytop 간격JS 0줄

What to change

Use it for service intro steps or pricing comparison cards.

.sk__card {
  position: sticky;
  min-height: 40px;
  margin-bottom: 8px;
  border-radius: 16px;
  box-shadow: 0 6px 12px rgba(23, 20, 26, .32);
}
.sk__card--1 { top: 8px;  background: #ffd6e8; }
.sk__card--2 { top: 16px; background: #d3ecff; }
.sk__card--3 { top: 24px; background: #e4f7d9; }
.sk__card--4 { top: 32px; background: #fff3c9; }

04Pinned scene swap

What you see

The screen stays pinned while scenes cross-fade in place according to how far you have scrolled — the core motion of scrollytelling. Three scenes share one scroll timeline and split it with keyframe ranges.

Pinned scene swap
Open in a new tab

04 · Pinned scene swap — Measured area 51.54% · moving frames 14/23Original by GODRICH · SCSS and React ship in the zip · See the password

animation-timeline: scroll()키프레임 구간opacity

Where to look in the code

Use it for three-step how-tos or product stories.

.ps__scroll {
  overflow-y: auto;
  scroll-timeline: --ps-scroll block;
}
.ps__pin {
  position: sticky;
  top: 0;
  height: calc(100% / 3);
  display: grid;
}
.ps__scene--1 { animation: ps-1 linear both; animation-timeline: --ps-scroll; }
.ps__scene--2 { animation: ps-2 linear both; animation-timeline: --ps-scroll; }
.ps__scene--3 { animation: ps-3 linear both; animation-timeline: --ps-scroll; }
@keyframes ps-1 { 0% { opacity: 1; } 33%, 100% { opacity: 0; } }
@keyframes ps-2 { 0%, 30% { opacity: 0; } 38%, 62% { opacity: 1; } 70%, 100% { opacity: 0; } }
@keyframes ps-3 { 0%, 64% { opacity: 0; } 74%, 100% { opacity: 1; } }

05Word-by-word fill

What happens on screen

Words in a sentence sharpen one by one as you scroll — the effect seen across Apple's copy blocks. Each word carries its own view() timeline, so geometry itself creates the stagger without any delay tricks.

Word-by-word fill
Open in a new tab

05 · Word-by-word fill — Measured area 4.778% · moving frames 17/23Original by GODRICH · SCSS and React ship in the zip · See the password

animation-range 겹침view()글자색만

How to read the code

Use it for landing openers or brand statements.

.wf__w {
  color: rgba(23, 20, 26, .16);   // light by default
  animation: wf-in linear both;
  animation-timeline: view();     // one timeline per word
  animation-range: entry 0% cover 42%;
}
@keyframes wf-in {
  from { color: rgba(23, 20, 26, .16); }
  to   { color: #17141a; }
}

06Highlighter sweep

What moves

As you scroll to it, a highlighter color sweeps in behind the key phrase from left to right. The trick is growing only the background gradient's width (background-size) while the letters stay untouched.

Highlighter sweep
Open in a new tab

06 · Highlighter sweep — Measured area 1.592% · moving frames 14/23Original by GODRICH · SCSS and React ship in the zip · See the password

background-sizeview()글자 안 건드림

What to change

Use it for section headline emphasis or sale copy.

.mk__hl {
  background: linear-gradient(#2f6df6, #2f6df6) no-repeat 0 62%;
  background-size: 0% 58%;
  padding: 0 4px;
  animation: mk-sw linear both;
  animation-timeline: view();
  animation-range: entry 30% cover 60%;
}
@keyframes mk-sw {
  from { background-size: 0% 58%; }
  to   { background-size: 100% 58%; }
}

07Section-by-section theme shift

What you see

The page background blends gently between colors section by section as you scroll, like a change of scene. A sticky background layer sits behind the content, and a scroll timeline drives its color keyframes.

Section-by-section theme shift
Open in a new tab

07 · Section-by-section theme shift — Measured area 48.633% · moving frames 8/23Original by GODRICH · SCSS and React ship in the zip · See the password

animation-timeline: scroll()background-colorroot 타임라인

Where to look in the code

Use it for narrative landings or routine and pricing guides.

.ts__scroll {
  overflow-y: auto;
  scroll-timeline: --ts-scroll block;
}
.ts__bg {
  position: sticky;
  top: 0;
  height: 100%;
  margin-bottom: -100%;  // pulls sections up over the background
  animation: ts-bg linear both;
  animation-timeline: --ts-scroll;
}
@keyframes ts-bg {
  0%   { background-color: #fff7e6; }
  50%  { background-color: #b8f0d0; }
  100% { background-color: #ff9db8; }
}

08Velocity-skewed list

What happens on screen

Fast scrolling tilts the list cards in proportion to the speed; stopping settles them back upright. A short script tracks the speed and writes it into a --vel variable, and CSS calc does all the tilting math.

Velocity-skewed list
Open in a new tab

08 · Velocity-skewed list — Measured area 18.627% · moving frames 23/23Original by GODRICH · SCSS and React ship in the zip · See the password

JS 10줄--vel 변수skewY

How to read the code

Use it for gallery feeds or news and magazine lists.

var box = document.querySelector('.feed');
var last = box.scrollTop, vel = 0;
box.addEventListener('scroll', function () {
  vel = Math.max(-24, Math.min(24, box.scrollTop - last));
  last = box.scrollTop;
});
(function decay() {
  vel *= 0.86;
  box.style.setProperty('--vel', vel.toFixed(2));
  requestAnimationFrame(decay);
})();
.feed__row {
  transform: skewY(calc(var(--vel, 0) * -0.18deg));
}

09Spotlight circle

What moves

On a pinned screen, a circular window grows as you scroll to uncover a hidden image. A bright layer sits on top, and a scroll timeline grows its clip-path: circle() radius.

Spotlight circle
Open in a new tab

09 · Spotlight circle — Measured area 46.333% · moving frames 11/23Original by GODRICH · SCSS and React ship in the zip · See the password

clip-path: circle()scroll-timeline: --sl-scroll이미지 공개

What to change

Use it for product reveal moments or artist intros.

.sl__spot {
  grid-area: 1 / 1;
  background: linear-gradient(135deg, #2f6df6, #8fb4ff);
  clip-path: circle(14% at 50% 50%);
  animation: sl-open linear both;
  animation-timeline: --sl-scroll;
}
@keyframes sl-open {
  from { clip-path: circle(14% at 50% 50%); }
  to   { clip-path: circle(75% at 50% 50%); }
}

Where it breaks — one trap

The trap that bit hardest was that position: sticky still occupies its slot in the flow. The first build of 02 placed the footer before the content, and no matter how far you scrolled, the footer never once appeared. Moving the footer to the very end of the document and giving the content a margin-bottom finally produced the picture of the panel traveling over the footer and stepping aside at the end. Item 07 suffered the same issue: its sticky background layer claimed a full screen of the flow, pushing the section chips below the fold so they never showed up in a single capture, until margin-bottom: -100% pulled the sections back on top. One more thing: the scroll timelines here (scroll() and view()) were verified by rendering in the installed Chrome, but Firefox and Safari do not support them yet — in those browsers the sentence in 05 stays sharp from the start and the circle in 09 stays open. That is why all nine ship an @supports not fallback showing the finished state, while scrolling itself never breaks. Type that spills out with no scroll involved at all is the side 9 CSS Typing Animation handles. All nine folders were re-checked this way before zipping, and entering ry7akxw2 exactly as written in the guide opens the whole thing.

Accessibility

All nine switch off their automatic motion under prefers-reduced-motion: reduce. The words in 05 stay dark from the start, the highlighter in 06 arrives fully drawn, the circle in 09 stays wide open, and 08 locks its speed reaction so cards never tilt. Every scroll box remains reachable with the Tab key, and even in the pinned layout of 04 the next section still sits right below, so keyboard users can read to the end.

FAQ

Do website scroll animation effects slow a site down?

The scroll timelines in 01, 04, 07, and 09 and the sticky tricks in 02 and 03 are handled directly by the browser's rendering stage, which is lighter than having JavaScript recalculate every frame. Only 08 runs a script each frame, and its whole job is writing one number into a variable. Reading the pointer as coordinates belongs to 9 Mouse Effects CSS Tricks instead.

How does it look in Firefox or Safari?

Items using scroll timelines (01, 04, 05, 06, 07, 09) freeze at their finished state in browsers without support: panel 1 shows, the sentence is sharp, the highlighter is drawn, the circle is open. Items 02, 03, and 08 do not rely on them and behave the same everywhere.

Does it work on iPhone?

The sticky footer and stacking cards in 02 and 03 and the background sweep in 06 work as-is in iPhone Safari. The rest rely on scroll timelines that iPhone Safari does not support yet, so they show their finished state — the layout itself stays intact and everything remains readable.

More scroll pieces live in the CSS animations category, and this article continues into the parallax collection and the sticky header collection. The formal spec of animation-timeline is on MDN's animation-timeline page, and sticky positioning is explained on MDN's position page.

Enter the archive password

The password is inside this article. You will find it as you read.