CSS捡屎记

2019 年 3 月 20 日 图灵教育

农谚:“种地不上粪,等于瞎胡混。”

跟许许多多大城市里的上班族一样,我也是在农村长大的。因此,毋庸讳言,我小时候拾过粪。毕竟,那时候在农村长大的孩子,有几个没拾过粪呢。粪就是屎,主要是牛屎,因为个头大,我们那里也把风吹日晒干了的牛粪叫作“牛粪坯子”。

屎,本来是废弃物。但正如牛粪,却是农民种地所必需的天然肥料,是庄稼茁壮成长的营养来源,更是来年好收成的重要保障。俗话说:“没有尿屎臭,哪有稻米香?”

如今,我有幸成为一名在前端领域辛勤耕种的码农。就在前几天,我心血来潮,从电脑里翻出了十几年前出版的一本CSS名著的第1版(2006年)和第2版(2009年)。翻来翻去,我不禁联想到小时候拾粪的经历。说到这里,不少读者可能还不明就里,其实如果你是一名资深前端,我只要提几个当年火得不得了的技术你就会明白我在说什么了。

好吧,闲话少说,言归正传。马上开始我们的CSS拾粪之旅吧!


圆角盒子

不知道大部分读者怎么样,反正我一听到这个词就会有一种穿越感。十几年前,CSS远远不如今天这么强大。页面仔们想要在网页中实现稍微前沿、酷炫一点的效果,都必须绞尽脑汁。

滑动门

“滑动门”,即Sliding Doors,是诞生于2003的一种实现“圆角盒子”技术。假设最终要通过CSS实现下图中这样可以伸缩适应的圆角盒子:

你会怎么做?

……等等,那可是在遥远的2003年,当时的CSS标准里并没有border-radius这么一个属性,更没有浏览器支持类似的特性。于是,一位聪明的大牛Douglas Bowman发明了“滑动门”技术。其原理如下图所示:

图中展示了两个GIF图片:top-left.gif和top-right.gif,前者头部是一个1/4圆且比较长,后者尾部是一个1/4圆且比较短。

关键是使用background-imagebackground-position属性,后者最终会覆盖到前者上面。当然,要实现4个圆角,就必须要用到4张图片:

配合HTML标记和CSS代码更容易理解:

  
  
    
  1. <div class="box">

  2. <div class="box-outer">

  3. <div class="box-inner">

  4. <h2>Headline</h2>

  5. <p>Content</p >

  6. </div>

  7. </div>

  8. </div>

  
  
    
  1. .box {

  2. width: 20em;

  3. background: #effce7 url(images/bottom-left.gif) ➥

  4. no-repeat left bottom;

  5. }

  6. .box-outer {

  7. background: url(images/bottom-right.gif) no-repeat right bottom;

  8. padding-bottom: 5%;

  9. }

  10. .box-inner {

  11. background: url(images/top-left.gif) no-repeat left top;

  12. }

  13. .box h2 {

  14. background: url(images/top-right.gif) no-repeat right top;

  15. padding-top: 5%;

  16. }

  17. .box h2, .box p {

  18. padding-left: 5%;

  19. padding-right: 5%;

  20. }

(文中代码左右滑动即可查看)

哇哦,精彩!

可以脑补出来最终效果的同学请为自己鼓掌,同时也恭喜你成功捡起了第一块“牛粪”。暂时还没搞明白的小伙伴也不必气馁,有时候捡屎本身也是个技术活儿呢~

山顶角

“山顶角”,英文是Mountaintop Corners,诞生于2004年,由另一位牛人Dan Cederholm发明。相比于“滑动门”直接用图片本身充当圆角,“山顶角”反其道而行之:用圆角蒙版遮住背景颜色实现圆角,因此更为灵活。上图:

如果一看到这张图你就立即明白了,那恭喜你,第二块“牛粪”成功入筐。还不明白的同学,请看以下代码,HTML跟前面类似,同样需要4个元素来应用4张背景图片:

  
  
    
  1. <div class="box">

  2. <div class="box-outer">

  3. <div class="box-inner">

  4. <h2>Headline</h2>

  5. <p>Content</p >

  6. </div>

  7. </div>

  8. </div>

CSS也极为相似:

  
  
    
  1. .box {

  2. width: 20em;

  3. background: #effce7 url(images/bottom-left.gif) ➥

  4. no-repeat left bottom;

  5. }

  6. .box-outer {

  7. background: url(images/bottom-right.gif) no-repeat right bottom;

  8. padding-bottom: 5%;

  9. }

  10. .box-inner {

  11. background: url(images/top-left.gif) no-repeat left top;

  12. }

  13. .box h2 {

  14. background: url(images/top-right.gif) no-repeat right top;

  15. padding-top: 5%;

  16. }

  17. .box h2, .box p {

  18. padding-left: 5%;

  19. padding-right: 5%;

  20. }

成功捡到这块“牛粪”的同学也不要过分兴奋,“山顶角”虽然可以通过简单修改背景颜色来改变圆角盒子的颜色,省去重新制作图片的麻烦,但它也有不足。由于当时每个角的蒙版图片是用位图制作的,所以只适用于制造细微的曲线,较大弧度的圆角会显得粗糙。

不过,瑕不掩瑜。“山顶角”无论如何都是当时制作圆角盒子当之无愧的王牌技术,更是当时每一个页面仔的大救星。十几年后,当屏幕前的我们与这块“牛粪”不期而遇时,一定也会暗自赞叹。关键是,这块简洁巧妙的牛粪,它好捡啊!

多重背景图片

在前述两块重量级“牛粪”的启发下,支持多背景图片的background-image属性终于应运而生。于是,更简单的实现方案出现了:

  
  
    
  1. .box {

  2. background-image: url(/img/top-left.gif),

  3. url(/img/top-right.gif),

  4. url(/img/bottom-left.gif),

  5. url(/img/bottom-right.gif);

  6. background-repeat: no-repeat,

  7. no-repeat,

  8. no-repeat,

  9. no-repeat;

  10. background-position: top left,

  11. top right,

  12. bottom left,

  13. bottom right;

  14. }

当然,给一个元素应用多个背景并不局限于实现圆角盒子效果。至于还可以实现什么,请相信:限制你的只有你的想象力。

圆角边框

同样是在前两块“牛粪”滋养的沃土之上,迄今为止最为简单强大的border-radius属性也诞生了:

  
  
    
  1. .box {

  2. border-radius: 1em;

  3. }

成功捡起两块“牛粪”之后,是不是很有成就感?你还想继续捡?没问题,走着~


下拉阴影

想当初,不仅仅是实现圆角盒子需要全世界的大牛为之殚精竭虑,同样让他们苦思冥想的还有下拉阴影。

先看看Dunstan Orchard大牛的杰作。其核心思想就是给元素背景上应用一大张阴影图,然后通过负外边距把阴影部分显露出来。

如图所示,这是一张800px✕800px的阴影图shadow.gif,其右下角放大后看可以看到5像素的阴影。以下是要应用阴影效果的HTML:

  
  
    
  1. <div class="img-wrapper">

  2. < img src="dunstan.jpg" width="300"➥

  3. height="300" alt="Dunstan Orchard" />

  4. </div>

显然,这是一个容器div中包含一张人物图片(dunstan.jpg)。为了让容器div包裹住图片,首先要利用float让这个块级元素收缩,从而包裹住其中的图片:

  
  
    
  1. .img-wrapper {

  2. background: url(images/shadow.gif) no-repeat bottom right;

  3. clear: right;

  4. float: left;

  5. }

但这样背景图片完全隐藏在了人物图片下方,为了让它显露出来,还必须配合神奇的负外边距:

  
  
    
  1. .img-wrapper img {

  2. margin: -5px 5px 5px -5px;

  3. }

于是,立体感十足的阴影效果做成了,见下图:

不过,这硬边阴影看着也忒不自然了,就算是在十几年前也是无法接受的。那好,这块“牛粪”还要做大点。为了模拟出自然的阴影,还需要一张与刚才的阴影图片对角的模糊蒙版:

HTML标记也要再嵌套一层 div

  
  
    
  1. <div class="img-wrapper">

  2. < img src="dunstan.jpg" width="300"➥

  3. height="300" alt="Dunstan Orchard" />

  4. </div>

首先,还是给最外层的容器 div应用硬边阴影背景,定位在右下角:

  
  
    
  1. .img-wrapper {

  2. background: url(images/shadow.gif) no-repeat right bottom;

  3. float: left;

  4. }

然后,给内层的 div应用模糊蒙版背景,定位在左上角:

  
  
    
  1. .img-wrapper div {

  2. background: url(images/mask.png) no-repeat left top;

  3. padding: 0 5px 5px 0;

  4. }

最后,再给图片添加个边框:

  
  
    
  1. .img-wrapper img {

  2. background-color: #fff;

  3. border: 1px solid #a9a9a9;

  4. padding: 4px;

  5. }

大功告成:

完美!

盒阴影

这块大“牛粪”威力够大,直接催生了 box-shadow

  
  
    
  1. img {

  2. box-shadow: 3px 3px 6px #666;

  3. }

这里用了仅仅一个属性,而且效果同上。冗长的HTML和CSS代码不见了,它们去哪儿了?那还用问,它们已经化作沉甸甸的“牛粪”装进了你我的粪筐里。恭喜你再次捡屎成功!


图片替换

想当年,大牛们为了使用特殊字体实现不一样的视觉效果,必须先把文字转换成图片,因为用户机器上已安装的通用字体数量有限。但图片对搜索引擎不友好,于是有牛人想出了点子。总体的思路是像往常一样使用文本,让搜索引擎可以找到,同时再通过某种方式让它对用户不可见,只显示包含特殊字体效果的图片。

比如,Todd Fahrner的Fahrner Image Replacement (FIR)。先把文本包一个 span中:

  
  
    
  1. <h2>

  2. <span>Hello World</span>

  3. </h2>

然后给标题 h2添加背景:

  
  
    
  1. h2 {

  2. background:url(hello_world.gif) no-repeat;

  3. width: 150px;

  4. height: 35px;

  5. }

最后,隐藏 span

  
  
    
  1. span {

  2. display: none;

  3. }

可是,由于多数屏幕阅读器会忽略 display:none;的元素,从而导致严重的无障碍问题。所以,这个看似简单的方案实践中并不可行。

于是,另一位牛人Mike Rundle想出了一个两全其美的点子:使用负文本缩进把文本拉到屏幕之外!

这下HTML还更简单了:

  
  
    
  1. <h2>

  2. Hello World

  3. </h2>

CSS:

  
  
    
  1. h2 {

  2. text-indent: -5000px;

  3. background:url(hello_world.gif) no-repeat;

  4. width: 150px;

  5. height:35px;

  6. }

这就解决了屏幕阅读器用户的问题。但还没有完,新的问题又出来了。在当时网络速度很慢的情况下,可能会有用户禁用浏览器显示图片的功能,而CSS照样起作用。这是一种极端情况,这时候用户会既看不到文本,也看不到图片。

追求完美的大牛们又开始行动了。Tom Gilder和Levin Alexander最终找到了既对屏幕阅读器友好,又能在禁用图片打开CSS的情况下让文本对用户可见的方案。

这个方案首先要在被替换的元素内额外添加一个空标签( span):

  
  
    
  1. <h2>

  2. <span></span>Hello World

  3. </h2>

然后,将容器设置为相对定位:

  
  
    
  1. h2 {

  2. width: 150px;

  3. height: 35px;

  4. position: relative;

  5. }

position:relative;将容器设定为其中span的定位上下文。接下来,把背景应用给span,并采用绝对定位,而宽和高均为父元素的100%会让它完全把文本盖在下面:

  
  
    
  1. h2 span {

  2. background: url(hello_world.gif) no-repeat;

  3. position: absolute;

  4. width: 100%;

  5. height: 100%;

  6. }

这里只有一个问题,此时的图片必须完全不透明,否则下面的文本就会“走光”。

如前所述,这几块“牛粪”最终要解决的是用户计算机上字体匮乏的问题。这些需求最终也催生了十几年后可以广泛使用的Web字体。

  
  
    
  1. @font-face {

  2. font-family: Vollkorn;

  3. src: url('fonts/Vollkorn-Regular.eot#?ie') format('embedded-opentype'),

  4. url('fonts/Vollkorn-Regular.woff2') format('woff2'),

  5. url('fonts/Vollkorn-Regular.woff') format('woff'),

  6. url('fonts/Vollkorn-Regular.ttf') format('truetype'),

  7. url('fonts/Vollkorn-Regular.svg') format('svg');

  8. }


Web字体是一个大话题,在此我们就不过多涉及了。总之,我们再一次见证了“牛粪”的力量,同时也给我们今天的拾粪之旅画上了一个完美的句号。


明日份牛粪

天下码农千千万,大牛却不多。大牛之所以成为大牛,通常都会给数年后的从业者留下可供捡拾的“牛粪”。今天我们的拾粪之旅,既是对CSS历史上曾经辉煌一时的技术的巡礼,更是对如群星般璀璨的大牛们的致敬。

这些曾经红极一时的技术在今天看来或许不值一提,甚至幼稚可笑。然而,“后之视今,亦犹今之视昔。”今天被顶礼膜拜、推崇备至的技术,十几年后再看,或许同样不值一提,甚至幼稚可笑。但不容否认的是,恰恰是这些今天看来简单、幼稚的“牛粪”,孕育、滋养了一代一代技术人,推动着技术不断进步和突破。人类社会就是这样一路走过来的。

朝花夕拾。从拾粪的视角看,我们不禁深思:今天的码农,有几人能留下供十年后的人捡拾的“牛粪”呢?所以,今天起,给自己定个小目标,着手准备我们的明日份“牛粪”吧!

看到这里,有好奇的同学可能会问:这些“牛粪”到底来自哪本CSS名著,能否透露一下?当然可以。它们就是CSS Mastery: Advanced Web Standards Solutions (中文版《精通CSS》)的第1版和第2版。而且,这本名著的最新版也就是第3版的中文版也刚刚上市。值得一提的是,《精通CSS(第3版)》里可是满满的“明日份牛粪”哦,如果想开启你的CSS“捡屎”之旅,那一定会是个不错的体验。

CSS畅销经典全面升级,充分展示现代CSS实践技巧

扫我捡屎

作者:Andy Budd,Emil Björklund

译者:李松峰


本书是CSS经典图书升级版,结合CSS近年来的发展,尤其是CSS3和HTML5的特性,对内容进行了全面改写。本书介绍了涉及字体、网页布局、响应式Web设计、表单、动画等方面的实用技巧,并讨论了如何实现稳健、灵活、无障碍访问的Web设计,以及在技术层面如何实现跨浏览器方案和后备方案。本书还介绍了一些鲜为人知的高级技巧,让你的Web设计脱颖而出。


文末畅聊

有人说CSS为什么那么难学?有人说CSS可以很优雅。学习CSS的小伙伴可以来说说你当初是怎么跟它结缘的。没学过CSS的小伙伴可以说说最近自己写代码的状态怎样?有没有遇到什么困难。精选留言选出5位获得赠书。活动截至2019.3.22。欢迎大家畅所欲言。

推荐阅读:

“表姐”升职记

没有π的日子,我竟然过得如此凄惨

一个西二旗码农的自白


更多前端好书,一戳便知

登录查看更多
0

相关内容

还在修改博士论文?这份《博士论文写作技巧》为你指南
【实用书】Python爬虫Web抓取数据,第二版,306页pdf
专知会员服务
115+阅读 · 2020年5月10日
《代码整洁之道》:5大基本要点
专知会员服务
49+阅读 · 2020年3月3日
《动手学深度学习》(Dive into Deep Learning)PyTorch实现
专知会员服务
116+阅读 · 2019年12月31日
深度学习界圣经“花书”《Deep Learning》中文版来了
专知会员服务
230+阅读 · 2019年10月26日
机器学习相关资源(框架、库、软件)大列表
专知会员服务
38+阅读 · 2019年10月9日
手把手教你用Python实现“坦克大战”,附详细代码!
机器学习算法与Python学习
11+阅读 · 2019年6月8日
基于Web页面验证码机制漏洞的检测
FreeBuf
7+阅读 · 2019年3月15日
说说我的老同事,前端大神程劭非
余晟以为
17+阅读 · 2019年1月14日
Python | Jupyter导出PDF,自定义脚本告别G安装包
程序人生
7+阅读 · 2018年7月17日
浅谈浏览器 http 的缓存机制
前端大全
6+阅读 · 2018年1月21日
教你用Python来玩跳一跳
七月在线实验室
6+阅读 · 2018年1月2日
tensorflow LSTM + CTC实现端到端OCR
机器学习研究会
26+阅读 · 2017年11月16日
Arxiv
4+阅读 · 2019年12月2日
Continual Unsupervised Representation Learning
Arxiv
7+阅读 · 2019年10月31日
VIP会员
相关VIP内容
还在修改博士论文?这份《博士论文写作技巧》为你指南
【实用书】Python爬虫Web抓取数据,第二版,306页pdf
专知会员服务
115+阅读 · 2020年5月10日
《代码整洁之道》:5大基本要点
专知会员服务
49+阅读 · 2020年3月3日
《动手学深度学习》(Dive into Deep Learning)PyTorch实现
专知会员服务
116+阅读 · 2019年12月31日
深度学习界圣经“花书”《Deep Learning》中文版来了
专知会员服务
230+阅读 · 2019年10月26日
机器学习相关资源(框架、库、软件)大列表
专知会员服务
38+阅读 · 2019年10月9日
相关资讯
手把手教你用Python实现“坦克大战”,附详细代码!
机器学习算法与Python学习
11+阅读 · 2019年6月8日
基于Web页面验证码机制漏洞的检测
FreeBuf
7+阅读 · 2019年3月15日
说说我的老同事,前端大神程劭非
余晟以为
17+阅读 · 2019年1月14日
Python | Jupyter导出PDF,自定义脚本告别G安装包
程序人生
7+阅读 · 2018年7月17日
浅谈浏览器 http 的缓存机制
前端大全
6+阅读 · 2018年1月21日
教你用Python来玩跳一跳
七月在线实验室
6+阅读 · 2018年1月2日
tensorflow LSTM + CTC实现端到端OCR
机器学习研究会
26+阅读 · 2017年11月16日
Top
微信扫码咨询专知VIP会员