J'ai une div dans laquelle j'anime le contenu:
#container {
position: relative;
width: 100px;
height: 100px;
border-style: inset;
}
#content {
visibility: hidden;
-webkit-animation: animDown 1s ease;
position: absolute;
top: 100px;
width: 100%;
height: 100%;
background-color: lightgreen;
}
#container:hover #content {
-webkit-animation: animUp 1s ease;
animation-fill-mode: forwards;
-webkit-animation-fill-mode: forwards;
}
@-webkit-keyframes animUp {
0% {
-webkit-transform: translateY(0);
visibility: hidden;
opacity: 0;
}
100% {
-webkit-transform: translateY(-100%);
visibility: visible;
opacity: 1;
}
}
@-webkit-keyframes animDown {
0% {
-webkit-transform: translateY(-100%);
visibility: visible;
opacity: 1;
}
100% {
-webkit-transform: translateY(0);
visibility: hidden;
opacity: 0;
}
}
<div id="container">
<div id="content"></div>
</div>
Au survol, le contenu glisse dans la div du conteneur. Mon problème est que lorsque j'actualise la page et que la page charge l'animation animDown de #content
S'exécute, et je préfère qu'elle ne s'exécute qu'après un survol.
Existe-t-il un moyen de faire ce CSS pur, ou je dois trouver quelque chose dans JS?
Solution 1 - Ajouter une animation au premier survol
La meilleure option est probablement de ne pas activer l'animation de down tant que l'utilisateur n'a pas survolé la container
pour la première fois.
Cela implique d'écouter l'événement mouseover
puis d'ajouter une classe avec l'animation à ce stade et de supprimer l'écouteur d'événement. Le principal inconvénient (potentiel) de cela est qu'il repose sur Javascript.
;(function(){
var c = document.getElementById('container');
function addAnim() {
c.classList.add('animated')
// remove the listener, no longer needed
c.removeEventListener('mouseover', addAnim);
};
// listen to mouseover for the container
c.addEventListener('mouseover', addAnim);
})();
#container {
position:relative;
width:100px;
height:100px;
border-style:inset;
}
#content {
position:absolute;
top:100px;
width:100%;
height:100%;
background-color:lightgreen;
opacity:0;
}
/* This gets added on first mouseover */
#container.animated #content {
-webkit-animation:animDown 1s ease;
}
#container:hover #content {
-webkit-animation:animUp 1s ease;
animation-fill-mode:forwards;
-webkit-animation-fill-mode:forwards;
}
@-webkit-keyframes animUp {
0% {
-webkit-transform:translateY(0);
opacity:0;
}
100% {
-webkit-transform:translateY(-100%);
opacity:1;
}
}
@-webkit-keyframes animDown {
0% {
-webkit-transform:translateY(-100%);
opacity:1;
}
100% {
-webkit-transform:translateY(0);
opacity:0;
}
}
<div id="container">
<div id="content"></div>
</div>
Solution 2 - jouer l'animation cachée
Une autre solution consiste à masquer initialement l'élément, à vous assurer que l'animation est lue pendant qu'elle est masquée, puis à la rendre visible. L'inconvénient est que le timing pourrait être légèrement décalé et qu'il est rendu visible trop tôt, et que le vol stationnaire n'est pas disponible immédiatement.
Cela nécessite du Javascript qui attend la durée de l'animation et ne fait alors que #content
visible. Cela signifie que vous devez également définir le opacity
initial sur 0
donc il n'apparaît pas lors du chargement et supprime également le visibility
des images clés - ceux-ci ne font rien de toute façon:
// wait for the animation length, plus a bit, then make the element visible
window.setTimeout(function() {
document.getElementById('content').style.visibility = 'visible';
}, 1100);
#container {
position:relative;
width:100px;
height:100px;
border-style:inset;
}
#content {
visibility:hidden;
-webkit-animation:animDown 1s ease;
position:absolute;
top:100px;
width:100%;
height:100%;
background-color:lightgreen;
opacity:0;
}
#container:hover #content {
-webkit-animation:animUp 1s ease;
animation-fill-mode:forwards;
-webkit-animation-fill-mode:forwards;
}
@-webkit-keyframes animUp {
0% {
-webkit-transform:translateY(0);
opacity:0;
}
100% {
-webkit-transform:translateY(-100%);
opacity:1;
}
}
@-webkit-keyframes animDown {
0% {
-webkit-transform:translateY(-100%);
opacity:1;
}
100% {
-webkit-transform:translateY(0);
opacity:0;
}
}
<div id="container">
<div id="content"></div>
</div>
Solution 3 - Utiliser des transitions
Dans votre scénario, vous pouvez créer ce CSS uniquement en remplaçant les keyframe
s par un transition
à la place, il commence donc par opacity:0
et juste le survol a un changement dans opacity
et le transform
:
#container {
position:relative;
width:100px;
height:100px;
border-style:inset;
}
#content {
position:absolute;
top:100px;
width:100%;
height:100%;
background-color:lightgreen;
/* initial state - hidden */
opacity:0;
/* set properties to animate - applies to hover and revert */
transition:opacity 1s, transform 1s;
}
#container:hover #content {
/* Just set properties to change - no need to change visibility */
opacity:1;
-webkit-transform:translateY(-100%);
transform:translateY(-100%);
}
<div id="container">
<div id="content"></div>
</div>
J'ai toujours défini la classe de préchargement sur body avec une valeur de temps d'animation de 0 et son fonctionnement plutôt bien. J'ai des transitions en arrière donc je dois aussi leur retirer l'animation de chargement. J'ai résolu ce problème en définissant temporairement le temps d'animation sur 0. Vous pouvez modifier les transitions en fonction des vôtres.
HTML
... <body class="preload">...
CSS met l'animation à 0s
body.preload *{
animation-duration: 0s !important;
-webkit-animation-duration: 0s !important;
transition:background-color 0s, opacity 0s, color 0s, width 0s, height 0s, padding 0s, margin 0s !important;}
JS supprimera la classe après un certain délai afin que les animations puissent se produire en temps normal :)
setTimeout(function(){
document.body.className="";
},500);
Existe-t-il un moyen de faire ce CSS pur?
Oui, absolument: voir la fourchette http://jsfiddle.net/5r32Lsme/2/ Il n'y a vraiment pas besoin de JS.
et je préfère qu'il ne s'exécute qu'après un vol stationnaire.
Vous devez donc dire à CSS ce qui se passe quand ce n'est PAS un événement de survol également - dans votre exemple:
#container:not(:hover) #content {
visibility: hidden;
transition: visibility 0.01s 1s;
}
Mais il y a deux choses à noter:
1) Le délai de transition ci-dessus doit correspondre à la durée de votre animation
2) Vous ne pouvez pas utiliser la propriété que vous utilisez pour masquer l'animation onLoad dans l'animation. Si vous avez besoin de visibilité dans l'animation, masquez l'animation initialement comme par ex.
#container:not(:hover) #content {
top: -8000px;
transition: top 0.01s 1s;
}
Un sidenote:
Il est recommandé de mettre les propriétés CSS natives après celles préfixées, il devrait donc être
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
et maintenant il y a une transformation native
-webkit-transform: translateY(0);
transform: translateY(0);
Ce n'est pas du CSS pur mais peut-être que quelqu'un tombera sur ce fil comme je l'ai fait:
Dans React j'ai résolu cela en définissant une classe temporaire dans ComponentDidMount () comme ceci:
componentDidMount = () => {
document.getElementById("myContainer").className =
"myContainer pageload";
};
puis en css:
.myContainer.pageload {
animation: none;
}
.myContainer.pageload * {
animation: none;
}
Si vous n'êtes pas familier, le "*" (n.b. l'espace) ci-dessus signifie qu'il s'applique également à tous les descendants de l'élément. L'espace signifie tous les descendants et l'astérisque est un opérateur générique qui fait référence à tous les types d'éléments.
Si vous envisagez cela après 2019, une meilleure solution est la suivante:
let div = document.querySelector('div')
document.addEventListener('DOMContentLoaded', () => {
// Adding timeout to simulate the loading of the page
setTimeout(() => {
div.classList.remove('prevent-animation')
}, 2000)
document.querySelector('button').addEventListener('click', () => {
if(div.classList.contains('after')) {
div.classList.remove('after')
} else {
div.classList.add('after')
}
})
})
div {
background-color: purple;
height: 150px;
width: 150px;
}
.animated-class {
animation: animationName 2000ms;
}
.animated-class.prevent-animation {
animation-duration: 0ms;
}
.animated-class.after {
animation: animation2 2000ms;
background-color: orange;
}
@keyframes animationName {
0% {
background-color: red;
}
50% {
background-color: blue;
}
100% {
background-color: purple;
}
}
@keyframes animation2 {
0% {
background-color: salmon;
}
50% {
background-color: green;
}
100% {
background-color: orange;
}
}
<div class="animated-class prevent-animation"></div>
<button id="btn">Toggle between animations</button>
Animation de rotation qui (apparaît) pour ne pas s'exécuter jusqu'à ce qu'elle soit nécessaire.
Le CSS ci-dessous permet des flèches haut et bas pour afficher les éléments de menu. L'animation ne semble pas s'exécuter au chargement de la page, mais c'est vraiment le cas.
@keyframes rotateDown {
from { transform: rotate(180deg); }
to { transform: rotate(0deg); }
}
@keyframes rotateUp {
from { transform: rotate(180deg); }
to { transform: rotate(0deg); }
}
div.menu input[type='checkbox'] + label.menu::before {
display :inline-block;
content : "▼";
color : #b78369;
opacity : 0.5;
font-size : 1.2em;
}
div.menu input[type='checkbox']:checked + label.menu::before {
display : inline-block;
content : "▲";
color : #b78369;
opacity : 0.5;
font-size : 1.2em;
}
div.menu input[type='checkbox'] + label.menu {
display : inline-block;
animation-name : rotateDown;
animation-duration : 1ms;
}
div.menu input[type='checkbox']:checked + label.menu {
display : inline-block;
animation-name : rotateUp;
animation-duration : 1ms;
}
div.menu input[type='checkbox'] + label.menu:hover {
animation-duration : 500ms;
}
div.menu input[type='checkbox']:checked + label.menu:hover {
animation-duration : 500ms;
}
Du haut jusqu'en bas: