Page Turn Effect
Un carnet de trois pages gris clair (180 × 200 px) relié à gauche, page 1 dessus : au survol, la page 1 tourne, puis la page 2 0,45 s plus tard, et la page 3 reste à lire ; les pages tournées se posent à gauche en montrant leur verso, comme un carnet ouvert. Il se referme dans l'ordre inverse. Survol, Tab ou toucher, sans JavaScript ; sous mouvement réduit, les pages s'effacent en fondu sans tourner.
Mis à jour le
Cet effet fait partie d'Effect.Labs — 840 effets vanilla, une partie gratuite, une partie premium. 3D comprend 50 effets, dont 8 gratuits. Découvrir la catégorie →
3 exemples d'usage



Comment ça marche
La racine .fx-0015-root (fond #0a0a0f) déclare deux réglages : --page-duration: .8s (temps d'une page) et --page-gap: .45s (écart entre deux pages). La zone .demo-3d fait 360 × 200 px, la largeur du carnet ouvert (max-width: 100%), et .page-turn la remplit avec tabindex="0" : c'est elle qui reçoit le survol et le focus. La pile .page-stack occupe la moitié droite, reliure sur son bord gauche, avec perspective: 1500px ; fermée, elle est décalée d'une demi-page vers la gauche (translateX(-50%)) pour que le carnet reste centré. Chaque .page tourne autour de son bord gauche et porte deux faces à l'envers masqué : .page-front, le recto, et .page-back, le verso, retourné d'avance de 180° et ombré vers la reliure.
Au survol, ou au focus (:focus-within), la page 1 reçoit rotateY(-180deg) en 0,8 s ; la page 2 fait de même avec 0,45 s de retard ; la page 3 ne bouge pas. Pendant ce temps la pile glisse de 90 px vers la droite, et la reliure revient au milieu du cadre. Mesuré dans Chromium 151 et Firefox 153 : la page 1 passe la verticale à 0,40 s et se pose vers 0,75 s, la page 2 passe la verticale à 0,85 s et se pose vers 1,2 s. À la fin, on lit la page 3 à droite et le verso de la page 2 à gauche (vérifié au point près sous le pointeur). Quand le pointeur part, la page 2 revient d'abord, puis la page 1 : le carnet se referme sur la page 1.
Pourquoi l'ordre d'empilement change à mi-course : les pages ne partagent pas un même espace 3D, c'est z-index qui décide laquelle est dessus (3, 2, 1 au repos). Une page tournée doit pourtant passer sous la suivante une fois posée à gauche. La page 1 change donc de z-index (3 → 1) exactement quand elle est à la verticale, par une transition de durée nulle retardée de la moitié du temps de page (z-index 0s calc(var(--page-duration) / 2)) ; à la fermeture, elle reprend sa place au moment où elle repasse la verticale. Les retards sont calculés depuis les deux variables : changer --page-duration ou --page-gap garde tout synchronisé.
Accessibilité
- Clavier et toucher :
.page-turnatabindex="0"et chaque règle:hoverest doublée par:focus-within. Tab ouvre le carnet jusqu'à la page 3, Tab suivant le referme ; un anneau de 2 px#a5b4fc(:focus-visible) entoure la pile au clavier. Au doigt, un toucher l'ouvre, un toucher ailleurs le referme. Mesuré dans Chromium 151, Firefox 153 et WebKit 26. Un clic à la souris donne aussi le focus : le carnet reste ouvert jusqu'au clic suivant ailleurs. - Mouvement réduit : sous
prefers-reduced-motion: reduce, un bloc limité à.fx-0015-rootretire toute rotation et tout glissement (le carnet reste fermé et centré) ; les pages 1 puis 2 s'effacent en fondu de 0,3 s, la seconde après--page-gap, et la page 3 apparaît. L'ordre de lecture est gardé, sans mouvement dans l'espace. - Lecteurs d'écran : les trois pages et leurs versos sont dans le HTML et lus dans l'ordre (page 1, son verso, page 2…), carnet ouvert ou fermé. Les versos vides ne disent rien ; si vous y mettez du texte, il sera lu juste après sa page.
- Contraste : texte
#333en demi-gras sur papier gris clair, de 8,19:1 (page 1, le plus foncé) à 11,9:1 (page 3).
Compatibilité navigateur
CSS seul (perspective, transform-style: preserve-3d, backface-visibility, variables CSS dans calc() pour les retards, transition de z-index, :focus-within, :focus-visible), aucun JavaScript, aucune dépendance. Mesuré dans Chromium 151 et Firefox 153 : même ordre de pages à l'ouverture et à la fermeture, deux copies indépendantes sur une page, fondu sans rotation sous mouvement réduit. Le WebKit de Playwright (26.5) aplatit toute 3D CSS, même un cube de référence : focus et toucher y sont mesurés, le rendu 3D n'a pas été vérifié sur un vrai Safari.
Sans transformations 3D, les pages ne tournent pas : le carnet reste fermé sur la page 1. Dans Safari avant 15.4, ajoutez -webkit-backface-visibility: hidden aux deux faces, sinon le recto se voit en miroir à travers le verso. Sans :focus-visible, c'est le contour de focus par défaut qui s'affiche.
Le code
Structure HTML à coller dans votre page (le CSS + JS sont inclus avec votre achat) :
<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">… son verso …</div>
</div>
… (pages 2 et 3, même structure)
</div>
</div>
</div>
</div>
Paiement unique, sans abonnement — le code est à toi pour toujours
Personnaliser
Options passées à l'API ou attributs data-* :
| Option / propriété | Défaut | Effet |
|---|---|---|
Rythme (CSS — --page-duration et --page-gap sur .fx-0015-root) |
.8s et .45s | Un écart plus petit que la moitié de la durée fait voler deux pages en même temps ; un écart égal à la durée tourne une page à la fois. Tous les retards (rotations, glissement, changements de z-index) sont calculés depuis ces deux variables : ne touchez qu'elles. |
Taille (CSS — width et height de .fx-0015-root .demo-3d) |
360 × 200 px | Chaque page fait la moitié de la largeur et toute la hauteur. Gardez max-width: 100% : sur un écran de 320 px, les pages passent à 160 px de large au lieu de déborder. |
Perspective (CSS — perspective de .page-stack) |
1500px | Plus petite (800 px), la page qui se lève grossit nettement en venant vers vous ; plus grande, le feuilletage devient plus plat. |
Papier (CSS — fond des .page-front par :nth-child, dégradé de .page-back) |
#e8e8e8 → #d0d0d0, #f0f0f0 → #e0e0e0, #f8f8f8 → #f0f0f0 ; verso #f2f2f2 → #d8d8d8 | Le dégradé du verso fonce vers la reliure : gardez cette ombre, c'est elle qui fait lire un carnet ouvert. Pour un papier crème, partez de #fbf6ea. |
Glissement du carnet (CSS — transform de .page-stack) |
translateX(-50%) fermé, none ouvert | Remplacez translateX(-50%) par none pour un carnet qui ne glisse pas : il reste alors posé à droite du milieu, fermé comme ouvert. |
FAQ
.page et suivez une règle simple, pour la page n° k sur N. Au repos : z-index N + 1 − k ; retour (fermeture) retardé de (N − 1 − k) × --page-gap, et changement de z-index à ce retard plus la moitié de --page-duration. Au survol : rotation retardée de (k − 1) × --page-gap, z-index k au milieu de sa rotation. La dernière page ne tourne pas ; le retard de retour de .page-stack devient (N − 2) × --page-gap. Règle vérifiée avec 4 pages dans Chromium et Firefox : ouverture 1, 2, 3, 4, fermeture dans l'ordre inverse.z-index) et remplacez les règles de survol par une classe posée sur chaque page, par exemple .page.is-turned { transform: rotateY(-180deg) }, ajoutée et retirée par deux boutons « page suivante » et « page précédente » en JavaScript, qui mettent aussi à jour le z-index de la page tournée.