CSS 如何防止css关键帧动画在页面加载时运行?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27938900/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 02:54:36  来源:igfitidea点击:

How to prevent css keyframe animation to run on page load?

cssanimationkeyframe

提问by Eduárdó

I have a div in which I animate the content:

我有一个 div,我可以在其中对内容进行动画处理:

#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>

On hover content slides into the container div. My problem is, when I refresh the page, and the page loads the #content's animDown animation will run, and I'd prefer it to run only after a hover event.

悬停内容滑入容器 div。我的问题是,当我刷新页面并加载页面时,#content将运行 animDown 动画,我希望它仅在悬停事件之后运行。

Is there a way to do this pure CSS, or I have to figure something out in JS?

有没有办法做这个纯 CSS,或者我必须在 JS 中找出一些东西?

http://jsfiddle.net/d0yhve8y/

http://jsfiddle.net/d0yhve8y/

采纳答案by Rhumborl

Solution 1 - Add down animation on first hover

解决方案 1 - 在第一次悬停时添加向下动画

Probably the best option is to not put the down animation on until the user has hovered over the containerfor the first time.

可能最好的选择是在用户container第一次将鼠标悬停在 上之前不要打开向下动画。

This involves listening to the mouseoverevent then adding a class with the animation at that point, and removing the event listener. The main (potential) downside of this is it relies on Javascript.

这涉及侦听mouseover事件,然后在该点添加带有动画的类,并删除事件侦听器。这的主要(潜在)缺点是它依赖于 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 - play animation hidden

解决方案 2 - 播放隐藏的动画

Another way around this is to initially hide the element, make sure the animation plays while it is hidden, then make it visible. The downside of this is that the timing could be slightly off and it is made visible too early, and also the hover isn't available straight away.

解决此问题的另一种方法是最初隐藏元素,确保动画在隐藏时播放,然后使其可见。这样做的缺点是时间可能会稍微偏离,并且过早地显示出来,而且悬停也无法立即使用。

This requires some Javascript which waits for the length of the animation and only then makes #contentvisible. This means you also need to set the initial opacityto 0so it doesn't appear on load and also remove the visibilityfrom the keyframes - these aren't doing anything anyway:

这需要一些 Javascript 等待动画的长度,然后才#content可见。这意味着您还需要将初始设置为opacity0以便它不会在加载时出现并visibility从关键帧中删除- 这些无论如何都不会做任何事情:

// 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 - Use transitions

解决方案 3 - 使用过渡

In your scenario, you can make this CSS only by replacing the keyframes with a transitioninstead, so it starts with opacity:0and just the hover has a change in opacityand the transform:

在您的场景中,您只能通过将keyframes替换为atransition来制作此 CSS ,因此它以 开头opacity:0并且只是悬停在opacity和 中发生了变化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>

回答by Tominator

I always set preload class to body with animation time value 0 and its working pretty well. I have some back going transitions so I have to remove load animation to them too. I solved this by temporary setting animation time to 0. You can change transitions to match yours.

我总是将预加载类设置为动画时间值为 0 的主体,并且它工作得很好。我有一些返回的过渡,所以我也必须删除它们的加载动画。我通过将动画时间临时设置为 0 解决了这个问题。您可以更改过渡以匹配您的过渡。

HTML

HTML

... <body class="preload">...

... <body class="preload">...

CSS is setting animation to 0s

CSS 正在将动画设置为 0

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 will remove class after some delay so animations can happen in normal time :)

JS 将在一些延迟后删除类,因此动画可以在正常时间发生:)

setTimeout(function(){
    document.body.className="";
},500);

回答by sebilasse

Is there a way to do this pure CSS ?

有没有办法做到这一点纯 CSS ?

Yes, absolutely : See the fork http://jsfiddle.net/5r32Lsme/2/There is really no need for JS.

是的,绝对:见fork http://jsfiddle.net/5r32Lsme/2/真的不需要JS。

and I'd prefer it to run only after a hover event.

我更喜欢它只在悬停事件之后运行。

So you need to tell CSS what happens when it is NOT a hover event as well - in your example :

所以你需要告诉 CSS 当它不是悬停事件时会发生什么 - 在你的例子中:

#container:not(:hover) #content {
  visibility: hidden;
  transition: visibility 0.01s 1s;
}

But there are two things to note:

但是有两点需要注意:

1) The transition delay above should match your animation duration

1) 上面的过渡延迟应该与您的动画持续时间相匹配

2) You can't use the property which you use to hide the animation onLoad in the animation. If you do need visibilityin the animation, hide the animation initially like e.g.

2)您不能使用用于隐藏动画中的动画 onLoad 的属性。如果您确实需要动画中的可见性,请先隐藏动画,例如

#container:not(:hover) #content {
  top: -8000px;
  transition: top 0.01s 1s;
}    

A sidenote:

旁注:

It is recommended to put native CSS properties after prefixed ones, so it should be

建议将原生 CSS 属性放在前缀之后,所以应该是

-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;

and now there is a native transform

现在有一个原生转换

-webkit-transform: translateY(0);
transform: translateY(0);

回答by ClownBaby

This is not pure CSS but maybe someone will stumble across this thread as I did:

这不是纯 CSS,但也许有人会像我一样偶然发现这个线程:

In React I solved this by setting a temporary class in ComponentDidMount() like so:

在 React 中,我通过在 ComponentDidMount() 中设置一个临时类来解决这个问题,如下所示:

componentDidMount = () => {
    document.getElementById("myContainer").className =
        "myContainer pageload";
};

and then in css:

然后在 css 中:

.myContainer.pageload {
    animation: none;
}

.myContainer.pageload * {
    animation: none;
}

If you are not familiar the " *" (n.b. the space) above means that it applies to all descendents of the element as well. The space means all descendents and the asterisk is a wildcard operator that refers to all types of elements.

如果您不熟悉上面的“*”(注意空格)意味着它也适用于元素的所有后代。空格表示所有后代,星号是通配符,表示所有类型的元素。

回答by Guilherme P.

If you're looking at this after 2019, a better solution is this:

如果您在 2019 年之后查看此内容,则更好的解决方案是:

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>

回答by user1126454

Rotation animation that (appears) not to run until needed.
The CSS below allows for up and down arrows for showing menu items. The animation does not appear to run on page load, but it really does.

旋转动画(似乎)在需要时才运行。
下面的 CSS 允许使用向上和向下箭头来显示菜单项。动画似乎不会在页面加载时运行,但确实如此。

@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;
}

From top to bottom:

从上到下:

  1. Create the rotations. For this there are two... one for the down arrow and one for the up arrow. Two arrows are needed, because, after the rotation, they return to their natural state. So, the down arrow starts up and rotates down, while the up arrow starts down and rotates up.
  2. Create the little arrows. This is a straight forward implementation of ::before
  3. We put the animation on the label. There is nothing special, there, except that the animation duration is 1ms.
  4. The mouse drives the animation speed. When the mouse hovers over the element, the animation-duration is set to enough time to seem smooth.
  1. 创建旋转。为此,有两个......一个用于向下箭头,一个用于向上箭头。需要两支箭,因为旋转后,它们会恢复到自然状态。因此,向下箭头开始向上并向下旋转,而向上箭头向下开始向上旋转。
  2. 创建小箭头。这是 ::before 的直接实现
  3. 我们把动画放在标签上。没有什么特别的,除了动画持续时间是 1 毫秒。
  4. 鼠标驱动动画速度。当鼠标悬停在元素上时,动画持续时间设置为足够的时间以看起来平滑。

Working on my site

在我的网站上工作

回答by VocoJax

Building off of Tominator's answer, in React, you can apply it per component like so:

基于 Tominator 的回答,在 React 中,您可以像这样为每个组件应用它:

import React, { Component } from 'react'

export default class MyThing extends Component {
  constructor(props) {
    super(props);

    this.state = {
      preloadClassName: 'preload'
    }
  }

  shouldComponentUpdate(nextProps, nextState) {
    return nextState.preloadClassName !== this.state.preloadClassName;
  }

  componentDidUpdate() {
    this.setState({ preloadClassName: null });
  }

  render() {
    const { preloadClassName } = this.state;

    return (
      <div className={`animation-class ${preloadClassName}`}>
        <p>Hello World!</p>
      </div>
    )
  }
}

and the css class:

和 css 类:

.preload * {
  -webkit-animation-duration: 0s !important;
  animation-duration: 0s !important;
  transition: background-color 0s, opacity 0s, color 0s, width 0s, height 0s, padding 0s, margin 0s !important;
}