你问我答(36)——带有纹理的渐变背景处理方法
每天收到不少问题,遇到有代表性的我就多花些时间,给出一个比较详细的回答,希望这样可以帮助更多有类似问题的读者。
问题描述

前几天有一位读者在我们的论坛上发了一个帖子,希望制作这样的一个网页菜单,需要使用CSS来实现。它给出了一个图示:
图中给出了他的切片思路,他的问题是:“自适应高度的 , 上下的1和3两个部分用 img src, 中间部位“2”, 不知道怎样设置渐变色背景了,哪位大侠能给讲解一下呢, 谢谢了。”
问题原因
从他的配图,以及他的文字描述,可以看出,“表格布局”方式已经深深刻进这位读者的脑子里了,使用CSS的时候最重要的一点就是要忘掉表格布局的思路。所以从这个意义上说,有些从零开始的读者学起来反而容易一些。就像一个成年人学外语很难,而小孩则容易得多,因为母语已经深深刻在我们的脑子里面了。英语老师常说的一句话是:“Think in English”。
CSS布局的一个最重要的原则就是,一切以内容为出发点,这个例子显然是一个很典型的列表菜单,那么它的HTML就是一个 ul 列表。我们要做的就是如何让这个ul列表具有设计图中的背景。千万不要上来就把这个图用两刀坎成三块,然后在打算用HTML和CSS拼到一起,这个思路从根本上来说,就是典型的“表格布局后遗症”~~~~。这就等于我们在说:“I’ll give you some color see see ”。
基本方案
那么正确的CSS思路又是如何的呢?我们做任何事情都要有一些基本的思考方法,比如从“简单到复杂”、“从特殊到一般”等等,其实你上中学的时候。这些方法都是渗透在各门课程中的,现在想一想,都会觉得很有收获。
比如具体到这个问题,首先考虑,如果没有渐变色,我们应该怎么办?这里因为我没有原图,就自己绘制了一个简单的,但是道理和原图是完全一样的。第一步,先从最简单的开始起步,如下面图中的左图所示,这里不存在渐变地情况。
下面要解决的就是一个高度自适应的问题了,那么用CSS解决自适应高度或宽度的问题,很显然要用到“滑动门”技术了。要做滑动门就要要准备好两扇“门”了,很简单,如下图中,右边的两个图所示。他们就是左边的图切片得到的,一个去掉顶部,一个去掉底部,这样当它们叠在一起,根据内容高度上下错动时,就可以产生自适应高度的背景框了。

接下来,编写HTML:
1 2 3 4 5 6 7 8 9 10 | <div id="outer">
<div id="inner">
<ul>
<li>Artech</li>
<li>Web Dev</li>
<li>Web disign</li>
此处省略若干菜单项……
</ul>
</div>
</div> |
这里就是把ul列表的外面套了两层div,各自作为滑动门的一扇门。如果有人要较真,非要只套一层div,而把ul作为另一扇门,也是可以的,不过这里为了简单明了,用两层div。
下面设置CSS样式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #outer { width:186px; background:url(images/bottom.png) no-repeat bottom; padding:0 0 35px 0; } #inner { padding:35px 0 0 0 ; margin:0; background:url(images/top.png) no-repeat ; } ul { margin:0 20px; } |
解释一下代码:

1:外层div设置一个固定宽度,就是背景图像的宽度,然后设定背景图像,注意最后一个“bottom”,表示从这个盒子的最底端开始放置背景图像。
2:内层div使用另一个背景图像,默认情况下就是从顶端放置背景图像,在内外层盒子重叠的部分,内层的盒子会压住外层的盒子。
3:下面注意,两层盒子的padding设置,外层盒子设置下部的padding为35像素,内层盒子设置上部的padding为35像素,这样就把上下装饰图像部分都让出来,而不会遮挡住他们的了。
4:最后,把最里面的ul列表位置调整一下,就完成了。
效果如右图所示,其高度可以根据ul的高度自适应。当然如果如果太高了,以致于内外两层div的背景图像无法重叠了,就会产生裂缝了,那么一种方法是把背景图像做的高一些即可,另一种方法是外面再再多套一层div,设置一个竖直方向平铺的背景,用它来填补中间的缝隙。
渐变背景

下面考虑背景渐变的情况,例如上面部分(#inner)的背景图像变成右图所示的样子,而下面(#outer)部分的背景图不需要变化,可以发现,代码不需要做任何修改,结果仍然是正确的。
但是要注意的一点是,在这种情况下,这时列表的内容就不能太短了,如果过短的话,渐变还没有完成就直接到了下侧的颜色,如下图所示,接缝处就会不自然了。

增加纹理

这位读者的问题中给出的图还不仅仅是渐变的问题,而且增加了纹理,这就有点麻烦了。如果仍使用上面方法则是的缺陷的,如果纹理很细小,不太明显的话,上面的方法还可以凑合了,而如果纹理比较大,就会比较明显。
在这里为了突出这个问题,我特意做了一个很大的纹理效果,如右图所示。可以发现,在接缝处(红色框里)就很不自然了,上下两层背景图的圆形纹理无法正好对上。按照上面的方法,这个接缝无法避免的,因为高度会自适应,所以无法确定到底它们会在什么位置接缝。
那么是否有更好的办法呢?要实现即有渐变色,又有纹理的背景能够自然衔接,就必须要用到半透明的背景图了,这种半透明学名叫作“alpha透明”。我们知道,GIF格式的图像是不支持alpha透明的,也就是说,GIF图像中的各个像素,要么就彻底不透明,要么就彻地透明,而无法控制透明的程度。但是PNG格式的图像就支持alpha透明,可以控制各个像素的透明度,比如某个像素是30%透

因此我们就来考虑一下,如何使用这个特性来实现具有自然过渡的纹理背景。很显然,我们必须要把“渐变色”和“纹理”这两件事分配到两个图像中,并使渐变色地图像使用alpha透明,这样就可以自然过渡了。具体来说,上面的div#inner的背景图像仅负责渐变色和alpha透明,下面的div#outer负责纹理图案。
因此,首先解决 div#inner 的背景图像,把设计图改成左图所示的样子,灰白小方格交替的部分代表透明背景,在Phostoshop和Fireforks中,都是这样的。上侧的切片图像,取红色虚线以上部分。
注意,在导出的时候,在Fireworks中要选择PNG格式,要注意一点,PNG格式有 8位、24位和32位三种,由于这个图像中存在渐变色,8位格式产生的效果太差,无法使用,此外,24位的无法产生alpha透明,因此,这里选择32位的PNG格式导出(32位:24位=4字节:3字节,多出来的一个字节就是就是记录透明度的)。

接下来,div#outer的背景简单一些了,把渐变层去掉,只保留纹理层,也不需要透明,直接到处即可。
这样,代码不需要调整,产生的效果就很完美了,在IE7、IE8和Firefox中,都可以如图所示显示。
由于 IE 6 尽管支持PNG格式的图像,但是不支持PNG的Alpha属性,因此上面的页面在IE6中,不能正确先显示。要在IE6种也可以正常显示,需要借助于IE6 的 AlphaImageLoader滤镜,也同样可实现,这篇文章已经太长了,这里就不再详细介绍这个细节了,读者可以参考《CSS设计彻底研究》的129页“柔边阴影”效果在IE6中的实现方法。但是要注意,我自己实验的结果是 AlphaImageLoader滤镜只对32位PNG图支持alpha透明,8位的PNG不行。
再给大家一个把alpha透明使用得登峰造极的例子:《你问我答(21)——破解Kai Laborenz的神秘海底世界》,这个例子是一个德国人做的CSS禅意花园的例子,太酷了。
如果你对“CSS滑动门技术”还比较陌生:
1:看一下这篇文章,你问我答(11)——CSS滑动门技术的简单应用 。
2:滑动门技术非常有用,《CSS设计彻底研究》书里面在很多案例中用到了滑动门技术,表面上看起来完全不同的案例,实际上具有相同的技术本质,很有趣,有兴趣的读者可以看一看。
最后给出这个例子的源文件,感兴趣的读者可以点击这里下载。
思考题
1:使用CSS布局,最核心的思想是什么?
2:你能否列举出一些你使用过的CSS滑动门技术的应用案例?
3:你是否能举出一些例子,说明“表面上看起来完全不同,本质上却是相同的”这个道理。
===============================================
[补充说明]
这篇文章贴出来一天之后,我发现我的解决方案还是有些问题的,虽然这个方法可以解决文中所说的读者问题中给出的图的要求,但是我给出的最后一个结果图,实际上和中间我画了一个红色方框的那个图相比,二者并不完全等价。区别在于,前者是在一个渐变色的基础上增加了纹理,后者在固定色上增加纹理后,又覆盖了一层渐变色,这两个效果是不一样的。因此用这种方法能够实现的效果,对设计效果时的操作步骤和顺序是有一定要求的,符合后者操作顺序的才能够拆到两个图像中,再叠加产生最终的效果。文章顶端的那个黑色图,是可以用这种方法做到的,因为渐变色是整个压在纹理上面的,而不是纹理压着渐变色。
7,247



A unique discussion might be priced at comment. I鈥檓 sure that you should generate more on the following topic, may possibly not be a taboo theme but generally people are too little to speak in such themes. To the next. Kind regards
老师你好,请问一下,咱们站点右侧导航 鼠标悬停的效果,有一个时间差,那个是怎么实现的~
crizyant ,
这个我问题,请参考: http://learning.artech.cn/20081104.jquery-intro.html
里面有详细介绍,用了一个插接实现这个效果的。
太好了,慢慢得积累一些经验,然后付诸行动!
keke,
您说的对!
抱歉没有及时回复,我们最近很忙,下半年我们会拿出更多时间增加新内容的,欢迎来交流!
为什么浮动的盒子脱离标准流和绝对定位的盒子脱离标准流不一样呢,浮动的盒子脱离标准流只是它的父元素当它不存在一样,但祖先元素还是当它存在的,而绝对定位脱离标准流后,如果它的祖先元素都没设置定位属性,那么所有祖先元素都当它不存在呢。
小唐 ,
抱歉没有及时回复,我们最近很忙,下半年我们会拿出更多时间增加新内容的,欢迎来交流!
你上面说的是不能太短了,如果过短的话,渐变还没有完成就直接到了下侧的颜色,接缝处就会不自然了,实际上太长了就会出现纹理和渐变分离,除非纹理层有足够的长。
kyphoon,
“渐变背景”这个四个字标题的上面一段文字中,我提到了这个问题。仔细看一下我说的这段话:
“效果如右图所示,其高度可以根据ul的高度自适应。当然如果如果太高了,以致于内外两层div的背景图像无法重叠了,就会产生裂缝了,那么一种方法是把背景图像做的高一些即可,另一种方法是外面再再多套一层div,设置一个竖直方向平铺的背景,用它来填补中间的缝隙。”
抱歉没有及时回复,我们最近很忙,下半年我们会拿出更多时间增加新内容的,欢迎来交流!
发觉一个问题哈,你上面的这个结果图实际上要求列表内容还是不能太长了,长了就出问题了,呵呵。(在IE7 和firefox 3下测试)
kyphoon,
“渐变背景”这个四个字标题的上面一段文字中,我提到了这个问题。
在您的CSS书中,制作简单的带有盒子的横向导航条都是将a元素设为float:left;,让他们在同一行显示,但我记得元素设置为浮动后都将变成块级元素在浏览器中显示,是吗?
如果是这样,那么为什么书中还要将a元素设为display:block呢,既然浮动元素会以块级元素显示,那这一句岂不是多余的呢。
我自己做了实验,把a元素的display:block这一句去掉,那么导航条不会有什么变化,但导航条下面如果跟了个div元素的话,那么div元素的盒子就会不见了,这和我在论坛里提的那个问题情况有点相似,这是为什么啊?
小唐 ,
是的,这里的代码是有些多余了,有一些是不需要的,有的时候也是为了解决一些bug,所以具体做的时候,只能具体问题具体分析了。
买本《CSS彻底研究》好好看看吧,这些例子书中讲的特别详细 对看过书的我来说都是“小儿科”啦
不懂的赶紧买书吧!!
含金部分
注意,在导出的时候,在Fireworks中要选择PNG格式,要注意一点,PNG格式有 8位、24位和32位三种,由于这个图像中存在渐变色,8位格式产生的效果太差,无法使用,此外,24位的无法产生alpha透明,因此,这里选择32位的PNG格式导出(32位:24位=4字节:3字节,多出来的一个字节就是就是记录透明度的)。
小渔,
呵呵,同意!
不错,回去测试下!
cssseo ,
好啊,祝你成功:)
哇 猛啊 这几天更新这么多文章。看起来最近你很有时间
mickey ,
多些鼓励,最近还有几篇文章,我正在写,我们一边写一边贴的!希望对大家有所帮助!
是个很有意思的问题。。。。
anyLiv,
是的,多创造出一些有意思的好方法!
纹理背景这个方法很巧妙啊,学习了
任平生 ,
任何技术,多动脑子,就会出现很多巧妙的方法,需要的就是我们多思考!
加油!
top和bottom 用 这么大图的话 浏览显示时 速度方面 没有区别吗?
chase22,
1:这些图合理地选择输出选项以后,也就是几K字节,对于现在的上网速度,完全没有问题。
2:这种自适应的方式的好处就是做了背景图片,可以在一个页面的很多地方使用,这样其实非常节省带宽的。
刚看到这个教程了,,
在这里遇到真正的好老师了,写的这么详细 真的很感谢,
现在看来 我想的是完全 表格布局思路,,
想的表格布局思路 是不是 CSS基础 没打好呢?
很多时候 PS里 不知道 怎么切块,
这个题 老师的讲解下 学到了 很多,,
在一次感谢老师,谢谢
chase22 ,
不客气~~
你的这个问题挺好,又很有代表性,介绍给更多人,让到家都有一些收获,是最好的了!