I’m doing a hover navigation and it was working until I started adding animations. Whenever there’s any animation present that involves movement, it starts to flicker when it’s hovered over.
Here’s the code with the issue. When the animation I added for example is removed, it works as intended:
<style>
.hide {
display: none;
}
.hover {
position:absolute;
display:block;
width:200px;
height:200px;
background:grey;
}
.hover:hover + .hide {
display:inline-block;
background:#fff;
position:absolute;
}
@keyframes animation {
0% {font-size:14px;}
100% {font-size:15px;}
}
.animationexample {
animation:animation 1s infinite;
position:absolute;
top:0;
right:0;
}
</style>
<p class="animationexample">Animation</p>
<p class="hover">
Hover over this
<p class="hide">
Now hover over this</p></p>
2
Answers
I added
pointer-events: none
to.hide
and that fixed the flickering issue. The hover effect seems to work correctly now. Hope this resolves all issues.The CSS rule
pointer-events: none
applied to the.hide
element means that it will not capture mouse events, even if it is visible, allowing mouse events to "pass through" this element to reach elements below it.This is not a complete answer but I put it here in the hopes that someone who understands in depth how animation is implemented can complete the explanation.
The first thing to notice is that the two elements are NOT nested, although your HTML layout makes it look as if they are [the p tag is closed automatically when the next p is encountered]. Your CSS was correctly understanding that, using a + rather than a >.
So, if the .hide element is hovered and it is above (z direction) the .hover element it stops the .hover element seeing the hover.
To start with, when there is no hovering, .hide is display: none and can’t be seen and is taking no space.
When .hover is hovered .hide gets display inline and position absolute and as .hide follows .hover in the DOM it overlays .hover. Thus .hide ‘sees’ the hover and .hover stops seeing it. So .hide again goes to display none and its position absolute is removed. At that point .hover again sees the hover and the whole thing starts again.
Now, why don’t we see flickering even if there is no other (seemingly unrelated) animation in progress?
I believe (but don’t absolutely know) that this is related to timing – when repainting takes place.
If there is animation going on then this example points to the system doing a repaint immediately the .hide element has its position changed.
If there is no animation going on then it seems the system doesn’t attempt a repaint so soon, so the change of .hide’s position backdown is all accomplished within one frame repaint.
I am hoping someone who understands exactly how CSS animations are implemented can clarify this.
This reference https://developer.mozilla.org/en-US/docs/Web/Performance/Animation_performance_and_frame_rate starts to explain the sequences but does not cover the case where position and display values are changed (I guess because these are not ‘animatable’ in the normal sense).
Anyway, as @BrendanMorel has ponted out, not allowing .hide to see the hover by setting pointer-events to none gets round the problem.