Does a CSS3 Animation Run When Parent Element Has Visibility: Hidden

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 the animation-iteration-count of the spinner from infinity 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



Leave a reply



Submit