web-dev-qa-db-fra.com

Comment empêcher l'animation d'images clés CSS de s'exécuter au chargement de la page?

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?

http://jsfiddle.net/d0yhve8y/

39
Eduárdó

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 keyframes 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>
17
Rhumborl

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);
58
Tominator

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);
3
sebilasse

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.

1
ClownBaby

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>
0
Guilherme P.

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:

  1. Créez les rotations. Pour cela, il y en a deux ... un pour la flèche vers le bas et un pour la flèche vers le haut. Deux flèches sont nécessaires, car, après la rotation, elles reviennent à leur état naturel. Ainsi, la flèche vers le bas démarre et tourne vers le bas, tandis que la flèche vers le haut commence vers le bas et tourne vers le haut.
  2. Créez les petites flèches. Ceci est une implémentation simple de :: before
  3. Nous avons mis l'animation sur l'étiquette. Il n'y a rien de spécial, là, sauf que la durée de l'animation est de 1ms.
  4. La souris pilote la vitesse d'animation . Lorsque la souris survole l'élément, la durée de l'animation est définie sur suffisamment de temps pour sembler fluide.

Travailler sur mon site

0
user1126454