GODRICH

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.

01Horizontal story panels

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. Use it for product feature stories or portfolio walkthroughs.

animation-timeline: scroll()scroll-timeline: --hp-scrollposition: sticky
.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

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. Use it for contact footers or closing greetings.

z-indexposition: stickySafari에서도 그대로
.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

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. Use it for service intro steps or pricing comparison cards.

position: stickytop 간격JS 0줄
.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

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. Use it for three-step how-tos or product stories.

animation-timeline: scroll()키프레임 구간opacity
.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

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. Use it for landing openers or brand statements.

animation-range 겹침view()글자색만
.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

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. Use it for section headline emphasis or sale copy.

background-sizeview()글자 안 건드림
.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

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. Use it for narrative landings or routine and pricing guides.

animation-timeline: scroll()background-colorroot 타임라인
.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

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. Use it for gallery feeds or news and magazine lists.

JS 10줄--vel 변수skewY
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

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. Use it for product reveal moments or artist intros.

clip-path: circle()scroll-timeline: --sl-scroll이미지 공개
.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. 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 scroll animations 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.

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.