使用 CSS 创建图像悬停效果非常容易。给元素设置一个背景图片,然后在它的 :hover
状态下,更改 background-image
。最佳实践是将两个图像合并成一个图像,并更改 background-position
而不是使用两个单独的图像,这就是 CSS 精灵 的概念。但如果想要淡入一个图像到另一个图像,而不是突然切换,该怎么做呢?
解决方案是在原始元素的顶部创建一个额外的元素,该元素的 opacity
为 0,并且 background-position
已经移到了指定位置。然后在 :hover
状态下,将不透明度淡入。以下三种方法使用一个小箭头图形来实现这一点。
(箭头来自 Ask Differently)
方法一:合理的渐进性
在原始元素内部添加一个 span 元素。该 span 元素本质上是悬停状态。我知道,额外的标记很糟糕,但我们需要一个额外的元素来使用,并且伪元素在大多数浏览器中无法进行过渡。
<a href="#" class="arrow">Arrow<span></span></a>
箭头本身将使用基本的 CSS 图像替换,并且背景定位在默认位置。
.arrow {
display: inline-block;
position: relative;
text-indent: -9999px;
width: 36px;
height: 36px;
background: url(sprites.png) no-repeat;
}
那里使用的相对定位是针对 span 元素的,我们将 span 元素绝对定位,使其大小完全相同。它的背景位置将被移到悬停状态的位置,其不透明度设置为 0,并且 CSS3 过渡被设置好。
.arrow span {
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
background: url(sprites.png) no-repeat;
background-position: -50px 0;
opacity: 0;
-webkit-transition: opacity 0.5s;
-moz-transition: opacity 0.5s;
-o-transition: opacity 0.5s;
}
然后在悬停状态下,不透明度上升
.arrow:hover span {
opacity: 1;
}
方法二:更具渐进性
我们之所以使用上面的 span 元素,是因为(在撰写本文时)只有 Firefox 4 对伪元素进行过渡。可以合理地认为,将来 WebKit 和其他浏览器也将支持此功能。因此,我们可以像这样清理标记
<a href="#" class="arrow">Arrow</a>
然后,其余 CSS 代码完全相同,只是我们使用 :after 而不是 span 元素。
.arrow:after {
content: "";
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
background: url(sprites.png) no-repeat;
background-position: -50px 0;
opacity: 0;
-webkit-transition: opacity 0.5s;
-moz-transition: opacity 0.5s;
-o-transition: opacity 0.5s;
}
.arrow:hover:after {
opacity: 1;
}
方法三:向后兼容性
某些浏览器根本不支持伪元素或过渡。如果要使此方法尽可能跨浏览器兼容,则必须使用额外的 HTML,并依赖 JavaScript (jQuery…) 来帮助实现。我们又回到了 span 元素。
<a href="#" class="arrow">Arrow<span></span></a>
CSS 代码基本相同,但由于我们不处理任何悬停或淡入操作,因此已简化。
.arrow {
display: inline-block;
position: relative;
text-indent: -9999px;
width: 36px;
height: 36px;
background: url(sprites.png) no-repeat;
}
.arrow span {
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
background: url(sprites.png) no-repeat;
background-position: -50px 0;
}
jQuery 将处理淡入操作。首先,我们将隐藏 span 元素,然后使用 hover 函数附加 mouseenter 和 mouseleave 事件,以实现淡入和淡出。
$(function() {
$(".arrow")
.find("span")
.hide()
.end()
.hover(function() {
$(this).find("span").stop(true, true).fadeIn();
}, function() {
$(this).find("span").stop(true, true).fadeOut();
});
});
所有三个示例
很棒的内容,一如既往。这正是我昨天下午花了大量时间却未能解决的问题。
很棒的教程... 小提醒,如果在 Chrome 中点击“按钮”,jQuery 版本会失效。
一个小问题,关于方法三(这将是我本能的解决问题的方法),我个人会选择使用未污染的 HTML,并在脚本中创建 span 元素...
完全符合我的想法 :)
本能似乎是关键词。
我同意;)
@SHOUTYMAN +1
喜欢
这个 :)
尽量避免不必要的标记,尤其是在使用启用 JavaScript 的情况下。
可能是我,但这仍然是 HTML。
因此,您将拥有与在 HTML 文件本身中包含它相同的 HTML 量。另外,您还获得了一段额外的 JavaScript 代码。
我支持清理代码。但您的解决方案对我来说仍然是 document.write('bla')。
使用伪元素将是添加视觉效果的正确方法,但正如 Chris 指出的那样,这些元素目前无法进行动画处理。
@Rene
我不确定两个额外的字符(“append” 与 “find”)是否值得被称为“额外的 JavaScript 代码”:)... 而且,即使最终的文档模型不是,已提供的 HTML 也更小巧更干净。
进行此更改意味着任何不运行 JavaScript 的用户都不会收到被污染的文档。虽然这在空 span 元素的情况下不是什么大问题,但作为一项原则,我会始终保持无脚本内容尽可能干净。
另外,更重要的是,除了这几个字符或空元素,通过在脚本中生成元素,您可以消除两个独立文件的内容之间的依赖关系。行为现在与驱动它所需的内容并置在一起。这对可维护性来说是一项重大优势,这件好事。
(实际上,我通常倾向于在脚本中构建特定于行为的 CSS 代码,尽管这将是一个稍微复杂一些的讨论,我现在不想谈论。)
很棒的逐步说明,Chris。这正是我们在新的 United Pixelworkers 网站上处理导航的方式。我们选择了方法 1。
嘿,Chris,很棒的教程,这个教程将会派上用场。
不幸的是,您的演示存在一个小错误。jQuery 按钮如果我缓慢地悬停和移开,它会起作用,但如果我快速地悬停和移开,它就不起作用了。
我在 Firefox 3.6.4 中遇到了这个问题。
谢谢,
Colin
啊,是的,我看到了。为了解决这个问题,您可以不使用 .fadeIn 和 .fadeOut,而是使用以下代码
.animate({ opacity: 1 }); 和 .animate({ opacity: 0 }); - 这样您就可以对特定值进行动画处理。淡入和淡出函数试图通过对先前设置的值进行动画处理来提供帮助,但如果它们没有完成,则不会完全为 1 或 0。
如果您对 .animate() 有什么不满,也可以使用 .fadeTo('1') 和 .fadeTo('0') jQuery 函数...
只是提个建议 :D
情人节快乐!
很棒的技术!谢谢。我想我会在我的下一个项目中考虑使用 jQuery 版本。
很棒的教程,最近使用过您的预制精灵之一,并将其变成了一个可重复使用的模板,这是一个很棒的补充 :-))
最喜欢第二种方法,然后是第一种。
但是...
我认为第一种方法更传统,更容易理解。
而第二种方法似乎更复杂。
好吧,jQuery 不适合简单的过渡 :-(
我很好奇,我在 其他地方 看到,CSS3 的 ease[-in] 过渡也可以用于在精灵之间进行状态过渡(例如,悬停按钮)。虽然在我链接的主题中,它有一种视觉错觉的感觉,因为它是过渡的,但我在按钮、图标、链接等等上看到了类似的效果,这些效果更微妙。如果我没记错的话,它们也使用过渡和延迟来单独实现这一点。
难道这,可能还有 jQuery(或您选择的任何库)回退,比不透明度或“:after”伪属性方法更好(我知道第三个示例中提供了 jQuery 方法)?我只是想知道有什么优势 - 如果有的话。我必须回去仔细阅读这篇文章,我想。
感谢您提供很棒的教程。写得很好,易于理解,将来一定会用在项目中!
当伪元素解决方案得到更广泛的浏览器支持时,它会非常有趣,尤其是因为它允许您将不透明度属性应用于生成的元素,而不会影响主元素的子元素。对于包含网页文本等的导航按钮来说很好。我有一个关于我意思的例子 这里.
可惜只有 FF4 支持它。来吧,WebKit 贡献者,快行动起来吧!
我喜欢第一个。
哈哈,第一个很聪明,简单,但我甚至没有想到!
谢谢,我一直在寻找相同的脚本。
谢谢
感谢您提供很棒的教程!将来肯定会用到它!
很棒的教程,我会试试 span 的方法!
Merci beaucoup, je vais essayer la technique avec le span.
我很久以前就想弄清楚这个,但我失败了。看到有人能如此轻松地解决这个问题真是太好了。并提供了如此防弹(好吧,几乎)的解决方案。
随着 CSS 3 规范的最终确定(包括动画伪元素),第二种方法将成为我的首选技术。
Chris,我认为你应该在 CSS Tricks 的某个地方实现这个技术,比如评论中的回复按钮。它通常很突然,但使用这种技术,您可以使其过渡到更暗的版本(同时保持精灵的速度)。
只是一个想法 =)。顺便说一下,您可以使用 jQuery 完全实现第三种方法,通过 jQuery 创建
span
标签。哦,是的,非常棒!我喜欢它。我一直期待着一种可以放在网站上的新酷技巧,这太棒了。干净又性感!
谢谢 Chris。你管理着这台机器!: )
很有趣!我之前为 http://www.nieuwbestand.nl 做过类似的事情,使用 jQuery。解决方案非常相似。
我在所有主要浏览器中看到所有 3 种技术的结果不一致。希望这在将来能成为普遍现象,但在那之前,我将坚持使用经过验证的方法。
哇,真的太棒的教程了!我还没有太多地使用 CSS3 中的精灵,所以我不确定你所有的代码都来自哪里。但是你以一种非常优雅的方式呈现了所有内容,你所有的说明都很容易理解和遵循。
Chris,很棒的教程!感谢您想出这个办法。
第三个示例在 Chrome 和 FireFox 中不起作用?
有趣的想法,好文章。
这就是我用 mootools 做 js 的方法(只是为了在这里添加一些好的 js :P)。
还没有测试过,只是快速写在一起。
(function(){
var arrow = document.getElement(‘.arrow3’),
span = arrow.getElement(‘span’).fade(‘hide’);
arrow.addEvents({
‘mouseenter’: function(){
span.fade(‘in’);
},
‘mouseleve’: function(){
span.fade(‘out’);
}
});
})();
在本教程的 nettuts 示例(appstore 按钮)中使用过类似的东西。
http://nettuts.s3.amazonaws.com/899_leaflet/Source/index.html
我喜欢使用第三个解决方案 :)
但在需要多个按钮时使用它会遇到一些问题。
当将两个 <a> 标签像这样彼此放在上面时。
那么,在两个图像之间会有一个空格(请看这里:http://earnur.cba.pl/projects/blog/test.html)。
但如果我在一行中编写它。
它会正确显示图像(http://earnur.cba.pl/projects/blog/test2.html)。
我总是以结构化方式创建我的 HTML 文件,而不是在一行中编写,以保持清晰度,但在这里我不知道如何删除那个空格…:/
为什么你要用 “text-indent: -9999px;” ?
为了隐藏文本,因为它被图像替换,如果没有 text-indent, “Arrow” 将显示在背景箭头图像之上。负值用于将文本推到左边,因为如果只是 text-indent: 9999px,它会移动到右边,从而创建水平滚动条。
在 mac 上的 firefox 中似乎不起作用。
太棒了,正是我要找的文章。
非常感谢,非常方便。CSS Tricks 又来了一次!
看起来,如果你在 Safari 和 Firefox 中多次悬停和取消悬停,JQuery 按钮就会坏掉 :-(
嗨,我找到了一种解决背景图像“溶解”过渡的方法。
http://jsfiddle.net/4a5RV/1/
它利用了 CSS 内容,并且仅适用于纯色背景…但适用于 Gecko 和 Webkit 浏览器 :-)
我喜欢选项 1,并且在一些图像悬停中使用它。效果很好,我不介意悬停状态在某些浏览器实例中不起作用时的过渡,但我的悬停状态没有太多对比度。感谢发布!
我弄不明白,我在编码方面是新手… 我有一个使用 css 图片精灵的 3 种状态的按钮,但我不知道如何在其中加入这种效果。
我的代码如下:
body {
background-color: #d3d3d3;
}
ul.button {
margin: auto;
list-style: none;
padding: 0px;
}
.displace {
position: absolute;
left: -5000px;
}
ul.button li {
margin: auto;
float: left;
}
ul.button li a {
display: block;
width: 183px;
height: 68px;
background: url('sprite.png');
}
ul.button li.download a {
background-position: 0 0;
}
ul.button li.download a:hover {
background-position: 0 -68px;
}
ul.button li.download a:active {
background-position: 0 -136px;
}
#allbutton {
margin-left: auto;
margin-bottom: auto;
margin-right: auto;
margin-top: 50px;
width: 183px;
}
Download
span 位置 -50px 怎么样?
第一种方法(合理的渐进式):按钮在 IE8 中始终处于活动状态,还是如果 IE8 则应该使用 span 进行 hack
background-position: 0 0; 以及
.arrow:hover span { opacity: 1; background-position: -50px 0; }
嗨,我能够成功地完成第一种和第二种方法,但是,我使用了一个精灵,它有一些部分是填充的,但当悬停时,会变得透明。
我注意到,所有这些代码做的只是将两个背景重叠。这对我有问题,因为非活动状态可以在活动状态下看到。有没有办法让非活动状态的透明度在悬停时变为 0?
抱歉,我对 CSS 比较生疏。