Qu'on aime ou déteste ça, le parallaxe est là pour durer. Utilisée à bon escient, elle peut ajouter de la profondeur et de la subtilité à une application Web. Le problème, cependant, est que l'implémentation un parallaxe performant peut s'avérer difficile. Dans cet article, nous aborderons discuter d'une solution à la fois performante et, tout aussi importante, qui fonctionne multi-navigateurs.
Résumé
- N'utilisez pas d'événements de défilement ni de
background-position
pour créer des animations parallaxes. - Utilisez des transformations 3D CSS pour créer un effet de parallaxe plus précis.
- Pour Mobile Safari, utilisez
position: sticky
pour vous assurer que l'effet de parallaxe est propagée.
Si vous souhaitez utiliser la solution prête à l'emploi, accédez au dépôt GitHub d'exemples d'éléments d'interface utilisateur et récupérez le Outil d'aide parallaxe JS ! Vous pouvez regarder une démonstration en direct du conteneur de défilement parallaxe dans la dépôt GitHub.
Parallaxes problématiques
Pour commencer, examinons deux façons courantes d'obtenir un parallaxe et en particulier les raisons pour lesquelles ils ne sont pas adaptés à nos besoins.
Mauvaise installation: utilisation d'événements de défilement
L'exigence clé du parallaxe est qu'il doit être couplé au défilement. pour à chaque changement de position de défilement de la page, l'attribut de l'élément parallaxe doit être mis à jour. Bien que cela semble simple, un mécanisme important de les navigateurs récents est leur capacité à fonctionner de manière asynchrone. Ceci s'applique dans notre pour faire défiler des événements. Dans la plupart des navigateurs, les événements de défilement sont générés comme "du mieux possible" et leur diffusion n'est pas garantie à chaque image Animation de défilement
Cette information importante nous explique pourquoi nous devons éviter Solution basée sur JavaScript qui déplace les éléments en fonction d'événements de défilement: JavaScript ne garantit pas que le parallaxe restera en phase avec le la position de défilement de la page. Dans les anciennes versions de Safari pour mobile, les événements de défilement livré à la fin du défilement, ce qui rendait impossible Effet de défilement basé sur JavaScript Les versions plus récentes présentent des événements de défilement pendant l'animation. Toutefois, comme pour Chrome, à la base. Si le Le thread principal est occupé par d'autres tâches, les événements de défilement ne seront pas transmis immédiatement, ce qui signifie que l'effet de parallaxe sera perdu.
Mauvaise mise à jour de background-position
Une autre situation que nous aimerions éviter est de peindre sur chaque cadre. Nombreuses solutions
tenter de modifier background-position
pour obtenir l'apparence parallaxe, ce qui
force le navigateur à repeindre les parties affectées de la page lors du défilement, et que
peut s'avérer assez coûteux pour entraîner
des à-coups dans l'animation.
Pour tenir la promesse du mouvement parallaxe, nous voulons atteindre peuvent être appliquées en tant que propriété accélérée (ce qui implique aujourd'hui de s'en tenir et l'opacité), et qui ne repose pas sur des événements de défilement.
CSS en 3D
Scott Kellum et Keith Clark ont tous deux a beaucoup travaillé sur l'utilisation de la 3D CSS pour obtenir un mouvement de parallaxe. et la technique qu'ils utilisent est effectivement le suivant:
- Configurez un élément conteneur pour le faire défiler avec
overflow-y: scroll
(et probablementoverflow-x: hidden
). - À ce même élément, appliquez une valeur
perspective
et une propriétéperspective-origin
définie surtop left
ou0 0
. - Pour les enfants de cet élément, appliquez une traduction en Z et redimensionnez-les pour fournir un mouvement parallaxe sans affecter leur taille à l'écran.
Le CSS utilisé pour cette approche se présente comme suit:
.container {
width: 100%;
height: 100%;
overflow-x: hidden;
overflow-y: scroll;
perspective: 1px;
perspective-origin: 0 0;
}
.parallax-child {
transform-origin: 0 0;
transform: translateZ(-2px) scale(3);
}
Cela suppose un extrait de code HTML comme celui-ci:
<div class="container">
<div class="parallax-child"></div>
</div>
Ajustement de l'échelle de la perspective...
Si vous repoussez l'élément enfant, il réduira sa taille proportionnelle à la du point de vue de l'utilisateur. Vous pouvez calculer la quantité de données à augmenter cette équation: (perspective - distance) / perspective. Puisque nous avons probablement que l'élément de parallaxe soit en parallaxe, mais apparaisse à la taille dans laquelle nous l'avons créé, il faudrait l'augmenter de cette manière, plutôt que de la laisser telle quelle.
Dans le cas du code ci-dessus, la perspective est de 1px, et la macro
La distance Z de parallax-child
est de -2 px. Cela signifie que l'élément aura besoin
à la hausse de 3x, que vous pouvez voir est la valeur intégrée au code:
scale(3)
Pour tout contenu auquel aucune valeur translateZ
n'est appliquée, vous pouvez :
remplacez-la par une valeur de zéro. Cela signifie que l'échelle est (perspective - 0) /
la perspective, qui renvoie une valeur de 1, ce qui signifie qu'elle est mise à l'échelle
ni vers le haut ni vers le bas. Très pratique, en fait.
Fonctionnement de cette approche
Il est important de bien comprendre pourquoi cela fonctionne, car nous allons l'utiliser
connaissances. Le défilement est effectivement une transformation, c'est pourquoi il peut être
accelerated; cela implique principalement le déplacement des
couches avec le GPU. Dans un
c'est-à-dire sans aucune notion de perspective,
se produit de manière 1:1 lors de la comparaison de l'élément défilant et de ses enfants.
Si vous faites défiler un élément de 300px
vers le bas, ses enfants sont transformés vers le haut
du même montant: 300px
.
Cependant, l'application d'une valeur de perspective à l'élément de défilement perturbe
dans ce processus ; cela modifie les matrices sous-jacentes
à la transformation de défilement.
Désormais, un défilement de 300 pixels ne peut déplacer les enfants que de 150 pixels, selon
Valeurs perspective
et translateZ
que vous avez choisies. Si un élément possède une
translateZ
définie sur 0, le défilement est effectué à 1:1 (comme c'était le cas auparavant), mais un élément enfant
déplacé en Z en dehors de l'origine de la perspective sera défilé à une position différente
votre note ! Résultat net: mouvement parallaxe. Et, très important, cela est traité comme
une partie de la machine de défilement interne du navigateur, ce qui signifie
pas besoin d'écouter les événements scroll
ni de modifier background-position
.
Une mouche en pot: Safari sur mobile
Chaque effet fait l'objet de mises en garde, et il est important de noter que la préservation des effets 3D sur les éléments enfants. S'il y a des éléments dans hiérarchie entre l'élément avec une perspective et ses enfants parallaxes, la perspective 3D est "aplatie", ce qui signifie que l'effet est perdu.
<div class="container">
<div class="parallax-container">
<div class="parallax-child"></div>
</div>
</div>
Dans le code HTML ci-dessus, le .parallax-container
est nouveau et
aplatir la valeur perspective
et perdre l'effet de parallaxe. La solution,
dans la plupart des cas, est assez simple: vous ajoutez transform-style: preserve-3d
à l'élément, ce qui entraîne la propagation d'effets 3D (comme notre perspective
) appliquées plus haut dans l'arborescence.
.parallax-container {
transform-style: preserve-3d;
}
Dans le cas de Safari pour mobile, les choses sont un peu plus compliquées.
Techniquement, appliquer overflow-y: scroll
à l'élément conteneur fonctionne, mais au
le coût de la possibilité
de faire glisser l'élément de défilement. La solution consiste à ajouter
-webkit-overflow-scrolling: touch
, mais cela va aussi aplatir perspective
et nous n'aurons pas de parallaxe.
D'un point de vue d'amélioration progressive, ce n'est probablement pas trop problème. Si nous ne pouvons pas parallaxe dans toutes les situations, notre application continuera de fonctionner, il serait bon de trouver une solution de contournement.
position: sticky
à la rescousse !
Il existe en fait de l'aide sous la forme de position: sticky
, qui permet
autoriser les éléments à "s'en tenir" en haut de la fenêtre d'affichage ou d'un élément parent donné
pendant le défilement. Les spécifications, comme la plupart d'entre elles, sont assez lourdes, mais elles contiennent
petit bijou pratique dans:
Cela ne semble peut-être pas grand-chose à première vue, mais un point clé dans cette phrase lorsqu'elle fait référence à la façon dont l'adhésion d'un élément compute: "le décalage est calculé par rapport à l'ancêtre le plus proche à l'aide d'une zone de défilement. En d'autres termes, la distance pour déplacer l'élément collant (pour qu'elle apparaisse associée à un autre élément ou à la fenêtre d'affichage) est Elle est calculée avant l'application de toute autre transformation, et non après. Cela signifie comme dans l'exemple de défilement précédent, si le décalage a été calculé à 300 px, vous pouvez profiter d'une nouvelle opportunité d'utiliser des perspectives (ou toute autre transformation) pour manipuler cette valeur de décalage de 300 pixels avant de l'appliquer à des blocs éléments.
En appliquant position: -webkit-sticky
à l'élément de parallaxe, nous pouvons
« inverser » efficacement l'effet d'aplatissement de -webkit-overflow-scrolling:
touch
. Cela garantit que l'élément de parallaxe fait référence à la
avec une zone de défilement (.container
dans le cas présent). Ensuite,
comme précédemment, .parallax-container
applique une valeur perspective
,
ce qui modifie le décalage de défilement calculé et crée un effet de parallaxe.
<div class="container">
<div class="parallax-container">
<div class="parallax-child"></div>
</div>
</div>
.container {
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
}
.parallax-container {
perspective: 1px;
}
.parallax-child {
position: -webkit-sticky;
top: 0px;
transform: translate(-2px) scale(3);
}
Cela permet de rétablir l'effet de parallaxe pour Safari sur mobile, ce qui est une excellente nouvelle. ronde !
Mises en garde concernant le positionnement persistant
Il y a cependant une différence dans le cas présent: position: sticky
modifie le
la mécanique parallaxe. Le positionnement persistant permet de faire adhérer l'élément au
conteneur à défilement, contrairement à une version non persistante. Cela signifie que
parallaxe avec fixation finira par être l'inverse
de celui sans:
- Avec
position: sticky
, plus l'élément est proche de z=0, moins il est moins. se déplace. - Sans
position: sticky
, plus l'élément est proche de z=0, plus il bouge.
Si tout cela vous semble un peu abstrait, regardez cette démonstration de Robert Flack, montre comment les éléments se comportent différemment avec et sans de votre application. Pour voir la différence, vous avez besoin de Chrome Canary (version 56). au moment de la rédaction de cet article) ou Safari.
Une démonstration de Robert Flack,
position: sticky
affecte le défilement parallaxe.
Divers bugs et solutions de contournement
Mais comme pour tout, il reste des bosses et des bosses lissées:
- L'assistance persistante est incohérente. La prise en charge est toujours en cours
Chrome, Edge n'est pas du tout compatible et Firefox peint des bugs lorsque l'image fixe est combinée à des transformations de perspective. Dans ces
il peut être utile d'ajouter du code pour n'ajouter que
position: sticky
(le version avec préfixe-webkit-
) lorsque cela est nécessaire, c'est-à-dire pour Safari sur mobile. uniquement. - L'effet ne "fonctionne pas simplement" dans Edge. Edge essaie de gérer le défilement à au niveau du système d'exploitation, ce qui est généralement une bonne chose, mais dans ce cas, cela l'empêche de détecter les changements de perspective lors du défilement. Pour résoudre ce problème, vous pouvez ajouter un élément de position fixe, car cela semble basculer Edge vers une méthode de défilement sans OS, et s'assure qu'elle tient compte des changements de perspective.
- "Le contenu de la page est devenu énorme !" De nombreux navigateurs tiennent compte de l'échelle
pour déterminer la taille du contenu de la page, mais malheureusement, Chrome et Safari
ne tiennent pas compte de la perspective. Donc
si une échelle de 3 x est appliquée à un élément, vous pouvez
les barres de défilement et d'autres éléments similaires, même si l'élément est 1x après le début
"
perspective
" a été appliqué. Il est possible de contourner ce problème en de mise à l'échelle des éléments à partir de l'angle inférieur droit (avectransform-origin: bottom right
), ce qui permet aux éléments surdimensionnés de se développer "région à exclure" (généralement en haut à gauche) de la zone déroulante ; à faire défiler ne vous permettent jamais de voir ni de faire défiler la page vers le contenu correspondant à la zone négative.
Conclusion
Le parallaxe est un effet amusant lorsqu'il est utilisé de manière réfléchie. Comme vous le voyez, il est possible pour l'implémenter de manière performante, couplée au défilement et multinavigateur. Puisqu'il faut un peu de gribouillissement mathématique et une petite quantité de code récurrent pour obtenir l'effet souhaité, nous avons créé une petite bibliothèque d'aide et exemple, que vous pouvez trouver dans notre dépôt GitHub d'exemples d'éléments d'interface utilisateur.
Jouez et dites-nous comment vous vous en sortez.