Perspective Tilt
Une carte indigo de 200 × 140 px s'incline vers le pointeur jusqu'à 12° sur ses bords, une tache de lumière glisse exactement sous la souris et le texte flotte 40 px en avant : elle répond aussi au doigt et aux flèches, chaque copie de la page a sa propre carte, et quand le système demande moins d'animation elle ne penche plus mais garde son reflet.
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
Sur le fond noir bleuté de .fx-0003-root (au moins 300 px de haut), un cadre .demo-3d de 280 × 200 px porte la carte .perspective-tilt : 200 × 140 px, dégradé #1e1b4b → #312e81, bord indigo translucide, coins de 1rem. Chaque racine reçoit sa propre instance du script, qui ne s'occupe que de sa carte. Quand le pointeur glisse sur la carte, sa position est ramenée de 0 à 1 en largeur et en hauteur, puis le script écrit transform: perspective(1000px) rotateX(…) rotateY(…) : le côté sous le pointeur vient vers vous, le côté opposé s'enfonce, jusqu'à 12° sur les bords. Relevé près du coin haut gauche (5 % du bord) : 11,0° et 10,6°, identiques sous Chromium 151 et Firefox 153. Les à-coups sont gommés par 0,1 s de transition ; quand le pointeur sort, la carte revient à plat.
La lumière est un pseudo-élément ::before étendu à toute la carte : un dégradé radial indigo (rgba(99, 102, 241, .3), transparent à 50 %) centré sur deux variables CSS, --mouse-x et --mouse-y, que le script met à jour en pourcentage. La tache suit donc le pointeur au pixel près, quelle que soit la taille de la carte, et elle reste au dernier point touché quand la carte se remet à plat. Le texte .perspective-tilt-content est avancé de 40 px (translateZ) dans une carte en transform-style: preserve-3d : il garde ce relief quand elle s'incline et glisse par rapport au fond, de 9,6 px avec le pointeur au bord droit (mesuré dans Chromium et Firefox).
Trois choix rendent la carte utilisable partout. Ce sont les événements pointer qui pilotent la carte, si bien qu'un stylet ou un doigt la font pencher comme la souris, et touch-action: none évite que la page défile quand le doigt glisse sur la carte ; elle revient à plat quand le doigt se lève. Grâce à tabindex="0", la carte prend le focus ; un role="group" et un aria-label la nomment. Au clavier, chaque flèche promène le reflet d'un dixième de carte, et Échap ou la sortie du focus la remettent à plat. Enfin l'angle est calculé en fraction de la carte, pas en pixels : agrandie à 400 × 200 px comme dans les scènes, elle ne dépasse toujours pas 12°, alors qu'un calcul en pixels doublerait l'angle à chaque doublement de largeur.
Accessibilité
- Mouvement réduit : avec
prefers-reduced-motion: reduce, la règle@mediaécrite sous.fx-0003-rootbloque la carte à plat (transform: none, sans transition). La tache de lumière continue de suivre le pointeur, on garde l'indication de l'endroit visé sans mouvement dans l'espace. Vérifié sous les trois moteurs (Chromium, Firefox, WebKit) : 0° sous la souris, contre 11° sans ce réglage. - Clavier : la carte est un arrêt de tabulation ; au focus, un liseré lavande
#a5b4fcde 2 px l'entoure (:focus-visible, 9,9:1 contre le fond). Quatre pressions sur → puis deux sur ↑ la penchent de 9,6° et 4,9° ; quitter le focus ou presser Échap la redresse. - Lecteurs d'écran : la carte est annoncée par son nom,
aria-label="Tilt card: the arrow keys tilt it"posé sur unrole="group", puis « Move Mouse » est lu. Sur un site français, écrivez ce nom en français. Si la carte mène quelque part, mettez un vrai lien dans son contenu. - Contraste : texte blanc sur
#312e81à 11,4:1 et sur#1e1b4bà 16:1. La tache indigo ne fait que l'éclaircir légèrement : gardez un texte clair si vous recolorez la carte en sombre. - Toucher :
touch-action: nonebloque le défilement de la page quand le doigt démarre sur la carte. À 200 × 140 px, c'est sans gêne ; pour une carte qui occupe toute la largeur d'un téléphone, passez àtouch-action: pan-y: le défilement vertical revient, seul un glissé de côté incline la carte.
Compatibilité navigateur
CSS (transform avec perspective(), rotateX et rotateY, transform-style: preserve-3d pour le relief du texte, variables CSS dans un dégradé, touch-action, :focus-visible) + JS d'événements pointer, aucune dépendance. Mesuré dans Chromium 151 et Firefox 153 : même inclinaison, même tache de lumière, deux copies indépendantes sur une page, carte à plat sous mouvement réduit, inclinaison au doigt (Chromium en mode tactile). Le WebKit de Playwright (26.5) affiche bien l'inclinaison de la carte, mais il aplatit toute 3D imbriquée, même sur un cube de référence : le relief du texte n'a pas été vérifié sur un vrai Safari.
Sans transformations 3D, la carte reste à plat et seule la tache de lumière suit le pointeur. Sans :focus-visible (navigateur ancien), c'est le contour de focus par défaut du navigateur qui s'affiche.
Le code
Structure HTML à coller dans votre page (le CSS + JS sont inclus avec votre achat) :
<div class="fx-0003-root">
<div class="demo-3d">
<div class="perspective-tilt" tabindex="0" role="group" aria-label="…">
<span class="perspective-tilt-content">Move Mouse</span>
</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 |
|---|---|---|
Inclinaison maximale (JS — MAX_TILT = 12) |
12° | Angle atteint sur les bords de la carte, quelle que soit sa taille. 6 donne un effet discret pour un bouton ou un visuel de produit ; au-delà de 20, le texte devient difficile à lire pendant le mouvement. |
Perspective (JS — perspective(1000px) dans le transform) |
1000px | Plus la valeur est petite, plus la déformation est forte au même angle : 500px donne un côté proche nettement plus grand que le côté lointain. Changez-la aux deux endroits du script (inclinaison et remise à plat). |
Relief du texte (CSS — translateZ(40px) de .perspective-tilt-content) |
40 px | Distance du texte devant la carte : 9,6 px de glissement mesuré au bord à 40 px. À 0, le texte reste collé à la carte ; au-delà de 60, il semble se détacher. |
Lumière (CSS — radial-gradient du ::before) |
rgba(99, 102, 241, .3), transparent 50% | Couleur et taille de la tache. Du blanc à .5 donne un reflet de matière brillante (émail, carte, métal) ; baissez le second pourcentage (30 %) pour une tache plus petite et plus nette. |
Taille de la carte (CSS — .perspective-tilt, .demo-3d) |
200 × 140 px dans un cadre de 280 × 200 px | L'angle ne dépend pas de la taille. Agrandissez aussi .demo-3d ou retirez ses dimensions, sinon la carte déborde du cadre. |
Réactivité (CSS — transition: transform .1s ease-out) |
0,1 s | 0,3 s donne une carte plus lourde qui rattrape le pointeur avec un temps de retard ; 0 la colle au pointeur sans aucun lissage. |
Pas du clavier (JS — 0.1 dans l'écouteur keydown) |
10 % de la carte par appui | 0.25 atteint le bord en deux appuis ; gardez une valeur qui laisse voir le mouvement à chaque appui. |
FAQ
reset() du script card.style.setProperty('--mouse-x', '50%') et la même ligne pour --mouse-y..fx-0003-root, et le script en lance une par racine, sans aucun id. Essai avec deux copies sur la même page, dans les trois moteurs : seule la carte survolée bouge. Pour une rangée de cartes, mettez une racine par carte et collez le script une seule fois.