I set up a keyframe animation in CSS. Attached it to a DOM element and set it to pause. With javascript (jQuery), I am changing the animation delay from 0s
to 100s
achieving a nice animation while scrolling.
This works well on all of the browsers, but not on Safari (Version 11.1.1 (13605.2.8)).
$(document).ready(function() {
fluider([
{
selector: '.manualAnim',
start: 100,
end: 500
},
{
selector: '.manualAnim2',
start: 500,
end: 1000
},
{
selector: '.manualAnim3',
start: 0,
end: 1500
}
])
})
function fluider(o) {
for(var i = 0; i < o.length; i++) {
$(o[i].selector).css('animation-play-state','paused');
$(o[i].selector).css('animation-duration','100s');
}
$(window).scroll(function() {
var h = $(window).scrollTop();
for(var i = 0; i < o.length; i++) {
$(o[i].selector).css('animation-delay',-clamp(0,100,((h-o[i].start)/o[i].end * 100)) + 's');
}
});
}
function clamp(from, to, val) {
if(val >= from) {
if(val <= to) {
return val;
}
else {
return to;
}
}
else {
return from;
}
}
body {
height: 1000vh;
}
.manualAnim {
position: fixed;
display: block;
width: 100px;
height: 100px;
background-color: red;
animation: 100s anim paused both;
animation-delay: 0s;
}
.manualAnim2 {
position: fixed;
display: block;
left: 120px;
width: 100px;
height: 100px;
background-color: red;
animation: 100s anim paused both;
animation-delay: 0s;
}
.manualAnim3 {
position: fixed;
display: block;
left: 240px;
width: 100px;
height: 100px;
background-color: red;
animation: 100s anim paused both;
animation-delay: 0s;
}
@keyframes anim{
0% {
background-color: red;
transform: scale(1);
}
30% {
background-color: green;
transform: scale(1.5);
}
60% {
background-color: blue;
transform: scale(0.5);
}
100% {
background-color: yellow;
transform: scale(1);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="manualAnim"></div>
<div class="manualAnim2"></div>
<div class="manualAnim3"></div>
I Googled a few hours days for now, but I have no clue what could be the problem.
Any idea?
After a lot of experimentation, here's a version with workarounds that gives smooth, expected behavior in both Safari 11.1.2 and Chrome 68 (and hopefully other browsers as well).
It looks like the underlying issue is that elements don't get redrawn when animation properties are changed for a paused animation, as the question states. This solution works around that by re-adding the necessary animation-related CSS (with the correct delay) each frame. This would normally cause flickering (since Safari tries to revert to the unanimated styling when the animation is removed), so this solution manually applies the current animation style each time it modifies the animation.
$(document).ready(function() {
fluider([{
selector: '.manualAnim',
start: 100,
end: 500
},
{
selector: '.manualAnim2',
start: 500,
end: 1000
},
{
selector: '.manualAnim3',
start: 0,
end: 1500
}
])
})
function getAnimatedProperties(animName) {
// Get an array of all property names that
// are modified by the animation ${animName}
let properties = {};
let sheets = document.styleSheets;
let propertyRegex = /([a-z\-]+):/ig;
for (let sheet of sheets) {
let rules = sheet.rules || sheet.cssRules;
for (let r of rules) {
if (r.name === animName) {
let rText = r.cssText;
let match = propertyRegex.exec(rText);
while (match) {
properties[match[1]] = true;
match = propertyRegex.exec(rText);
}
}
}
}
return Object.keys(properties);
}
function fluider(o) {
const animationName = "anim";
const preservedProperties = getAnimatedProperties(animationName);
$(window).scroll(function() {
var h = $(window).scrollTop();
for (var i = 0; i < o.length; i++) {
let el = document.querySelector(o[i].selector);
let pct = 100 * (parseInt(h) - o[i].start) / o[i].end;
let delay = -Math.max(Math.min(pct, 100), 0) + 's';
let s = window.getComputedStyle(el);
// without setting these properties and overwriting .style,
// the animation will flicker
let preservedStyles = preservedProperties.map(p => `${p}: ${s[p]};`).join("");
el.style = `${preservedStyles} animation-delay: ${delay}; animation-duration: 100s; animation-play-state: paused;`;
// without scheduling this *using setTimeout*,
// the animation will not rerender
window.setTimeout(() => {
el.style.animationName = animationName;
}, 0);
}
});
}
body {
height: 1000vh;
}
.manualAnim {
position: fixed;
display: block;
width: 100px;
height: 100px;
background-color: red;
}
.manualAnim2 {
position: fixed;
display: block;
left: 120px;
width: 100px;
height: 100px;
background-color: red;
}
.manualAnim3 {
position: fixed;
display: block;
left: 240px;
width: 100px;
height: 100px;
background-color: red;
}
@keyframes anim {
0% {
background-color: red;
transform: scale(1);
}
30% {
background-color: green;
transform: scale(1.5);
}
60% {
background-color: blue;
transform: scale(0.5);
}
100% {
background-color: yellow;
transform: scale(1);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="manualAnim"></div>
<div class="manualAnim2"></div>
<div class="manualAnim3"></div>
You need to add the animation webkit to your code and css for Safari
-webkit-animation
-webkit-animation-delay
-webkit-animation-duration
-webkit-animation-play-state
@-webkit-keyframes
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With