I'm learning how to use transition:
in CSS. But for some reason, my images keep flickering instead of giving me smooth animation. I'm developing in Windows 10 with the latest version of Chrome. Here is my code, which is very simple:
function toggleClass() {
var box = document.getElementById('box');
box.className = box.className.match(/active/) ? '' : 'active';
}
#box {
width:200px;
height:200px;
background-color:#999;
opacity:0;
transform:translate(0,30px);
transition:background-color 0.6s ease, opacity 0.6s ease, transform 0.6s ease;
}
#box.active {
opacity:1;
transform:translate(0,0);
}
img {
width:100%;
display:block;
filter: grayscale(100%) brightness(120%);
mix-blend-mode:multiply;
}
#box:hover {
background-color:red;
}
<button type="button" onClick="toggleClass()">Toggle Image</button>
<div id="box" class="">
<img src="https://i.sstatic.net/GwYD1.jpg" alt="">
</div>
What I want to do is when I press the Toggle Image
button, I want a grey scale to fade in. Then when I mouse over the image, I want it to turn red since it is using the mix-blend-mode
and the #box
should have a red background color.
The problem is that every time I add the active
to #box.active
, the image doesn't "gradually fade in". Instead, a solid grey box scrolls up and fades in. Once the grey box completes animation, the image then "snaps" into view as if animation duration is 0 seconds. I don't want the image to "snap" into view...I want the image to fade in smoothly just like the grey box.
I want both the grey box and the grey picture to animate in smoothly together.
How do I make this happen?
EDIT
I noticed that if I add the line #box.active {background-color:transparent;}
, then the image fades in. But the image is too bright. Applying a #box-active {background-color:#999;}
had the same problem as the original question.
EDIT 2
I noticed that if I add these lines, it almost does what I need
#box { background-color:rgba(155,155,155,1); }
#box.active { background-color:rgba(155,155,155,0.9);}
For some unusual reason using rgba
along with an alpha of 1 before the active class and an alpha of 0.9, seems to help a little. Now I see the browser "trying" to animate things in smoothly, it's just very choppy now.
Try adding transform: translateZ(0)
on the child element img
.
function toggleClass() {
var box = document.getElementById('box');
box.className = box.className.match(/active/) ? '' : 'active';
}
#box {
width:200px;
height:200px;
background-color:#999;
opacity:0;
transform:translate(0,30px);
transition:background-color 0.6s ease, opacity 0.6s ease, transform 0.6s ease;
}
#box.active {
opacity:1;
transform:translate(0,0);
}
img {
width:100%;
display:block;
filter: grayscale(100%) brightness(120%);
mix-blend-mode:multiply;
transform: translateZ(0); // this rules forces a new layer
}
#box:hover {
background-color:red;
}
<button type="button" onClick="toggleClass()">Toggle Image</button>
<div id="box" class="">
<img src="https://doggyholder.netlify.app/300/400" alt="">
</div>
Theoretically your code is correct, this has been a bug in chrome for quite some time.
The translateZ(0)
workaround forces chrome to draw seperate layers for the GPU to toy with. You can find more about layers here.
Also note that if you're going for visual consistency, you might have to go with some additional vendor prefixed styling.
As of now, Chrome, Firefox and Edge don't agree on what a blend should look like