3D✨ Premium

Page Turn Effect

A three-page light gray notebook (180 × 200 px) bound on the left, page 1 on top: on hover, page 1 turns, then page 2 0.45 s later, and page 3 stays to be read; turned pages settle on the left showing their back, like an open notebook. It closes in reverse order. Hover, Tab or a tap, with no JavaScript; under reduced motion, the pages fade out without turning.

CSS3DBook

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. 3D has 50 effects, including 8 free. Explore the category →

3 usage examples

Leafing through an illustrator's sketchbook — portfolio page — Page Turn Effect example 1

① Leafing through an illustrator's sketchbook — portfolio page

WhenLéa Ferrand's sketchbook no. 7, set on a dark background: "Saturday market", "The neighbor's cat", "Concarneau harbor", three pencil sketches. On hover, the sketchbook leafs open; the backs carry the illustrator's notes ("Quimper, 8 am. The mushroom stall opens before the others").
WhyPages turning one after another recreate the thumb flipping through a sketchbook; a grid gallery would lose the sketchbook as an object.
SettingsArea enlarged to 400 × 222 px (200 × 222 px pages) to cover the whole capture path; cream paper #fbf6ea shaded toward the binding, sketches as SVG line drawings in #5b5348, back notes in Georgia italic. Original duration and gap.
A puppy's health record, leafed through — "Our litters" page of a dog breeder — Page Turn Effect example 2

② A puppy's health record, leafed through — "Our litters" page of a dog breeder

WhenUnder the heading "Every puppy leaves with an up-to-date health record": the vaccination page (CHPPiL at 8 weeks), the identification page (microchip), the deworming page (10 weeks), each with the vet's stamp. The backs give the weight and the next booster.
WhyShowing three pages turning says "complete record" better than a list: buyers see a real booklet, page after page.
Settings380 × 200 px area (190 × 200 px pages); blue #2f5d84 band at the top of each page, red #b23a48 stamp drawn in CSS and tilted −12°; bluish paper #f7fafc.
A jazz festival program leafed through day by day — Page Turn Effect example 3

③ A jazz festival program leafed through day by day

When"Jazz on the Ramparts", July 11, 12 and 13: one page per day, three concerts each with their time. The program leafs open on hover up to Sunday and closes back on Friday when the mouse leaves; the backs give the site map and the shuttles.
WhyThree days, three pages: the offset between the sheets gives the chronological order without numbering.
Settings390 × 212 px area (195 × 212 px pages) on a midnight blue background; ivory paper #fbf3e0, day titles in 19 px Georgia underlined in gold #d7b36a, times in bold gold, a dotted line per concert.

How it works

The root .fx-0015-root (#0a0a0f background) declares two settings: --page-duration: .8s (time for one page) and --page-gap: .45s (delay between two pages). The .demo-3d area is 360 × 200 px, the width of the open notebook (max-width: 100%), and .page-turn fills it with tabindex="0": it receives hover and focus. The .page-stack takes the right half, binding on its left edge, with perspective: 1500px; when closed, it is shifted half a page to the left (translateX(-50%)) so the notebook stays centered. Each .page turns around its left edge and carries two faces with hidden backs: .page-front, the front, and .page-back, the back, turned 180° in advance and shaded toward the binding.

On hover or focus (:focus-within), page 1 gets rotateY(-180deg) over 0.8 s; page 2 does the same 0.45 s later; page 3 does not move. Meanwhile the stack slides 90 px to the right, bringing the binding back to the middle of the frame. Measured in Chromium 151 and Firefox 153: page 1 passes vertical at 0.40 s and settles around 0.75 s, page 2 passes vertical at 0.85 s and settles around 1.2 s. At the end, page 3 reads on the right and the back of page 2 on the left (checked at the exact point under the pointer). When the pointer leaves, page 2 comes back first, then page 1: the notebook closes on page 1.

Why the stacking order changes halfway: the pages do not share one 3D space, so z-index decides which is on top (3, 2, 1 at rest). Yet a turned page must go under the next one once it lies on the left. So page 1 changes its z-index (3 → 1) exactly when it stands vertical, through a zero-length transition delayed by half the page time (z-index 0s calc(var(--page-duration) / 2)); when closing, it takes its place back as it passes vertical again. The delays are computed from the two variables: changing --page-duration or --page-gap keeps everything in sync.

Accessibility

  • Keyboard and touch: .page-turn has tabindex="0" and every :hover rule is doubled by :focus-within. Tab opens the notebook to page 3, the next Tab closes it; a 2 px #a5b4fc ring (:focus-visible) surrounds the stack for keyboard users. On a touchscreen, a tap opens it, a tap elsewhere closes it. Measured in Chromium 151, Firefox 153 and WebKit 26. A mouse click also gives focus: the notebook stays open until the next click elsewhere.
  • Reduced motion: under prefers-reduced-motion: reduce, a block scoped to .fx-0015-root removes every rotation and slide (the notebook stays closed and centered); pages 1 then 2 fade out over 0.3 s, the second after --page-gap, and page 3 appears. Reading order is kept, without motion in space.
  • Screen readers: the three pages and their backs are in the HTML and read in order (page 1, its back, page 2…), notebook open or closed. Empty backs say nothing; if you put text on them, it is read right after its page.
  • Contrast: semibold #333 text on light gray paper, from 8.19:1 (page 1, the darkest) to 11.9:1 (page 3).

Browser compatibility

CSS only (perspective, transform-style: preserve-3d, backface-visibility, CSS variables inside calc() for the delays, a z-index transition, :focus-within, :focus-visible), no JavaScript, no dependencies. Measured in Chromium 151 and Firefox 153: same page order when opening and closing, two independent copies on one page, fade without rotation under reduced motion. Playwright's WebKit (26.5) flattens all CSS 3D, even a reference cube: focus and touch are measured there, the 3D rendering was not checked on a real Safari.

Chrome 86+✓ Full
Firefox 85+✓ Full
Safari 15.4+✓ Focus and touch measured on WebKit; 3D rendering not checked on a real Safari
Edge 86+✓ Full
Mobile iOS 15.4+✓ Not checked on a real iPhone
Android Chrome✓ Full, with a tap

Without 3D transforms, the pages do not turn: the notebook stays closed on page 1. In Safari before 15.4, add -webkit-backface-visibility: hidden to both faces, otherwise the front shows mirrored through the back. Without :focus-visible, the browser's default focus outline shows instead.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0015-root">
  <div class="demo-3d">
    <div class="page-turn" tabindex="0">
      <div class="page-stack">
        <div class="page">
          <div class="page-front">… page 1 …</div>
          <div class="page-back">… its back …</div>
        </div>
        … (pages 2 and 3, same structure)
      </div>
    </div>
  </div>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Pace (CSS — --page-duration and --page-gap on .fx-0015-root) .8s and .45s A gap shorter than half the duration sends two pages flying at once; a gap equal to the duration turns one page at a time. Every delay (rotations, slide, z-index changes) is computed from these two variables: only touch them.
Size (CSS — width and height of .fx-0015-root .demo-3d) 360 × 200 px Each page is half the width and the full height. Keep max-width: 100%: on a 320 px screen, the pages shrink to 160 px wide instead of overflowing.
Perspective (CSS — perspective of .page-stack) 1500px Smaller (800 px), the lifting page grows clearly as it comes toward you; larger, the leafing gets flatter.
Paper (CSS — background of each .page-front by :nth-child, gradient of .page-back) #e8e8e8 → #d0d0d0, #f0f0f0 → #e0e0e0, #f8f8f8 → #f0f0f0; back #f2f2f2 → #d8d8d8 The back's gradient darkens toward the binding: keep that shadow, it is what makes an open notebook readable. For cream paper, start from #fbf6ea.
Notebook slide (CSS — transform of .page-stack) translateX(-50%) closed, none open Replace translateX(-50%) with none for a notebook that does not slide: it then sits right of center, closed as well as open.

FAQ

Copy a .page block and follow one simple rule, for page number k out of N. At rest: z-index N + 1 − k; return (closing) delayed by (N − 1 − k) × --page-gap, and z-index change at that delay plus half of --page-duration. On hover: rotation delayed by (k − 1) × --page-gap, z-index k halfway through its rotation. The last page does not turn; the return delay of .page-stack becomes (N − 2) × --page-gap. Rule checked with 4 pages in Chromium and Firefox: opening 1, 2, 3, 4, closing in reverse order.
It has the width of the open notebook (360 px): the notebook slides half a page and turned pages settle on the left, so the area must already cover that spot. If it were limited to the closed notebook, the slide could move the pointer out of the area and close the notebook mid-motion. Accepted side effect: hovering the empty space left of the closed notebook opens it too.
Not with this code, which opens the whole notebook in one gesture. For a real page-by-page book, keep the structure (two-sided pages, stack, z-index) and replace the hover rules with a class set on each page, for instance .page.is-turned { transform: rotateY(-180deg) }, added and removed by "next page" and "previous page" buttons in JavaScript, which also update the turned page's z-index.