Every once in a while, Chrome will render perfectly valid HTML/CSS incorrectly or not at all. Digging in through the DOM inspector is often enough to get it to realize the
I ran into this challenge today in OSX El Capitan with Chrome v51. The page in question worked fine in Safari. I tried nearly every suggestion on this page - none worked right - all had side-effects... I ended up implementing the code below - super simple - no side-effects (still works as before in Safari).
Solution: Toggle a class on the problematic element as needed. Each toggle will force a redraw. (I used jQuery for convenience, but vanilla JavaScript should be no problem...)
jQuery Class Toggle
$('.slide.force').toggleClass('force-redraw');
CSS Class
.force-redraw::before { content: "" }
And that's it...
NOTE: You have to run the snippet below "Full Page" in order to see the effect.
$(window).resize(function() {
$('.slide.force').toggleClass('force-redraw');
});
.force-redraw::before {
content: "";
}
html,
body {
height: 100%;
width: 100%;
overflow: hidden;
}
.slide-container {
width: 100%;
height: 100%;
overflow-x: scroll;
overflow-y: hidden;
white-space: nowrap;
padding-left: 10%;
padding-right: 5%;
}
.slide {
position: relative;
display: inline-block;
height: 30%;
border: 1px solid green;
}
.slide-sizer {
height: 160%;
pointer-events: none;
//border: 1px solid red;
}
.slide-contents {
position: absolute;
top: 10%;
left: 10%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>
This sample code is a simple style-based solution to maintain aspect ratio of an element based on a dynamic height. As you increase and decrease the window height, the elements should follow and the width should follow in turn to maintain the aspect ratio. You will notice that in Chrome on OSX (at least), the "Not Forced" element does not maintain a proper ratio.
</p>
<div class="slide-container">
<div class="slide">
<img class="slide-sizer" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">
<div class="slide-contents">
Not Forced
</div>
</div>
<div class="slide force">
<img class="slide-sizer" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">
<div class="slide-contents">
Forced
</div>
</div>
</div>
If you want to preserve the styles declared into your stylesheets, better to use something like:
jQuery.fn.redraw = function() {
this.css('display', 'none');
var temp = this[0].offsetHeight;
this.css('display', '');
temp = this[0].offsetHeight;
};
$('.layer-to-repaint').redraw();
NB: with latest webkit/blink, storing the value of offsetHeight
is mandatory in order to trigger the repaint, otherwise the VM (for optimizations purposes) will probably skip that instruction.
Update: added the second offsetHeight
reading, it is necessary to prevent browser from queueing/caching a following CSS property/class change with the restore of the display
value (this way a CSS transition that can follow should be rendered)
We recently encountered this and discovered that promoting the affected element to a composite layer with translateZ fixed the issue without needing extra javascript.
.willnotrender {
transform: translateZ(0);
}
As these painting issues show up mostly in Webkit/Blink, and this fix mostly targets Webkit/Blink, it's preferable in some cases. Especially since many JavaScript solutions cause a reflow and repaint, not just a repaint.
CSS only. This works for situations where a child element is removed or added. In these situations, borders and rounded corners can leave artifacts.
el:after { content: " "; }
el:before { content: " "; }
Most answers require the use of an asynchroneous timeout, which causes an annoying blink.
But I came up with this one, which works smoothly because it is synchroneous:
var p = el.parentNode,
s = el.nextSibling;
p.removeChild(el);
p.insertBefore(el, s);
I had a react component list which when scrolled, then opened another page, then when returning back the list was not rendered on Safari iOS until page was scrolled. So this is the fix.
componentDidMount() {
setTimeout(() => {
window.scrollBy(0, 0);
}, 300);
}