I have a CSS keyframe animation that uses a CSS variable as one of the animation properties. This variable is defined in jQuery. The entire animation seems to work fine in Chrome and Firefox. However, in Safari and on mobile browsers, only the portions of the animation not using the variable work correctly.
I've spent a lot of time trying to debug the issue...
From all this, it seems to be a problem with the combination of the variable being defined in jQuery (also didn't work for straight JavaScript) and being used in the animation.
Any thoughts on what's going on?
function refHeight() {
if ($('#main-content').length != 0) {
$(':root').css('--varheight', Math.round($('#main-content').outerHeight()) + 'px');
}
}
window.addEventListener('load', refHeight);
window.addEventListener('resize', refHeight);
:root {
--hardvarheight: 75vh;
}
#main-content {
width: 100%;
height: 75vh;
}
.item {
width: 75px;
height: 50px;
font-size: 80%;
}
.one {
animation: animOne 3s linear infinite alternate;
position: absolute;
background-color: pink;
}
.two {
position: absolute;
top: calc(var(--varheight) / 100 * 50);
left: 50vw;
background-color: lightblue;
}
.three {
animation: animThree 3s linear infinite alternate;
position: absolute;
background-color: lightgreen;
}
@keyframes animOne {
0% {top: calc(var(--varheight) / 100 * 10); left: 40vw;}
50% {top: calc(var(--varheight) / 100 * 20); left: 50vw;}
100% {top: calc(var(--varheight) / 100 * 10);left: 60vw;}
}
@keyframes animThree {
0% {top: calc(var(--hardvarheight) / 100 * 80); left: 40vw;}
50% {top: calc(var(--hardvarheight) / 100 * 90); left: 50vw;}
100% {top: calc(var(--hardvarheight) / 100 * 80); left: 60vw;}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="main-content">
<div class="item one">Animated Using jQuery Variable</div>
<div class="item two">Positioned Using jQuery Variable</div>
<div class="item three">Animated Using CSS Variable</div>
</div>
I think I've finally figured it out. Safari doesn't seem to like to recalculate any CSS calc() values after they've been initially defined.
Instead of having the animation property attached to the element in CSS, I created a separate class and added addClass() to the element after the variable was calculated. Seems to work.
The only bug I'm having to sort out now is how to get it to recalculate the calc() value in the keyframe animation once the browser is resized.
function refHeight() {
if ($('#main-content').length != 0) {
$(':root').css('--varheight', Math.round($('#main-content').outerHeight()) + 'px');
$('.one').addClass('animated');
}
}
window.addEventListener('load', refHeight);
window.addEventListener('resize', refHeight);
:root {
--hardvarheight: 75vh;
}
#main-content {
width: 100%;
height: 75vh;
}
.item {
width: 75px;
height: 50px;
font-size: 80%;
}
.one {
position: absolute;
background-color: pink;
}
.two {
position: absolute;
top: calc(var(--varheight) / 100 * 50);
left: 50vw;
background-color: lightblue;
}
.three {
animation: animThree 3s linear infinite alternate;
position: absolute;
background-color: lightgreen;
}
.animated {
animation: animOne 3s linear infinite alternate
}
@keyframes animOne {
0% {top: calc(var(--varheight) / 100 * 10); left: 40vw;}
50% {top: calc(var(--varheight) / 100 * 20); left: 50vw;}
100% {top: calc(var(--varheight) / 100 * 10);left: 60vw;}
}
@keyframes animThree {
0% {top: calc(var(--hardvarheight) / 100 * 80); left: 40vw;}
50% {top: calc(var(--hardvarheight) / 100 * 90); left: 50vw;}
100% {top: calc(var(--hardvarheight) / 100 * 80); left: 60vw;}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="main-content">
<div class="item one">Animated Using jQuery Variable</div>
<div class="item two">Positioned Using jQuery Variable</div>
<div class="item three">Animated Using CSS Variable</div>
</div>