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

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

65541 次浏览

解决方案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-使用过渡

在您的场景中,您只能通过将 keyframe替换为 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>

我总是设置预加载类体与动画时间值0和它的工作相当不错。我有一些回去过渡,所以我必须删除加载动画他们太。我通过将动画时间临时设置为0来解决这个问题。您可以更改转换以匹配您的转换。

超文本标示语言

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

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 会在一些延迟后移除类,这样动画就可以在正常时间发生:)

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

直到需要才运行的旋转动画。
下面的 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. 我们把动画放在标签上。没有什么特别的,那里,除了动画的持续时间是1毫秒。
  4. 鼠标驱动动画速度 。当鼠标悬停在元素上时,动画持续时间被设置为看起来足够平滑的时间。

在我的网站上工作

有没有办法做到这一点纯 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);

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

在 React 中,我通过像下面这样在 Component DidMount ()中设置一个临时类来解决这个问题:

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

然后是 css:

.myContainer.pageload {
animation: none;
}


.myContainer.pageload * {
animation: none;
}

如果您不熟悉上面的“ *”(n.b. 空格)表示它也适用于元素的所有后代。空格表示所有的子元素,星号是一个通配符,它引用所有类型的元素。

如果你打算在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>

基于 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;
}

不依赖 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;
}
}

必须解决类似的挑战,一个整洁的 CSS-only Trick Morewry 发布的已经回到2013年是创建一个动画,最初是在一个暂停的 游戏状态关键帧隐藏元素:

#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! */
}

当鼠标悬停时,非常简短的动画转换被应用,并保持在100%-关键帧状态,即使鼠标-离开感谢 animation-fill-mode

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