Force a property of an element to a certain value even as it's being animated
Asked Answered
E

2

6

I have two types of elements, let's call them .a and .b.

They may have some CSS animations set on them. I don't have control over these keyframes, over whether they're set or not, over what they're animating.

They may be animating opacity. However, I want the opacity on my .a elements to stay a certain value, let's say 1, regardless of whether it is animated or not.

Consider the following code, where I have three cases:

  1. there's no animation being set on my elements
  2. there's an animation, but it's not animating opacity
  3. there's an animation and opacity is among the properties being animated

div {
  /* some dummy styles so we can see stuff */
  display: inline-block;
  width: 5em; height: 5em;
  background: purple;
}

[class*='ani'] { animation: a 1s ease-out infinite alternate }

.ani--one { animation-name: ani-one }

@keyframes ani-one { to { transform: scale(.5) } }

.ani--two { animation-name: ani-two }

@keyframes ani-two {
  to {
    opacity: 0;
    background: orange;
  }
}
<div class='a'></div>
<div class='b'></div>
<div class='a ani--one'></div>
<div class='b ani--one'></div>
<div class='a ani--two'></div>
<div class='b ani--two'></div>

In the first two cases (1 = no keyframe animation and 2 = keyframe animation, but it's not animating opacity) I don't need to do anything.

In the last case, however, I need to somehow force the opacity of the .a element to 1, cancel the animation effect on just that property.

I can't remove the keyframe animation from the .a element because I want the other properties (background in this case, whatever else may be in the general case) to keep on being animated.

I can't alter the animation because I want it to work as initially specified, animating the opacity for other elements (.b).

So the question is, how can I detect if, on an .a element, the opacity property is being animated and, if it is, how can I force its value to stay at 1, while the other properties set via the same keyframes are being animated?

I want to solve this problem using vanilla JS, no libraries.

Extricate answered 16/4, 2017 at 13:33 Comment(1)
while(true){elem.opacity=1;} but thats quite hacky...Neal
E
5

Now it just hit me that I could do it by adding an extra CSS keyframes animation:

@keyframes opacity-override { 0%, 100% { opacity: 1 } }

Now for all .a elements that have an animation set, I can add opacity-override to the animation name and it should take care of things!

Additionally, I can use it to force opacity: 1 against styles that might be set on hover or on adding other classes, which is super convenient!

const _A = document.querySelectorAll('.a');

_A.forEach(a => {
  let aname = getComputedStyle(a).animationName;
  
  if(aname !== 'none') a.style.animationName = `${aname}, opacity-override`;
  else a.style.animation = 'opacity-override 1s infinite';
});
div {
  /* some dummy styles so we can see stuff */
  display: inline-block;
  width: 5rem; height: 5rem;
  background: purple;
  color: white;
  font: 700 3em/5rem verdana;
  text-align: center;
}

div:hover { opacity: .7 }

[class*='ani'] { animation: a 1s ease-out infinite alternate }

.ani--one { animation-name: ani-one }

@keyframes ani-one { to { transform: scale(.5) } }

.ani--two { animation-name: ani-two }

@keyframes ani-two {
  to {
    opacity: 0;
    background: orange;
  }
}

@keyframes opacity-override { 0%, 100% { opacity: 1 } }
<div class='a'>A</div>
<div class='b'>B</div>
<div class='a ani--one'>A</div>
<div class='b ani--one'>B</div>
<div class='a ani--two'>A</div>
<div class='b ani--two'>B</div>
Extricate answered 16/4, 2017 at 14:46 Comment(0)
B
0

You can hack it by using !important

.solid-always { opacity:1 !important; }

and then just put at class in the one you don't want its opacity to change. Keyframe should not overwrite !important.

Britishism answered 16/4, 2017 at 13:56 Comment(2)
Actually, @keyframe animations do override !important and they should do that as per spec. Just try it out.Extricate
Sorry, but per spec the "Important author declarations" cascading origin should override "Animation declarations" (w3.org/TR/css-cascade-4/#cascading), so, theoretically, @Noobit's answer was mainly correct. The problem was that this spec was implemented correctly only in Firefox for years. But recently this bug has been fixed in Chromium (bugs.chromium.org/p/chromium/issues/detail?id=552085)Sherris

© 2022 - 2024 — McMap. All rights reserved.