Does a CSS3 animation run when parent element has visibility: hidden?
Yes, the animations continue to run even if the parent container has visibility:hidden
because the element is still there and it is only hidden. In the below snippet you can verify the contents of .output
div to see that it keeps running and marginLeft
keeps changing.
window.onload = function() { var animEl = document.querySelector('.animated'); var outputEl = document.querySelector('.output'); window.setTimeout(function() { outputEl.textContent = 'Margin left when visibility becomes hidden: ' + window.getComputedStyle(animEl).marginLeft; document.querySelector('.wrapper').style.visibility = 'hidden'; window.setTimeout(function() { outputEl.textContent = 'Margin left when visibility becomes visible: ' + window.getComputedStyle(animEl).marginLeft; document.querySelector('.wrapper').style.visibility = 'visible'; }, 1000); }, 1000);}
.wrapper{ white-space: nowrap;}.wrapper > div { display: inline-block; height: 100px; width: 100px; border: 1px solid;}.animated { animation: move 3s linear infinite;}@keyframes move { to { margin-left: 300px; }}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script><div class='wrapper'> <div class='animated'></div> <div class='sibling'></div></div><div class='output'></div>
Do CSS animations still happen when invisible?
While not sure if animations still take place on an element when it's hidden, you can use animation-iteration-count
to end the animation after a certain number of iterations.
- Use
class="is-hidden"
to hide the loader when not needed. - When
.is-hidden
is applied to the loader, change theanimation-iteration-count
of the spinner frominfinity
to, say,5
.
This will make the spinner do exactly 5 more spins and then end the animation. These 5 spins will take place while the loader is fading out. Obviously, you could increase the number of iterations/spins if 5 is not enough to cover the fade out duration.
LIVE DEMO (add and remove .is-hidden
to .loader
)
/* CSS */
@keyframes spin {
to { transform: rotateZ(360deg); }
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
.loader {
/* loader styles... */
animation: fadeIn 1s forwards;
}
.spinner {
/* spinner styles... */
animation: spin 0.5s linear infinite;
}
.loader.is-hidden {
animation: fadeOut 1s forwards;
}
.loader.is-hidden .spinner {
animation-iteration-count: 5;
}
CSS3-Animate elements if visible in viewport (Page Scroll)
Using IntersectionObserver API
The IntersectionObserver API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport.
Here's an example that triggers a classList toggle when an Element is in viewport:
const inViewport = (entries, observer) => {
entries.forEach(entry => {
entry.target.classList.toggle("is-inViewport", entry.isIntersecting);
});
};
const Obs = new IntersectionObserver(inViewport);
const obsOptions = {}; //See: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#Intersection_observer_options
// Attach observer to every [data-inviewport] element:
const ELs_inViewport = document.querySelectorAll('[data-inviewport]');
ELs_inViewport.forEach(EL => {
Obs.observe(EL, obsOptions);
});
[data-inviewport] { /* THIS DEMO ONLY */
width:100px; height:100px; background:#0bf; margin: 150vh 0;
}
/* inViewport */
[data-inviewport="scale-in"] {
transition: 2s;
transform: scale(0.1);
}
[data-inviewport="scale-in"].is-inViewport {
transform: scale(1);
}
[data-inviewport="fade-rotate"] {
transition: 2s;
opacity: 0;
}
[data-inviewport="fade-rotate"].is-inViewport {
transform: rotate(180deg);
opacity: 1;
}
Scroll down...
<div data-inviewport="scale-in"></div>
<div data-inviewport="fade-rotate"></div>
Animated element not visible outside of parent container in Firefox
Edited after comment:
You can take the animated element out of its parent (i.e. the element which has overflow: hidden
), on a higher level in the HTML code - as a sibling to the container. I did that in the snippet below, and also added a z-index
that places the animated element above the container:
.app {
overflow: hidden;
}
.container {
width: 260px;
max-height: 400px;
background: blue;
left: 10px;
right: 10px;
top: 10px;
position: fixed;
z-index: 500;
overflow-y: auto;
}
.wrapper {
height: 250px;
padding: 10px;
margin: 5px;
background: yellow;
top: 5px;
position: sticky;
}
.content {
height: 600px;
margin: 5px;
background: orange;
}
@keyframes fly-to-top {
10% {
top: 150px;
right: 80%;
width: 50px;
}
30% {
top: 120px;
right: 70%;
width: 45px;
}
60% {
top: 75px;
right: 40%;
width: 40px;
}
100% {
top: 10px;
right: 160px;
width: 35px;
}
}
.animated {
position: fixed;
right: unset;
top: 165px;
width: 50px;
background: red;
color: white;
animation: fly-to-top linear 2s forwards;
display: flex;
align-items: flex-start;
z-index: 501;
}
<div class="app">
<div class="container">
<div class="wrapper">
</div>
<div class="content">
Lorem ipsum
</div>
</div>
<div class="animated">
Text
</div>
</div>
Pure CSS animation visibility with delay
You are correct in thinking that display
is not animatable. It won't work, and you shouldn't bother including it in keyframe animations.
visibility
is technically animatable, but in a round about way. You need to hold the property for as long as needed, then snap to the new value. visibility
doesn't tween between keyframes, it just steps harshly.
.ele { width: 60px; height: 60px; background-color: #ff6699; animation: 1s fadeIn; animation-fill-mode: forwards; visibility: hidden;}
.ele:hover { background-color: #123;}
@keyframes fadeIn { 99% { visibility: hidden; } 100% { visibility: visible; }}
<div class="ele"></div>
Animate div when parent section is visible on scroll
It looks like you have the "visible" class being applied to a parent element of your target section.
Your css:
.visible .home__content-slide-right {
transform: translateX(0);
}
is written so that any parent of that element with a .visible class will apply this css rule. If you want to ensure that this fires only when visible is added to the same section, re-write the css like this:
section.visible .home__content-slide-right {
transform: translateX(0);
}
Or make sure that no parent element has the visible class applied if it is unnecessary.
CSS transition on child element where parent toggles display property
Since display:none
on a parent also takes out descendants from the DOM tree, one solution could be to drop transitions and use animations instead.
The animation will kick in when the child element is displayed.
Do use the necessary vendor prefixes.
.fade {
opacity: 0.2
}
#wrap.show .fade {
animation: reveal 10s forwards;
}
@keyframes reveal {
100% {
opacity: 1
}
}
/* set timeout to show how animation starts. */
setTimeout(function reveal() { var wrap = document.getElementById('wrap'); wrap.classList.add('show');}, 2000);
#wrap { background-color: orange; width: 200px; height: 200px; display: none;}
#wrap.show { display: block}
.fade { background-color: green; width: 100px; height: 100px; opacity: 0.2}
#wrap.show .fade { animation: reveal 10s forwards;}
@keyframes reveal { 100% { opacity: 1 }}
<div id="wrap"> <div class="fade"></div></div>
Related Topics
Use an Image Instead of a Bootstrap's Glyphicon
React Js: Apply Material-Ui CSSbaseline
How to Reverse-Engineer a Webkit Matrix3D Transform
How to Change The Scrollbar to Custom Design? (Avoid Using The Default Browser Look)
Ie7 Cause of "Text - Empty Text Node"
CSS: Overflow-Y: Scroll; Overflow-X: Visible
Default CSS Filter Values for Brightness and Contrast
Data-Uri Svg Background in CSS Not Working in Firefox
Why Border of <Th> and <Thead> Both Not Showing Here
Horizontally Center Absolute Positioned Element Below The Center of Another Element
Linear-Gradient Using CSS3 Pie in Ie9 Not Working, Ie8 Does
Adding New Theme to ASP.NET MVC 5 Dont Work
What Is The Definition of "The Baseline of Parent Box"
How to Make a Border-Layout Using CSS
:Has Vs: Matches - Selectors Level 4