正因为我们是前端,所以代码更需要优雅

前端是个很特殊,带点矛盾的职位。所以我们的“前端攻城师”也大都是些矛盾体。矛盾在感性和理性之间,矛盾在文艺和三俗之间,矛盾在放任和严谨之间。作为所谓的“攻城师”,攻的不仅是“前端”这座善变诡异的高城,同时也是在攻我们自己对于艺术和编码的心防。
【关于HTML】
--语义化
语义化,是什么?即用正确的标签做正确的事。我一直认为学一种编程语言和学一门我们常规意义里的“语言”如汉语,英语,其实是类似的。单字和单词以及语法都是一门语言的组成部分,但却不是最重要的部分。怎么去组织这些单字和语法去表达正确的意思才是语言的精髓。这就好比汉语我们每个人都会写,但是能用汉语写出惊艳的散文,写出逻辑严谨的小说的又有多少呢?所以,我们普通人和一些优秀的作家的最大的区别或许不在于知道单词的多少,了解语法的多少,而在于叙述一件事情,表达一个观点时的思维。。。
好像扯远了。回到html的语义化上。我说了,重点不在于你知晓标签的多少。哪怕你知晓了所有标签,甚至能区分了不同的DTD下符合规范的标签。那又怎么样呢?仅仅等同于熟背了一本《现代汉语词典》。每个标签都有他自己的语义。这也是为什么我们会抛弃用table来布局的方式。因为table本来的语义很明晰,就是“数据表格”,他该为数据表格而生,而不是为布局而生。
举一个一线互联网公司一个关于合理使用html标签的笔试题:
<P>小明说:<BR>小王是刚来公司的前端工程师,对公司内部的"FED"称谓不了解,你给他解释下吧。<BR><BR>我把一本《前端攻略》送给了小王,他很高兴。

 请把一段简单的html写成你觉得规范的,优雅的html。

如果我们考虑到标签的闭合,考虑到标签的大小写。于是我们会这样改:

<p>小明说:<br/>小王是刚来公司的前端工程师,对公司内部的"FED"称谓不了解,你给他解释下吧。<br/><br/>我把一本《前端攻略》送给了小王,他很高兴。</p>

 

如果我们考虑到合理使用标签。为什么要两个br连用?其实那里应该已经可以分为两个段落了。所以:
<p>小明说:<br/>小王是刚来公司的前端工程师,对公司内部的"FED"称谓不了解,你给他解释下吧。</p><p>我把一本《前端攻略》送给了小王,他很高兴。</p>

 

如果上面一段html出现在一个内容充实的页面里,其实基本也可以了,可是,如果我们假设我们一个页面的主要内容就是上面那一小段html,或者甚至一个页面就那一小段。那么,或许我们还需要更好的语义去修饰:
<p><strong>小明</strong>说:<br/><cite="xiaoming">小王是刚来公司的前端工程师,对公司内部的<abbr title="Front-End-Developer">"FED"</abbr>称谓不了解,你给他解释下吧</q></p><p>我把一本<cite>《前端攻略》</cite>送给了小王,他很高兴。</p>

 

到此为止,在某些情况下上面的强语义的方式是合理的,而或许某些情况上面的代码片段是有些冗余的。正如我们用汉语写文章,修饰的形容词用少了会觉得无味,用多了会显得口味重。所以,合理的判别文档在页面的权重以及用合理的标签去修饰它显得尤为重要。

 

--清晰地结构,与表现分离

说到html结构,我不得不说一种经典的思想:面向对象。OO的思想自从在经典的C语言中被推广开来后,一直长兴不衰,面向对象的确是编码中目前为此最为优雅的方式。有人或许会说,你说c,c++,java等面向对象的编码,我能理解,你说JavaScript也能面向对象的编码,我也能接受,至于html和css也能面向对象?这就有点唐突了。是的,html和css一个作为“置标语言”,一个作为样式表。能否真正的呈现面向对象的思想有待考究。不过这并不妨碍我们把OO的思想贯穿于我们的编码中。

我们知道。html是以“盒模型”为基础的,那我们不妨就面向“盒子”这个对象来架构我们的html。比如一个典型的“盒模型”类似: 

    <div class="box">
        
<h2 class="box-title"></h2>
        
<div class="box-con"></div>
        
<div class="box-footer"></div>
    
</div>

 

 

如果我们把这样一个盒子作为我们的“基对象”的话,那么html的结构会类似于下面这样:

代码
    <body>
        
<!-- 文档包裹 -->
        
<div class="wp">
            
<!-- header --> 
            
<div id="header" class="header">
                
<div class="box">
                    
<h2 class="box-title"></h2>
                    
<div class="box-con"></div>
                    
<div class="box-footer"></div>
                
</div>
            
</div>
            
<!-- main content -->
            
<div id="content" class="content">
                
<div class="box">
                    
<h2 class="box-title"></h2>
                    
<div class="box-con">
                        
<!-- left column -->
                        
<div class="box col-left">
                            ...
                        
</div>
                        
<!-- right column -->
                        
<div class="box col-right">
                            ...
                        
</div>
                    
</div>
                    
<div class="box-footer"></div>
                
</div>
            
</div>
            
<!-- footer -->
            
<div id="footer" class="footer">
                
<div class="box">
                    
<h2 class="box-title"></h2>
                    
<div class="box-con"></div>
                    
<div class="box-footer"></div>
                
</div>
            
</div>
        
</div>
    
</body>

 

这只是一个基本的例子,有些box可能没有title,有些可能不需要footer,根据实际情况随机而变即可。

至于结构与表现的分离,应该还是和一些小规范更有关系,如:

--不要使用内联样式

--不要使用带表现层的标签,如<font>,<big>,<i>,<center>...等等 

 

【关于css】 --样式的分离和聚合 世界上所有的事物都遵循的“物极必反”的道理,而这个道理在css的编码里显得尤为明显。这时候“中庸”就显得尤为重要了。 我们需要高效的,少冗余的css,所以会提倡css的分离,亦即OO-css。可是如果css分离的太彻底了,在html的维护上会是很大的问题,等于是牺牲了html的可维护性与部分优雅来成全一种偏激和绝对的oo-css。这显然也是不合理的。 我们在html文档里定义css样式渲染类名用的是class这个属性。提到class,在编码语言里是一个默认的“类”的代名词。也就是说,其实css的作者其实在创作css的时候其实就是基于“类”来考虑的,要不然也不会用class这个词作为css样式的属性名。 这自然不奇怪,oo-css的思想很早就有人提出来了,可是世上总有些矛盾是难以调和的,考虑下面的css: 

    .con-text {
        padding
: 8px 10px;
        background
: red;
        border
: 1px solid #CCC;
        color
: blue;
    
}
    <p class="con-text">test</p>

 

 

 

如果我们需要多个这样类似的p,但又要求文本颜色不一样的话,会怎么办,重写多个类? .con-text1, .con-text2 ... ?

显然太不现实,也太过冗余,所以或许我们需要用的面向对象中一个重要的思路--抽像公共接口。或许我们可以这么做:

    .normal-text {
        padding
: 8px 10px;
        background
: red;
        border
: 1px solid #ccc;
    
}
    .red 
{color: red}
    .blue 
{color: blue}
        ...
    <p class="normal-text red">test1</p>
    <p class="normal-text blue">test2</p>

 

 是的,这样做没错,而且很好,可是慢着,如果我们还要要求每个p不仅文本颜色不一样,背景色也不一样。。。怎么办?有人会想,我们照上面的思路继续抽象就好了。比如:
    .normal-text {
        padding
: 8px 10px;
        border
: 1px solid #ccc;
    
}
    .bg-red 
{background: red}
    .blue 
{color: blue}
    <p class="normal-text bg-red blue">test</p>

 

 

我们继续纠结下去,我们要border也不同,甚至padding也不同,怎么办?还继续分离吗?如果我们钻个牛角尖,我们对css进行彻底的分离,最终的结果会全是类似于

    .bg-red {background: red}
    .blue 
{color: blue}
    .pad-t8 
{padding-top: 8px}
    .pad-l10 
{padding-left: 10px}
        ...

 

最终的结果就不是面向对象了,而是面向属性了...是的,分离的越彻底,开发时的效率会越高,css文件也会越小越精简。可是别忘了这样做的后果是可能一个元素需要写5个,甚至10个并列的css类名去渲染...

那这样,我们所谓的“类”意义何在,这样又和写style内联样式有什么分别?我们维护时是不是要在html文档里满篇去找要几十上百个类名去增删改??

所以css分离是好的,可是过度的分离是不行的。如何把握尺度和权重才是最重要的。鄙人有几个小建议。

1.css面向对象请面向通用的对象。比如box,一个网站可以有多个box样式,boxA,boxB...boxF...等等,对应响应的boxA-tit,boxB-tit...等等,为这些通用的对象抽离公用的样式

2.可以为全站都通用的样式进行抽离:比如清除浮动

.clearfix:after {

content: ".";

display: block;

height: 0;

clear: both;

visibility: hidden;

}

/* Hides from IE-mac \*/

.clearfix {zoom: 1;}

/* End hide from IE-mac */

3.可以为栅格化的布局样式做抽离, 如:col-a{width:..}, clo-b {width: ..}等等

4.需要的时候局部的面向属性的绝对分离也是可以的,但请在有需要的时候局部使用。

5.建议class的并列类名不要大于3个,否则就需要考虑是否应该稍微聚合一下了。

以上只是个人建议,每个人在项目或建站时遇到的需求可能都不一样,自己秉着“中庸”的心态去权衡css的分离与聚合很重要。

【关于JavaScript】

--优雅的js

关于这个方面,大家讨论的就比较多了。我这里只举很简单的例子,比如我们要写一个幻灯片。思路我们有了,先初始化,然后需要一个变换函数,可能我们还需要一些渐变的效果,所以还需要一个渐变的函数,最后我们还需要自动轮播。有了思路,我们的代码可能大概会这样:

        function init() { //初始化
            ...
            pos();
        }
        
function pos () { //每张图片轮换函数
            ...
            window.timer 
= setInterval(function(){anim()}, 20);
        }
        
function anim () { //渐变的函数
            ...
            
if(finish) { //变换结束
                clearInter(timer);
                auto();
            }
        }
        
function auto () {
            setInterval(
function(){pos()}, 4000);
        }
        
        
/* init */
        init();

 

这样的方式我们大概可以理解为一种过程式编码。当然这样的风险有很多,比如,变量名污染,模块化管理,多实例重用等等都是问题。所以它显然不够优雅。我自己常用的方式:
        var slider = function () {
            
var init = function () {
                ...
                
this.pos();
            }
            init.protorype 
= {
                pos : 
function () {
                    
//TODO
                },
                anim : 
function () {
                    
//TODO
                }
                auto : 
function () {
                    
//TODO
                }
            }
            
return init;
        }();
        
/* init */
        
new slider();

 

至于为什么会推荐这种构造函数/原型 的混合方式来构建,可以参考之前的“我所了解的类构造方式”以及“动态原型”扩展的文章。另外还有种抽象构造类的方式也是我挺喜欢的
    var Class = {
        create: 
function () {
            
return function () {
                
return this.init.apply(this, arguments);
            }
        }
    };
    
    
var slider = Class.create();
    slider.prototype 
= {
        init: 
function () {
            
//TODO
        }
    }
    
/* init */
    
new slider();

 

好了,文已至此,也差不多了,前端作为UED里的一个职位,干的却是编码的工作,注定了它的特殊性,所以我们不得不说,正因为我们是前端,所以我们更需要“优雅”!!

ps:以上全是个人观点,不一定适用于各位同仁,请谨慎取舍...