枫影夜读 #24 《编写高质量代码——WEB前端开发修炼之道》

2011年5月26日 · 14 years ago

2022-08-20 原《每周读书》系列更名为《枫影夜读》

互联网业界里头,WEB前端开发算是颇为年青的一行了,大约是从原先的“网页制作”演变而来。在WEB开发还被称为“网页制作”的时代,WEB的内容还大都是静态的,内容、结构混在一起,直到WEB2.0兴起,才把前端、设计、后台等很好的分开来。而前端所要掌握的最基本的技能,大约包括:CSS、HTML和JS。

这本书的作者曹刘阳前辈,是一名资深WEB前端开发工程师,先后就职于雅虎中国和淘宝,现就职于新浪。书中所写的内容都是很实在的,没有泛泛而谈的长篇大论,有的只是实战中积累下来的大量宝贵的经验,对于前端工程师来说很有帮助。虽然你可能已经做过不少网站,虽然这些网站看起来都没有多大问题,甚至运行的很好,也兼顾了浏览器兼容性,但是你总会有没有注意到的东西。比方说HTML,这个看起来很简单的东西,往往深入去了解就会发现其实很复杂。这本书介绍了HTML、CSS和JS里头各种需要注意的地方,很细很重要,这本书的主要读者应当是已经做过一两个项目的前端工作者,对于CSS、HTML和JS都有一定程度的了解和掌握,才能比较好地理解其中的专业词汇。不过总的来说还是很容易理解的。

下面贴一下我看了本书之后的一些笔记。

第一章和第二章从网站重构一直谈到团队合作的重要性,没有很深入涉及技术,但是都很重要。

 

第三章高质量的HTML

HTML里面最需要注意的应当是标签的语义化,这点在《超越CSS》一书也重点强调过。

1.为什么要使用语义化的标签。

比方说从h1~h6,我们在浏览器中看到的内容都是经过CSS定义过样式的,但是搜索引擎“看不到”这些样式,它们看到的是直接的代码,而富有语义的代码则对搜索引擎更加友好。比方说一个网页的大纲,使用h1~h6来定义要远远好过使用无数个div。

“但是搜索引擎看不到视觉效果,看到的只是代码,只能通过标签来判断内容的语义。”

CSS很强大,但是如果使用不当,容易是我们陷入CSS布局的一个误区——只要不是table布局,只要是通过CSS布局的,就是对的,就是符合WEB标准的。如果只考虑最终视觉效果,而不考虑标签语义,其实又走上了table布局的老路。

正确的做法是:先确定HTML,确定语义的标签,再来选用合适的CSS。

2.如何确定你的标签是否予以良好

去掉样式,看网页结构是否组织良好有序,是否仍然有很好的可读性。如著名的“CSS裸体日”。

推荐使用Firefox上的一个扩展——Web Developer.

可以看看W3C官网,去掉CSS样式之后网页的可读性依然极佳。

3.常见模块

1)标题用h1~h6,段落用p等等

2)表单中,用filedset包括起来,用legend写表单的title,用label设置input的名称。(这样讲不太清楚,建议看看原书。)

3)table中,使用caption,thead,tbody,tfoot和th等标签。

第四章 高质量的CSS

这章和后面一章高质量的JavaScript都是重点。

1.怪异模式和DTD

DTD即Document Type Definition,我们一般写在HTML开头作为文件类型声明。虽然类型挺多,常见的有四种,都挺长的,而目前最新的HTML5直接写为<!DOCTYPE HTML>即可。怪异模式就又是IE的专利了,如果我们的DTD漏写了,在FF里面是没问题的,但是在IE(6、7、8都是)里面就会变得很诡异了。

2.组织CSS

书中介绍一种把CSS分为三层的方法:base层->common层->page层。

最底层的base层可以说是css reset,中间common层则提供组件,page层则每个页面都不同,也是我们写CSS的重点。

base层因为只是做reset工作,一般有一个成熟的文件就可以了,可以使用作者推荐的base.css文件,在书里有,或者直接用YUI框架里头的那个也行。

3.划分模块

写CSS类的时候我们通常需要观察设计稿中相同的部分,然后划分出各个不同的模块,最大程度地使得模块可以重用。

以下是划分模块的技巧:

1)模块与模块之间尽量不要包含相同的部分,如果有相同的部分,应将它们提取出来,拆分成一个独立的模块。

2)模块应在保证数量尽可能少的原则下,做到尽可能简单,以提高重用性。

4.CSS命名

CSS的命名推荐使用英语。

常用的命名法有骆驼命名法和划线命名法。推荐将这两种方法组合使用。比方说一个ul(比方class为timeList)中最后一个li我们要设置不一样的样式,比方多个左下右下的圆角或者少个下划线什么的,那么通常我们会在最有一个li里面定义一个"last"的class,然后再用子选择符比方这么写: .timeList li{...} .timeList li:last{...}这样。但是这样涉及一个问题:滥用子选择符。为了避免多工程师合作时产生的样式层叠等问题,不推荐轻易使用子选择符。

这时候就使用两种命名法组合使用,给最后一个li命名为timeList-last,或者timeList_last。这样可以很清晰地看到这个last属于timeList模块,而又不至于名字太长。

多工程师合作的时候,为了避免不同的工程师在同个页面用了同样的class名称,可以加个前缀,比方说zhang xia工程师负责的内容,就给命名前面加个zx-xxxx。这样命名虽然会变很长,但是当项目很大的时候这样的命名还是很有帮助的,利大于弊。

5.多用组合,少用继承

我们知道class和id的区别在于class可以有多个而id只能有一个。

在给几个看起来很相似的ul定义不同的样式的时候,我们可以给每个ul都定义不同的名字然后分别定义样式。但是这样的话,我们的CSS代码会看起来很冗长,当然,使用诸如 .numberList1, .numberList2{....}这样的方法可以是代码变得简洁。但是如果几个ul的浮动、字体大小和颜色各不相同的时候我们还是得多写很多行代码。

所以可以预先定义几个浮动类 .fl{float:left} .fr{float:right},定义几个字体类 .ft12{font-size:12px} .ft16{font-size:16px},颜色类 .red{color:red},之后只要在numberList1和2中挂上各自需要类就完了。

<ul>

<li>111</li>

</ul>

<ul>

<li>111</li>

</ul>

6.处理上下margin

对于模块来说,每个模块的margin通常都是不定的,因为设计的需要会有不同的margin。所以我们可以跟第5点一样挂上个 .mt20{margin-top:20px} 这样的类。

值得注意的是,如果相邻两个div都设置了margin-left或者margin-right那么距离会被叠加,而margin-top或者margin-bottom则只会显示其中一个数值。

比方

<style type="text/css">

.up{margin-bottom: 10px}

.down{margin-top: 10px}

</style>
<div class="up"></div>

<div class="down"></div>

本来我们指望这两个div可以相距20px,但事实上只相距了10px。

总结:如果不确定上下模块的上下margin特别稳定,最好不要将它写到模块的类里,而是使用类的组合,单独为上下margin挂用于边距的原子类(例如mt10,mb20)。模块最好不要混用margin-top和margin-bottom,统一使用margin-top或者margin-bottom。

 

7.低权重原则

当不同选择符的样式设置有冲突的时,会采用权重高的选择符设置的样式。

权重的规则是这样的:HTML标签的权重是1,class的权重是10,id的权重是100。例如p的权重是1,"div em"的权重是1+1=2,"strong.demo"的权重是10+1=11,"#test .red"的权重是100+10=110。

如果CSS选择符的权重相同,那么样式会遵循就近原则,哪个选择符最后定义,就采用哪个选择符的样式。(也就是说,写在CSS文件里面比较靠后的会覆盖写在前面的。)

为了保证样式容易被覆盖,提高可维护性,CSS选择符需保证权重尽可能低。

8.CSS sprite

为了减少HTTP请求,可以把不常变动的图片,比方说那些箭头啦下拉框啦按钮啦什么的合成一张图(这个大家应该不陌生了)。

不过这个也有缺点:1)影响开发速度;2)大图中每一个小图都不可以轻易改动,牵一发则动全身,等下整张图要重来过,而相关的CSS坐标也要全部重新标过

由于代价挺大的,所以流量不大的网站就没什么必要花费时间在这个东西上了,不划算呀。

9.常见问题

1)编码风格

作者推荐使用一行式代码风格。就是:

.test{width:960px;...}

.demo{background-color:green;...}

2)id和class

a.同一个网页,相同的id只能出现一次而class可以多次

b.id的选择符权重为100而class为10

c.原生的JS提供getElementById(),但是木有getElementByClassName(),所以要么自己写个要么用框架。

 

3)CSS hack

各种hack的方法大家应该都不陌生了,不一一赘述,总之轻易别hack,而各种hack方法各有利弊,自己是情况使用。

 

4)hasLayout

又是IE的专利,在IE里头如果出现各种诡异的错误想破脑袋解决不了的话可以试试触发IE才有的hasLayout属性,这是IE用于CSS的解析引擎,有时候触发这玩意儿一些诡异的错误就自动解决了。出发方法可以使用“zoom:1”来触发,这是相对比较好的方法。

 

5)块级元素和行内元素的区别

就是block和inline的区别。块级元素有div、p、form、ul等,行内元素有span、strong、em等。

块级元素会独占一行,默认情况下宽度自动填满父级元素。行内元素则不会独占一行,相邻的元素会排列在一行,排不下再自动换行,宽度随内容自适应。

块级元素可以设置margin和padding。行内元素的margin和padding则很诡异,水平的没问题,但是竖直的设置了会变大但是没有边距效果。

10.网格布局

注意:main的内容比sidebar的更重要,无论sidebar和main在样式上谁左谁右,在html标签上要保证main的标签在sidebar之前被加载(就是写在在sidebar之前)。

11.使用IETester进行IE兼容性调试。

 

 

第四章 高质量的JavaScript

1.使用匿名函数将脚本抱起来,可以有效控制全局变量,避免冲突隐患。如:

(function(){

var a = 123;

//工程师A写的代码

...

})();

...

(function(){

var a = 456;

//工程师B写的代码

...

})();

这样,虽然同样有个变量为a,如果没有匿名函数包裹那么a就是全局变量,互相之间就会影响到,用匿名函数包裹起来则作用域就在函数内,不会互相影响了。

2.使用命名空间

GLOBAL.A={};

GLOBAL.A.str2=a;

GLOBAL.A.str=b;

还可以使用多级命名空间:

GLOBAL.A.CAT={};

GLOBAL.B.CAT={};

GLOBAL.A.CAT.name="mimi";

GLOBAL.B.DOG.name="wangcai";

GLOBAL.A.CAT.move=function(){

...

}

GLOBAL.B.CAT.move=function(){

...

}

3.window.onload和DOMReady

二者都是在页面加载完成后执行函数。但是window.onload是必须所有元素都加载完成,也就是所有图片啦各种富媒体啦都下载完才会执行,而像DOMReady则是各种JS框架基本都提供的方法,比方jQuery的$(document).ready(); 用这个函数则会判断所有节点已生成时执行,即便图片没下载完,所以执行速度会快很多。

如果不想用JS框架那么就把自己的JS代码放在文件尾部的</body>前面,这样所有节点生成完就会执行该JS代码鸟~

4.CSS放在页头,JavaScript放在页尾

网速慢或者文件大的时候,用户需要第一时间看到最重要的内容,把JS文件放在页尾可以加快载入速度,而CSS放在页头则是不希望在网速慢的时候用户看到完全没样式的页面。

5.文件压缩

JS源文件我们一般有大量的空格和注释,使用压缩工具可以去掉空格和注释,还可以使用比较短的变量名代替原有变量名,使得文件变小很多。不过压缩后的文件可读性就差了,所以我们要记得备份源文件。

压缩可以使用Packer和YUI Compresser。

Packer是在线的,YUI Compresser则需要下载并使用命令行执行。

(剩下的JS高级部分就不列出来的,反正光用文字也说不清楚[其实是偷懒= =!],各位如果有兴趣就看看原书吧,还是挺不错的书的。^^)