CSS:避免图像首次悬停闪烁

73

我有一个锚点,当使用包含background-image的类class-btn悬停时,会更改其背景图像。

悬停时,它具有

a.class-btn:hover
{
    background-image('path/to/image-hovered.jpg');
}
当页面首次加载并且您第一次悬停在此按钮上时,它会闪烁(下载悬停图像需要约半秒钟)。如何在没有JavaScript的情况下避免闪烁(只允许使用简单的CSS和HTML)?
我尝试在Stack Overflow中搜索类似的问题,但没有找到。
只需添加:
• 我应该“预加载”悬停的图像吗?怎么做?
• 我应该使用 z-index 或 opacity 来进行调整吗?
它在所有浏览器中都会发生,因此解决方案应适用于所有浏览器。
14个回答

95

这是我多次使用的一种简单而有效的CSS图片预加载技术。您可以通过放置内容:url() url() url() ...等来加载多个图像。

body:after {
 display: none;
 content: url('path/to/image-hovered.jpg') url('path/to/another-image-hovered.jpg');
}

4
一开始这对我没有效果,但现在我意识到,不知何故,你必须将这些样式应用于body:after元素! - Aaron Franke
3
@Aaron Franke 这段代码对于任何元素的“after”伪元素都有效。 - Toniq
12
看起来这个方法不再起作用了。我的猜测是浏览器优化了页面加载,使得隐藏元素的背景不会被加载。尝试在最新的 Firefox、Safari 和 Chrome 版本中测试过,当声明为 display: none; 时,似乎没有一个浏览器会加载图片。如果使用 width: 0; height: 0 进行测试,结果也是一样的。如果元素可见,则可以正常工作,但会在页面上添加不需要的图像。有其他人遇到相同的问题吗? - Bence Szalai
1
@Grapestain 和我一样。当 display: none; 时不起作用。 - ladiesman1792
4
这个解决方案似乎在现代浏览器中有效。https://dev59.com/tnM_5IYBdhLWcg3wcSx_#14390213 - taylor michels
显示剩余8条评论

62

避免这个问题的最简单方法是利用图像精灵。想要了解更多,请看这篇CSS技巧文章

这样做不仅可以解决你看到的闪烁问题,还可以减少HTTP请求的数量。你的CSS将类似于:

a.class-btn { background: url('path/to/image.jpg') 0 0 no-repeat; }
a.class-btn:hover { background-position: 0 -40px; }

具体情况取决于你的图像。你也可以利用在线雪碧图生成器使该过程更容易。


4
如果我使用了 background-size: contain,有什么建议吗? - Bugs Bunny
如果你想使用 transition 来淡入淡出图片,这个方法可行吗?我认为不行。 - anthonygore
如果CSS已经准备好,我不会说这是修复闪烁问题最简单的解决方案。但它仍然是一个不错的方法。 - Jānis Elmeris

15

我使用的一个简单技巧是将原始背景图像复制一遍,并确保将悬停图像放在第一位。

.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;
    }
 }

没有性能损失,非常简单

或者如果你还没有使用SCSS:

.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;
 }

1
如果我正在开发浏览器,我会仅加载有效的背景(即最后一个)以最小化网络负载。我认为你可以预期这在任何浏览器中迟早都不会起作用。 - Srneczek
5
这在最近的 Chrome 更新前是有效的,现在却被浏览器优化了(这很好,但破坏了预加载)。 - MightyPork

9
如果您这样做:
#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');
}

这真的很有帮助!

看这里:

http://particle-in-a-box.com/blog-post/pre-load-hover-images-css-only

P.S. - 不是我的作品,但这是我找到的一个解决方案 :)


2
有点取巧,但它能用。如果你不想弄乱布局,我会添加position: absolute;或更好的display: none;而不是visibility: hidden;。 - Srneczek
如果您真的想要使用伪元素进行某些操作,那么这种方法是行不通的。 - anthonygore
display: none会阻止图片上传,只需添加position: absolute - Stiig

3

在 Firefox 48.0 (OS X) 中,@Kristian 在页面 body 后应用隐藏的 'content: url()' 的方法似乎不起作用。

然而,将 "display: none;" 改为类似以下样式:

body:after {
 position: absolute; overflow: hidden; left: -50000px;
 content: url(/path/to/picture-1.jpg) url(/path/to/picture-2.jpg);
}

...对我很有帮助。也许 Firefox 不会加载隐藏的图像,或者这与渲染有关。


好的发现!谢谢你的分享! - Kristian Svensson
不错!我建议使用 position:absolute; width:0; height:0; overflow:hidden; z-index:-1;。不过,left: -50000px 有点让我感到不安。 基本上,问题与此处描述的相同: https://dev59.com/tnM_5IYBdhLWcg3wcSx_#14390213 - bilbohhh

2
您可以预加载图像。
function preloadImages(srcs, imgs, callback) {
var img;
var remaining = srcs.length;
for (var i = 0; i < srcs.length; i++) {
    img = new Image();
    img.onload = function() {
        --remaining;
        if (remaining <= 0) {
            callback();
        }
    };
    img.src = srcs[i];
    imgs.push(img);
}
}
// then to call it, you would use this
var imageSrcs = ["src1", "src2", "src3", "src4"];
var images = [];
preloadImages(imageSrcs, images, myFunction);

2

这是一个非CSS的解决方案:如果悬停图像在一个目录中并且具有共同的命名约定,例如包含子字符串“-on.”,则可以选择文件名并将其作为一系列放入HTML中:

<img src='...' style='display: none' />

1

对我而言,这段代码起作用了:a.class-btn {transition-delay: 0.1s;}


1
你的答案可以通过提供更多支持信息来改进。请编辑并添加更多细节,例如引用或文档,以便他人可以确认你的答案是否正确。你可以在帮助中心中找到有关如何撰写良好答案的更多信息。 - Community

0

对我来说,“将原始背景图像加倍”这个技巧不起作用,所以我使用了另一个CSS技巧:

.next {
    background: url(../images/next.png) center center no-repeat;        
}
.next:hover {
    background: url(../images/next-hover.png) center center no-repeat;
}
.next:after {
    content: url(../images/next-hover.png);
    display: none;
}

0
我曾经遇到过同样的问题。 尝试了所有与CSS相关的方法,但都无法解决问题。 最终解决问题的方法是模拟有人悬停在元素上。 CSS是正常的。
CSS
#elemName{
 /* ... */
} 
#elemName:hover{
 /* change bg image */
}

JS

var element = document.getElementById('elemName');
var event = new MouseEvent('mouseover', {
  'view': window,
  'bubbles': true,
  'cancelable': true
});
element.dispatchEvent(event);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接