【问题标题】:How to prevent a CSS keyframe animation from running on page load?如何防止css关键帧动画在页面加载时运行?
【发布时间】:2015-03-12 09:33:18
【问题描述】:

我有一个 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>

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

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

http://jsfiddle.net/d0yhve8y/

【问题讨论】:

标签: css animation keyframe


【解决方案1】:

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

HTML

... &lt;body class="preload"&gt;...

CSS 将动画设置为 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 会在延迟一段时间后移除类,因此动画可以在正常时间发生:)

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

【讨论】:

  • 感谢您的解决方案。
  • 绝对实用,就像做梦一样。非常感谢。这是一个正确的答案。
  • 简单有效。谢谢!
  • 天哪,它奏效了。给 Tominator 接受的答案!
  • DOMContentLoaded 在这里效果很好,效率更高:document.addEventListener("DOMContentLoaded", () =&gt; document.body.className = "")
【解决方案2】:

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

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

这涉及监听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>

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

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

这需要一些 Javascript 来等待动画的长度,然后才使 #content 可见。这意味着您还需要将初始的opacity 设置为0,这样它就不会出现在加载中,并且还需要从关键帧中删除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>

解决方案 3 - 使用过渡

在您的场景中,您只能通过将keyframes 替换为transition 来制作此CSS,因此它以opacity:0 开头,并且只是悬停在opacitytransform 中发生了变化:

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

【讨论】:

  • OP 标记为keyframe,所以我相信他想要一个关键帧解决方案。
  • @Vucko 同样的想法也可以用在关键帧上
  • @Kaiido 我不同意,但你能证明一下吗?
  • @Vucko 我最初的回答是解决 OP 遇到的问题并给出相同的行为。发布的代码中只有 2 个关键帧,因此大部分转换是等效的。
  • @Vucko,对不起,我错了,使用 webkit 浏览器似乎是不可能的。如果转换是由动画进行的,就好像它们不会触发转换(即使getBoundingClientRect()确实注意到了转换)。我确实尝试过使用 FF,它确实有效:jsfiddle.net/d0yhve8y/5
【解决方案3】:

有没有办法做这个纯 CSS ?

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

而且我希望它只在悬停事件之后运行。

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

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

但有两点需要注意:

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

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

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

附注:

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

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

现在有一个原生的变换

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

【讨论】:

  • 当你肯定可以使用#container #content 时,为什么还要使用#container:not(:hover) #content
  • 完美!也谢谢你的例子
【解决方案4】:

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

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

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

然后在css中:

.myContainer.pageload {
    animation: none;
}

.myContainer.pageload * {
    animation: none;
}

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

【讨论】:

    【解决方案5】:

    如果您在 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>

    【讨论】:

      【解决方案6】:

      不依赖 javascript 的解决方案总是更好。

      这里提到的带有 CSS 的都可以。在某些情况下,在鼠标悬停时隐藏的想法很好,但我注意到如果我希望在鼠标移出元素时发生动画,由于 :not(:hover) 规则,它不会发生.

      我想出的解决方案对我来说效果最好,通过向父元素添加动画,它只会在相同的持续时间下增加最后的不透明度。显示比解释容易:

      我抓住了@sebilasse 和@9000 制作的小提琴,并在那里添加了以下代码:

      https://jsfiddle.net/marcosrego/vqo3sr8z/2/

      #container{
          animation: animShow 1s forwards;    
      }
      
      @keyframes animShow {
          0% {
            opacity: 0;
          }
          99% {
            opacity: 0;
          }
          100% {
            opacity: 1;
          }
      }
      

      【讨论】:

        【解决方案7】:

        Rotation animation that (appears) not to run until needed.
        下面的 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;
        }
        

        从上到下:

        1. 创建旋转。为此,有两个...一个用于向下箭头,一个用于向上箭头。需要两个箭头,因为在旋转之后,它们会恢复到自然状态。因此,向下箭头开始并向下旋转,而向上箭头开始向下并向上旋转。
        2. 创建小箭头。这是 ::before 的直接实现
        3. 我们将动画放在标签上。没什么特别的,除了动画持续时间是 1ms。
        4. 鼠标驱动动画速度。当鼠标悬停在元素上时,animation-duration 设置为足够平滑的时间。

        Working on my site

        【讨论】:

          【解决方案8】:

          必须解决一个类似的挑战,一个简洁的纯 CSS trick morewry posted 早在 2013 年就可以创建一个动画,该动画最初位于隐藏元素的关键帧上的暂停 play-state

          #content {
            animation:animDown 1s ease, hasHovered 1ms paused;
            animation-fill-mode: forwards; /* for both animations! */
          }
          #container:hover #content {
            animation:animUp 1s ease, hasHovered 1ms;
          }
          
          /* hide #content element until #container has been hovered over */
          @keyframes hasHovered {
            0% { visibility: hidden; }     /* property has to be removed */
            100% { visibility: visible; }  /* from the other animations! */
          }
          

          悬停时,由于animation-fill-mode,即使鼠标离开后,也会应用非常简短的动画变换并保持在 100% 关键帧状态。

          关于如何设置animation的多个动画子属性,见https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations#setting_multiple_animation_property_values

          【讨论】:

            【解决方案9】:

            根据 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>
                )
              }
            }
            

            还有 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;
            }
            

            【讨论】:

              猜你喜欢
              • 2016-12-26
              • 2014-06-09
              • 2013-11-02
              • 1970-01-01
              • 2012-06-29
              • 1970-01-01
              • 2013-08-12
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多