话说web前端的技术先驱,国外当属Yahoo,而国内则当属淘宝。因此它们的一举一动都是整个互联网的风向标。css
就在前几天,偶然发现曾经一直困扰本身的鼠标悬停共用部分空间的问题在淘宝这里有了解决方案,立刻拿来分析下。html
用语言描述老是怪怪的,仍是上图吧。前端
能够看到,按照正常的的导航制做方法,每一个按钮元素都有本身的独立区域,它们之间互不影响。但在本例中,两个按钮却在悬停状态下共用了中间一条线的区域,它是如何实现的,咱们一步步来分析。先看它的背景原图(其它部分不重要,无视之)web
从原图上看,与咱们传统的Sprite并没有区别。再来看看Html结构浏览器
1
2
3
4
5
6
|
/*这是我本身写的,与淘宝原始结构稍有不一样*/
<
ul
>
<
li
class
=
"nav1"
><
a
href
=
"#"
>1</
a
></
li
>
<
li
class
=
"nav2"
><
a
href
=
"#"
>2</
a
></
li
>
<
li
class
=
"nav3"
><
a
href
=
"#"
>3</
a
></
li
>
</
ul
>
|
此结构与正常结构并没有区别,继续用普通方法定义CSS性能优化
1
2
3
4
5
6
7
8
|
li {
float
:
left
;
margin
:
0
;
padding
:
0
;}
li a {
float
:
left
;
display
:
inline
;
height
:
38px
;
text-indent
:
-10000px
;
overflow
:
hidden
;
background
:
url
(
'sprites.gif'
)
no-repeat
;}
li.nav
1
a {
width
:
103px
;
background-position
:
0
-19px
;}
li.nav
1
a:hover {
background-position
:
0
-57px
;}
li.nav
2
a {
width
:
91px
;
background-position
:
-103px
-19px
;}
li.nav
2
a:hover {
background-position
:
-103px
-57px
;}
li.nav
3
a {
width
:
106px
;
background-position
:
-194px
-19px
;}
li.nav
3
a:hover {
background-position
:
-194px
-57px
;}
|
效果以下dom
能够看出,当鼠标悬停在中间按钮时,并无实现咱们想要的效果,这固然也是在乎料之中的。继续分析,咱们但愿鼠标悬停在中间按钮时按钮空间能够占据右侧竖线的一像素,这时想到当:hover时,元素可使margin-left负一个像素,这样中间按钮就向左偏移了一个像素,为了使它的物理大小不发生变化,再给它定义一个像素的padding-left,这样该按钮在逻辑上增大了一个像素,物理上却没有变化,经过修改CSS,让:hover下背景定位向右偏一个像素性能
1
2
3
4
5
|
/*修改过的CSS*/
li a:hover {
margin-left
:
-1px
;
padding-left
:
1px
;}
li.nav
1
a:hover {
background-position
:
1px
-57px
;}
li.nav
2
a:hover {
background-position
:
-102px
-57px
;}
li.nav
3
a:hover {
background-position
:
-193px
-57px
;}
|
效果以下测试
这正是咱们要的效果。经测试,发现进行负值操做后IE6下面出现bug优化
乍一看,咱们的css没有生效,其实否则,为了解决此bug,按钮元素须要加上position:relative;
1
|
li a {
position
:
relative
;
float
:
left
;
display
:
inline
;
height
:
38px
;
text-indent
:
-10000px
;
overflow
:
hidden
;
background
:
url
(
'sprites.gif'
)
no-repeat
;}
|
这样,此bug就已经被修复了,IE6下显示正常。(对此bug的产生缘由并无深刻研究,请高手补充)
到此,咱们须要的效果就已经实现了。
等等!若是仅仅只是到此,这不过是一个小技巧而已,并无什么。其实好戏才刚刚开始!
在研究淘宝代码的过程当中,发现它用了一个怪异的文档结构,以下图
能够看到,它没有用咱们经常使用的<li class="nav1"><a href="#">1</a></li>方式制做按钮,而是采用了img图片,src中的地址正是用来作Sprite的背景图片。就在我对此百思不得其解的时候,猛然想起曾经看过的一篇关于浏览器对图片加载顺序的文章,我恍然大悟,难道它这么作是与此有关?
补充,若是称传统Sprite技术为CSS Sprite的话,该技术则为IMG Sprite
立刻进行测试,文档结构以下
1
2
3
4
5
6
|
<
ul
>
<
li
class
=
"nav1"
><
a
href
=
"#"
>1</
a
></
li
>
<
li
class
=
"nav2"
><
a
href
=
"#"
>2</
a
></
li
>
<
li
class
=
"nav3"
><
a
href
=
"#"
>3</
a
></
li
>
</
ul
>
<
img
src
=
"37.jpg"
/>
|
结果以下
结果果真如预期所料,因为浏览器渲染时认为img为内容,而background只是修饰,因此在加载时,浏览器会先加载img图片,而最后才加载background的图片。浏览器这样认为,从逻辑上来说是对的,但在实际运用中,咱们每每会把导航作为最重要的部分,并且但愿它可以最快的加载出来。因为浏览器的这个特性,咱们每每不得不接受在加载大量img图片以后才看到导航缓缓出现,若是background在导航中仅仅只是修饰做用还好,若是像此例般,描述性文字是存在于图片中,继而让浏览者面长时间对空白等待,这就不可接受了。
通过上述分析,再回过头来从新看淘宝的结构,便能明白他这样作的良苦用心。
按照淘宝的风格,从新定义文档结构以下
1
2
3
4
5
6
|
<
ul
>
<
li
class
=
"nav1"
><
a
href
=
"#"
><
img
src
=
"img/sprites.gif"
/></
a
></
li
>
<
li
class
=
"nav2"
><
a
href
=
"#"
><
img
src
=
"img/sprites.gif"
/></
a
></
li
>
<
li
class
=
"nav3"
><
a
href
=
"#"
><
img
src
=
"img/sprites.gif"
/></
a
></
li
>
</
ul
>
<
img
src
=
"37.jpg"
/>
|
再次测试
一样,结果与预料中同样,它按照咱们想要的顺序来执行加载。至于CSS一样是使用margin负值,并没有太多新东西,直接贴出
1
2
3
4
5
6
7
8
9
10
11
12
|
li {
float
:
left
;
margin
:
0
;
padding
:
0
;}
li a {
position
:
relative
;
float
:
left
;
display
:
inline
;
height
:
38px
;
overflow
:
hidden
;}
li a:hover {
margin-left
:
-1px
;
padding-left
:
1px
;}
li.nav
1
a {
width
:
103px
;}
li.nav
1
a img {
margin
:
-19px
0
0
0
;}
li.nav
1
a:hover img {
margin
:
-57px
0
0
0
;}
li.nav
2
a {
width
:
91px
;}
li.nav
2
a img {
margin
:
-19px
0
0
-103px
;}
li.nav
2
a:hover img {
margin
:
-57px
0
0
-103px
;}
li.nav
3
a {
width
:
106px
;}
li.nav
3
a img {
margin
:
-19px
0
0
-194px
;}
li.nav
3
a:hover img {
margin
:
-57px
0
0
-194px
;}
|
效果一样是正确的,IE6一样(这里有一事不解,若是不对li a:hover进行定义,li.nav1 a:hover img的定义在IE6下便会失效)
到此,这个效果算是大功告成了。
固然,采用此方法也有弊端,因为按钮使用的是图片,在禁用CSS或WAP下浏览,浏览者就会由于图片没有进行过定位的整张Sprite图片而感到迷惑。固然,在一般状况下这种方法所带来的性能优化与所付出的代价相比是值得的。
后记
本文是我认真写的第一篇博文,并无参考过多前辈的文章,因此此方法或许早有人推而广之了。在这里仍是要感谢淘宝的UED们,大家的做品让我收获不已。同时以上分析仅仅是个人一家之言,或许淘宝他们之因此这么作还有其它理由,或许只有淘宝的UED们才讲得清了。最后,以上分析若有错误,请多多指正。
关于元素加载的更多内容参看个人转载:http://hi.baidu.com/gdgd8760/blog/item/710910d3ac4750c8a8ec9a30.html
感谢radom童鞋的补充,关于Img Sprite的其它优点请参看文章:http://www.cnblogs.com/radom/archive/2011/05/18/2050