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.

Ana
  • 35,599
  • 6
  • 80
  • 131

2 Answers2

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>
Ana
  • 35,599
  • 6
  • 80
  • 131
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.

Ilya Streltsyn
  • 13,076
  • 2
  • 37
  • 57
Noobit
  • 411
  • 3
  • 8
  • Actually, `@keyframe` animations *do* override `!important` and they *should* do that as per spec. Just try it out. – Ana Apr 16 '17 at 14:16
  • Sorry, but per spec the "Important author declarations" cascading origin _should override_ "Animation declarations" (https://www.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 (https://bugs.chromium.org/p/chromium/issues/detail?id=552085) – Ilya Streltsyn Aug 06 '20 at 13:40