css: avoid image hover first time blinking
Solution 1
Here is a simple and effective css image preloading technique I have used several times. You can load several images by placing content: url() url() url()... etc.
body:after {
display: none;
content: url('path/to/image-hovered.jpg') url('path/to/another-image-hovered.jpg');
}
Solution 2
The easiest way to avoid this is to make use of image sprites. For a good overview, check out this CSS Tricks article.
That way, you not only solve the flicker problem you're seeing, but will also reduce the number of HTTP requests. Your CSS will look something like:
a.class-btn { background: url('path/to/image.jpg') 0 0 no-repeat; }
a.class-btn:hover { background-position: 0 -40px; }
The specifics will depend on your images. You can also make use of an online sprite generator to make the process easier.
Solution 3
A simple trick I use is to double up the original background image making sure to put the hovered image first
.next {
background: url(../images/next-hover.png) center center no-repeat;
background: url(../images/next.png) center center no-repeat;
&:hover{
background: url(../images/next-hover.png) center center no-repeat;
}
}
No performance hit and very simple
Or if you're not using SCSS yet:
.next {
background: url(../images/next-hover.png) center center no-repeat;
background: url(../images/next.png) center center no-repeat;
}
.next:hover{
background: url(../images/next-hover.png) center center no-repeat;
}
Solution 4
If you do this:
#the-button {
background-image: url('images/img.gif');
}
#the-button:before {
content: url('images/animated-img.gif');
width:0;
height:0;
visibility:hidden;
}
#the-button:hover {
background-image: url('images/animated-img.gif');
}
This will really help!
See here:
http://particle-in-a-box.com/blog-post/pre-load-hover-images-css-only
P.S - not my work but a solution I found :)
Solution 5
@Kristian's method of applying hidden 'content: url()' after the body didn't seem to work in Firefox 48.0 (OS X).
However, changing "display: none;" to something like:
body:after {
position: absolute; overflow: hidden; left: -50000px;
content: url(/path/to/picture-1.jpg) url(/path/to/picture-2.jpg);
}
... did the trick for me. Perhaps Firefox won't load hidden images, or maybe it's related to rendering(?).
Haradzieniec
Updated on July 05, 2022Comments
-
Haradzieniec almost 2 years
I have an anchor that changes its background image when hovered with a class
class-btn
that contains abackground-image
.When hovered, it has
a.class-btn:hover { background-image('path/to/image-hovered.jpg'); }
When the page loads the first time and you hover this button the first time, it blinks (it takes about half a second to download the hovered image). How to avoid that blinking without JavaScript (only simple css and html is allowed)?
I tried to search Stack Overflow for the similar question, but with no luck.
Just added:
- Should I "preload" the hovered image? How?
- Should I play with z-index or opacity?
It happens with all browsers and thus the solution should work for all browsers.
-
Haradzieniec over 11 yearsNice solution. Thanks for your answer.
-
Bugs Bunny almost 9 yearsWhat if I'm using
background-size: contain
? Any ideas? -
Civilian over 8 yearsLove it! Great answer, doesn't require making sprites, you can dump all of your extra images in there.
-
Caye over 8 yearsAwesome, simple and more intuitive, for me at least
-
Srneczek over 8 yearsKinda hacky, but it works. I would add position: absolute; or much better display: none; instead of visibility: hidden; if you don't want to mess your layout.
-
yorbro almost 8 yearsIt's a good solution but does not work so well when you increase the number of icons in your application, as the number of images you load at the initial load increases every time.
-
Srneczek almost 8 yearsif I was developing browser Id load only the valid background (so the last one) to minimize the network load. I think you can expect this is not gonna work in any browser sooner or later.
-
Srneczek almost 8 years@yorbro I guess you can combine sprites with this approach
-
anthonygore almost 8 yearsOP wants a different image for default state and hover so this wouldn't work
-
anthonygore almost 8 yearsWould this work if you wanted to use
transition
to fade between the images? I'm thinking not.. -
anthonygore almost 8 yearsDoesn't work if you actually want to use the pseudo element for something
-
Aaron Franke over 7 yearsThis wasn't working for me at first, but I realize now that for some reason the element you apply these styles to MUST be body:after!
-
MightyPork over 7 yearsthis worked OK until a recent chrome update, now it's optimized by the browser (which is great, but breaks the preload)
-
Kristian Svensson over 6 yearsGood catch! Thank you for sharing!
-
Toniq over 6 years@Aaron Franke this works for me on any element:after
-
fgonzalez over 6 yearsgreat solution!
-
sbnc.eu over 4 yearsLooks like this does not work any more. My guess is that browsers optimize page loads in a way that the background for hidden elements is not loaded. Tried in recent Firefox, Safari and Chrome versions, none seem to load the image when
display: none;
is in the declaration. Same results when I try withwidth: 0; height: 0
. If it is visible, it works, however adds unwanted image to the page. Anyone else facing the same? -
ladiesman1792 over 4 years@Grapestain same with me. Not working when there's display: none;
-
bilbohhh about 4 yearsNice! I would suggest to use
position:absolute; width:0; height:0; overflow:hidden; z-index:-1;
though. Somehowleft: -50000px
freaks me out) Basically, the problem is the same as described here: stackoverflow.com/a/14390213/4810382 -
taylor michels over 3 yearsthis solution seems to work in modern browsers stackoverflow.com/a/14390213/1108467
-
jinyong lee about 3 yearsI wouldn't call this the easiest solution to fix flickering if the CSS is already otherwise ready. But it is a good way nonetheless.
-
josue.0 over 2 yearsI used only width 1 and height 1 and it worked for me
-
Dominik over 2 yearsHere are also some solutions. Take a look and leave some feedback. stackoverflow.com/a/70673030/9251185
-
CodeNinja about 2 yearsIf you have developer tools open, make sure the "disable cache" checkbox is not selected. Banged my head against this for days before I finally realized. Using this solution worked for me!