如何防止 CSS 关键帧动画在页面加载时出现 运行?
How to prevent a CSS keyframe animation from running on page load?
我有一个 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 中弄清楚一些东西?
解决方案 1 - 在第一次悬停时添加向下动画
可能最好的选择是在用户第一次将鼠标悬停在 container
上之前不打开按下动画。
这涉及侦听 mouseover
事件,然后在该点添加带有动画的 class,并删除事件侦听器。这样做的主要(潜在)缺点是它依赖于 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
开头,并且只是悬停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>
我总是将预加载 class 设置为动画时间值为 0 的主体,并且效果很好。我有一些反向过渡,所以我也必须删除它们的加载动画。我通过临时将动画时间设置为 0 解决了这个问题。您可以更改过渡以匹配您的过渡。
HTML
... <body class="preload">...
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 将在一些延迟后删除 class,以便动画可以在正常时间发生 :)
setTimeout(function(){
document.body.className="";
},500);
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;
}
从上到下:
- 创建旋转。为此,有两个……一个用于向下箭头,一个用于向上箭头。需要两个箭头,因为在旋转之后,它们 return 回到自然状态。因此,向下箭头开始向上并向下旋转,而向上箭头开始向下并向上旋转。
- 创建小箭头。这是 ::before
的直接实现
- 我们把动画放在标签上。没有什么特别的,除了动画持续时间是 1ms。
- 鼠标驱动动画速度。当鼠标悬停在元素上时,动画持续时间设置为足够长的时间以使其看起来平滑。
Is there a way to do this pure CSS ?
是的,绝对是:见分叉http://jsfiddle.net/5r32Lsme/2/
真的不需要JS了
and I'd prefer it to run only after a hover event.
所以你需要告诉 CSS 当它不是悬停事件时会发生什么 - 在你的例子中:
#container:not(:hover) #content {
visibility: hidden;
transition: visibility 0.01s 1s;
}
但是有两点需要注意:
1) 上面的过渡延迟应该匹配你的动画持续时间
2) 不能在动画中使用隐藏动画onLoad的属性。
如果您确实需要动画中的 visibility,请先隐藏动画,例如
#container:not(:hover) #content {
top: -8000px;
transition: top 0.01s 1s;
}
旁注:
建议将原生CSS属性放在前缀属性之后,所以应该是
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
现在有原生 transform
-webkit-transform: translateY(0);
transform: translateY(0);
这不是纯粹的 CSS 但也许有人会像我一样偶然发现这个线程:
在 React 中,我通过在 ComponentDidMount() 中设置一个临时 class 来解决这个问题,如下所示:
componentDidMount = () => {
document.getElementById("myContainer").className =
"myContainer pageload";
};
然后在 css:
.myContainer.pageload {
animation: none;
}
.myContainer.pageload * {
animation: none;
}
如果您不熟悉上面的“*”(n.b。space)意味着它也适用于该元素的所有后代。 space 表示所有后代,星号是指所有类型元素的通配符。
如果您在 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 class:
.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 制作的 fiddle 并在那里添加了以下代码:
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 posted already back in 2013 is to create an animation that initially is in a paused 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
我有一个 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 中弄清楚一些东西?
解决方案 1 - 在第一次悬停时添加向下动画
可能最好的选择是在用户第一次将鼠标悬停在 container
上之前不打开按下动画。
这涉及侦听 mouseover
事件,然后在该点添加带有动画的 class,并删除事件侦听器。这样做的主要(潜在)缺点是它依赖于 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
开头,并且只是悬停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>
我总是将预加载 class 设置为动画时间值为 0 的主体,并且效果很好。我有一些反向过渡,所以我也必须删除它们的加载动画。我通过临时将动画时间设置为 0 解决了这个问题。您可以更改过渡以匹配您的过渡。
HTML
... <body class="preload">...
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 将在一些延迟后删除 class,以便动画可以在正常时间发生 :)
setTimeout(function(){
document.body.className="";
},500);
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;
}
从上到下:
- 创建旋转。为此,有两个……一个用于向下箭头,一个用于向上箭头。需要两个箭头,因为在旋转之后,它们 return 回到自然状态。因此,向下箭头开始向上并向下旋转,而向上箭头开始向下并向上旋转。
- 创建小箭头。这是 ::before 的直接实现
- 我们把动画放在标签上。没有什么特别的,除了动画持续时间是 1ms。
- 鼠标驱动动画速度。当鼠标悬停在元素上时,动画持续时间设置为足够长的时间以使其看起来平滑。
Is there a way to do this pure CSS ?
是的,绝对是:见分叉http://jsfiddle.net/5r32Lsme/2/ 真的不需要JS了
and I'd prefer it to run only after a hover event.
所以你需要告诉 CSS 当它不是悬停事件时会发生什么 - 在你的例子中:
#container:not(:hover) #content {
visibility: hidden;
transition: visibility 0.01s 1s;
}
但是有两点需要注意:
1) 上面的过渡延迟应该匹配你的动画持续时间
2) 不能在动画中使用隐藏动画onLoad的属性。 如果您确实需要动画中的 visibility,请先隐藏动画,例如
#container:not(:hover) #content {
top: -8000px;
transition: top 0.01s 1s;
}
旁注:
建议将原生CSS属性放在前缀属性之后,所以应该是
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
现在有原生 transform
-webkit-transform: translateY(0);
transform: translateY(0);
这不是纯粹的 CSS 但也许有人会像我一样偶然发现这个线程:
在 React 中,我通过在 ComponentDidMount() 中设置一个临时 class 来解决这个问题,如下所示:
componentDidMount = () => {
document.getElementById("myContainer").className =
"myContainer pageload";
};
然后在 css:
.myContainer.pageload {
animation: none;
}
.myContainer.pageload * {
animation: none;
}
如果您不熟悉上面的“*”(n.b。space)意味着它也适用于该元素的所有后代。 space 表示所有后代,星号是指所有类型元素的通配符。
如果您在 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 class:
.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 制作的 fiddle 并在那里添加了以下代码:
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 posted already back in 2013 is to create an animation that initially is in a paused 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
。
有关如何设置具有多个动画的 animation
子属性,请参阅 https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations#setting_multiple_animation_property_values