I have an element which I call back
covered by another element which I call front
.
Back
is set in CSS to change color on hover. Front
is set, when hovered, to disappear after a 1s
delay and the mouse pointer which was on Front
element now is on back element.
Front
disappears by setting height: 0
in JavaScript. After Front
disappears and the mouse ointer is hovering on Back
the browser doesn't rerender the hover effect on Back
which results in its color not being changed as it should.
When I try the same example by naturally removing Front
from the DOM it works fine. My app, though, requires I do this by setting height: 0
.
You can try it for yourselves in the following examples. You will see a red box and a blue box. Red is Front
and blue is Back
. When you move the mouse pointer to the red box, the red box's color changes to green
. When you move your mouse onto the blue box, after one second, it will disappear.
The point of the example is to show that after the blue box disappears, the mouse pointer now hovers on the red box and it should therefore bee green
.
In this example, the blue box is removed from the DOM pletely and it works as well as expected.
In this example, though, the blue box is to be removed by setting height: 0
. After disappearing, the red element won't bee green
until after I move the mouse.
Is there any way to force browser to rerender?
The problem persists in Google Chrome and Microsoft Edge. Firefox works good.
I have an element which I call back
covered by another element which I call front
.
Back
is set in CSS to change color on hover. Front
is set, when hovered, to disappear after a 1s
delay and the mouse pointer which was on Front
element now is on back element.
Front
disappears by setting height: 0
in JavaScript. After Front
disappears and the mouse ointer is hovering on Back
the browser doesn't rerender the hover effect on Back
which results in its color not being changed as it should.
When I try the same example by naturally removing Front
from the DOM it works fine. My app, though, requires I do this by setting height: 0
.
You can try it for yourselves in the following examples. You will see a red box and a blue box. Red is Front
and blue is Back
. When you move the mouse pointer to the red box, the red box's color changes to green
. When you move your mouse onto the blue box, after one second, it will disappear.
The point of the example is to show that after the blue box disappears, the mouse pointer now hovers on the red box and it should therefore bee green
.
In this example, the blue box is removed from the DOM pletely and it works as well as expected.
In this example, though, the blue box is to be removed by setting height: 0
. After disappearing, the red element won't bee green
until after I move the mouse.
Is there any way to force browser to rerender?
The problem persists in Google Chrome and Microsoft Edge. Firefox works good.
Share Improve this question edited Jul 17, 2016 at 13:59 Angel Politis 11.3k15 gold badges50 silver badges67 bronze badges asked Jul 10, 2016 at 10:19 MisazMisaz 3,9953 gold badges28 silver badges45 bronze badges5 Answers
Reset to default 6Instead of trying to force the browser to rerender, you can just add a class to foo
that will make it green when bar
disappears and then, it returns to normal on mouseleave
.
CSS:
#foo.hover, /* <- I just added this */
#foo:hover {
background-color: green;
}
JavaScript:
var
foo = document.getElementById("foo"),
bar = document.getElementById("bar");
/* Set the 'mouseenter' event for bar to set the height to 0 and & the 'hover' class. */
bar.onmouseenter = function() {
setTimeout(function() {
bar.style.height = 0;
foo.classList.add("hover");
}, 1000);
}
/* Set the 'mouseleave' event for bar to remove the 'hover' class. */
bar.onmouseleave = function() {
foo.classList.remove("hover");
}
Check out the following snippet for a visual representation.
Snippet:
/* --- JavaScript --- */
var
foo = document.getElementById("foo"),
bar = document.getElementById("bar");
/* Set the 'mouseenter' event for bar. */
bar.onmouseenter = function() {
setTimeout(function() {
/* Set the height to 0. */
bar.style.height = 0;
/* Add the 'hover' class. */
foo.classList.add("hover");
}, 1000);
}
/* Set the 'mouseleave' event for bar. */
bar.onmouseleave = function() {
/* Remove the 'hover' class. */
foo.classList.remove("hover");
}
/* --- CSS --- */
#foo {
width: 200px;
height: 200px;
background-color: red;
position: absolute;
top: 10px;
left: 15px;
}
#foo.hover,
#foo:hover {
background-color: green;
}
#bar {
width: 200px;
height: 200px;
background-color: blue;
position: absolute;
top: 100px;
left: 100px;
}
<!-- HTML -->
<div id = "foo"></div>
<div id = "bar"></div>
This really seems like a browser issue, there are some ways on how to force webkit to redraw. But I really wouldn't remend that for you. You can simply use bar.style.display = 'none';
instead of setting the height to zero. Has the same effect and everything works as expected. See this fiddle: https://jsfiddle/zkhorh38/4/.
It's possible to do it in CSS just by playing with the transition
property.
#foo {
width: 200px;
height: 200px;
background-color:red;
position: absolute;
top:10px;
left:15px;
z-index: 10;
}
#foo:hover {
background-color: green;
}
#bar {
width: 200px;
height: 200px;
background-color:blue;
position: absolute;
top:100px;
left:100px;
z-index: 20;
transition: all 1000000s;
}
#bar:hover {
transition: all 0.01s;
opacity: 0;
z-index: 1;
}
<div id="foo"></div>
<div id="bar"></div>
If back is pletely covered by front, you could set front.style['pointer-events'] = 'none'
in the onmouseenter
callback first to let the mouse activate back's :hover
rule before front disappears.
See modified working snippet.
This might be a browser issue, but there are some ways on how to force webkit to redraw. But I wouldn't remend that for you. You can simply use bar.style.display = 'none';
instead of setting the height to zero.
Another solution to force a redraw/repaint that works just fine:
sel.style.display='none';
sel.offsetHeight; // no need to store this anywhere, the reference is enough
sel.style.display='';
**
To avoid flickering you may try 'inline-block'
, 'table'
or 'run-in'
instead of 'none'
, but this may have side-effects. Also, a timeout of 0 triggers a reflow just like querying offsetHeight does: sel.style.display = 'run-in'; setTimeout(function () { sel.style.display = 'block'; }, 0);
Try this it really works !