CSS预处理工具Stylus

CSS(层叠样式表,Cascading Style Sheet)是前端开发中最基本也是最必须的三个(HTML,CSS,JavaScript)技能之一。然而在传统的前端开发中,CSS的开发过于静态化,存在着一些制约开发效率的问题,例如,语法不够强大,无法嵌套书写,导致模块化开发中多次重复书写相同的选择器;没有变量和合理的样式复用机制,使得逻辑上相关的属性值必须以字面量的形式重复输出,导致代码冗余、难以维护,等等。

1、背景

为了解决上述问题,提高CSS开发效率,近十年来,陆续有多种CSS预处理器被提出。那么,什么是CSS预处理器呢?CSS预处理器定义了一种专门针对web页面样式设计的编程语言,其基本思想是,用一种专门的编程语言,为CSS增加一些编程的特性,并将CSS文件作为目标生成文件。CSS预处理器为CSS增加了一些编程的特性,例如可以使用变量、简单的逻辑程序、函数等等,且无需考虑浏览器的兼容性问题,让CSS的编写更加简洁、适应性更强、可读性更佳。CSS 预处理器提供了CSS 缺失的样式层复用机制,减少了冗余代码,提高了样式代码的可维护性。目前,CSS预处理器技术已经比较成熟,而且涌现出多种不同的CSS预处理器语言,例如:Sass(SCSS)、LESS、Stylus、 Turbine、Swithch CSS、CSS Cacheer、DT CSS等。

在众多的CSS预处理器语言中, Sass、LESS和Stylus被使用的最多,也最优秀。这三款CSS预处理器语言具有一些相同的特性,例如:变量、混入、嵌套、函数等,根据以往使用者的经验,对三者的简单总结如下:

  1. LESS

LESS,2009年出现,使用CSS的语法,让大部分开发者和设计师更容易上手,其缺点是比起Sass和Stylus,编程功能不够强大。

  1. Sass

Sass,2007年诞生,是最早的CSS预处理器,发展成熟,但依赖于ruby环境,所以装Sass之前要先安装和学习ruby,增加开发、维护人员的学习成本。

  1. Stylus

Stylus,2010年产生,来自Node.js社区,功能上更为强壮,和js联系更加紧密,可以创建健壮的、动态的、富有表现力的CSS。

综合考虑三者的功能、学习成本,以及企业环境,如果要使用CSS预处理器,Stylus似乎是最合适的。

2、Stylus介绍及特点

Stylus 是一个基于Node.js的CSS的预处理框架,诞生于2010年,比较年轻,可以说是一种新型语言,其本质上做的事情与 Sass/LESS 等类似, 可以以近似脚本的方式去写CSS代码,创建健壮的、动态的、富有表现力的CSS,默认使用 .styl 的作为文件扩展名,支持多样性的CSS语法。Stylus比LESS更强大,而且基于nodejs比Sass更符合我们的思路。

Stylus的特点如下

  • 基于js

Node.js是一个Javascript运行环境(runtime),是对Google V8引擎进行了封装,V8引擎执行Javascript的速度非常快,性能非常好。对于不了解Node.js的开发人员,不会增加太多学习成本。Stylus基于Node.js,换而言之,就是借助JavaScript让CSS更富有表现力,更动态,更健壮!而且还有专门的JavaScript API。

  • 支持Ruby之类框架

虽然Stylus基于Node.js,但是依然支持Ruby之类框架,还有FireBug插件FireStylus, sublimetext插件,便于开发、调试。

  • 功能强大,使用灵活,支持多样性的CSS语法

Stylus的功能比LESS强大,不逊于Sass。在用法上,支持传统的CSS,而且相对于传统的用法,更加简洁、灵活,像省掉花括号、冒号,分号,甚至使用混合的CSS编程,Stylus都可以接受。

3、使用Stylus的优缺点

【优点】

  • 解决样式覆写的问题,尤其是mixin式复用

使用纯CSS,我们可以抽象出一些常用的布局CSS属性组合,通过CSS的类组合来达成常见的mixin式复用,然而这种方案存在一些问题,例如,当页面重构时,需要频繁修改class name,这个问题在后端人员掌握着视图层的时候格外突出,前后端耗费很多沟通成本;在约束上下文的时候非常无力,比如“只有在ul下面的img.db允许是display:block”的规则,写成“ul img.db { display: block; }”就完全跑偏了,它违背了创建这个.db类时的本意,造成了代码的可读性和可维护性下降。如果你要改动规则,需要同时修改HTML和CSS,也可能造成新的样式问题。

而通过Stylus可以建立一种新的代码风格,只允许CSS Class代表UI模块的抽象,这样一来,改动样式时不至于通知后端改模板,然后在CSS Class内部实现mixin。而这正是CSS的短板,CSS体系内的用法只有复制粘贴。

  • 可缓解多浏览器兼容造成的冗余

进入CSS3的时代,旧式CSS hack如filter,新式兼容前缀如-webkit-等,都是冗余,修改的时候也需要修改多处,不容易维护。在Stylus里面,写个函数就能解决,多次复用也不需要看到如此之多的hack。

  • 提高效率,节约成本.

用Stylus开发CSS可以提高效率,它类似于一种CSS的方言,可以用更精简的语法表达更多的意思。比如,Stylus中可以使用变量,比如和 UED 同学订好各种样式的规范,做好变量后开发中直接使用,避免页面中的各种杂乱样式。当样式需求有变动时,也可以重新给变量赋值,一下改掉相关样式,不用再一点一点的改。

  • 使CSS开发更加灵活

Stylus可以使用变量、条件、循环,兼容传统的CSS样式,等等,可以让CSS的开发和修改更加灵活。

【缺点】

  • 开发过程增加步骤

CSS的好处在于简便、随时随地被使用和调试,使用Stylus,增加了预编译CSS的步骤,让我们开发工作流中多了一个环节,调试也多了个步骤。

  • 增加学习成本。

虽然Stylus简单易学,可以兼容传统CSS,但是当开发和维护团队都从CSS过渡到Stylus时,还是需要一点学习成本的,而且初学者使用起来,不一定能明显提高效率。

二、  使用Stylus的方便之处

1、基本语法

Stylus的文件扩展名是“.styl”,语法规则使用缩进控制来代替花括号,使用逗号或换行为多个选择器同时定义属性,同时Stylus也接受不带大括号、分号、冒号的语法,也接受标准的CSS语法,使用起来非常灵活,如下所示:

stylus1

2、变量

变量允许我们单独定义一系列通用的样式,然后在需要的时候去调用它。Stylus中支持变量,可以减少代码冗余,提高灵活度。

Stylus样式中,声明变量没有任何限定,可以使用“$”符号开始,结尾的分号可有可无,但变量名和变量值之间的等号是必须的。变量命名需要注意的是,如果使用“@”符号开头来声明变量,Stylus会进行编译,但其对应的值并不会赋值给变量。换句话说,在 Stylus中不要使用“@”符号开头声明变量。

Stylus的变量和其他程序语言一样,可以实现值的复用,同样,它也存在生命周期,也就是Scope(变量范围,开发人员习惯称之为作用域),简单点讲就是局部变量和全局变量的概念,查找变量的顺序是先在局部定义中找,如果找不到,则查找上级定义,直至全局,也就是一种向上冒泡查找的过程。Stylus中我们可以指定表达式为变量,变量甚至可以组成一个表达式列表。

3、运算

Stylus具有运算的特性,简单的讲,就是对数值型的Value(如:数字、颜色、变量等)进行加减乘除等运算。Stylus的运算是三款预处理器(LESS、Sass、Stylus)语言中最强大的一款,它拥有其他程序语言一样的运算功能。这样的特性在CSS样式中是想都不敢想的,但在Stylus中,对样式做一些运算一点问题都没有。

4、逻辑控制

说到编程,对于编程基本控制流,大家并不会感到陌生,除了循环就是条件了。条件提供了语言的可控性,否则就是纯粹的静态语言。在 Stylus 中,提供了 if、else if、else、unless、for…in 来实现类似功能,语法简洁灵活,如下示例:

stylus2

Stylus除了这种简单的条件语句应用之外,还支持后缀条件语句。这就意味着可以把if和unless(unless条件,其基本上与if相反,本质上是“(!(expr))”)当作操作符,当右边表达式为真时,执行左边的操作对象。

在Stylus中,循环是通过for/in表达式来进行的,这对一些类似样式的书写,是非常方便的。

5、嵌套

Stylus中的嵌套指的是在一个选择器中嵌套另一个选择器来实现继承,从而减少代码量,使代码看起来更加清晰,并且增加了代码的可读性。比如说,我们在CSS中,多个元素有一个相同的父元素,那么写样式会变得很乏味,我们需要一遍一遍的在每个元素前写这个父元素,除非给特定的元素添加类名“class”或者ID。相反,使用Stylus的嵌套特性,我们可以在父元素的大括号内写这些元素。同时可以使用“&”符号来引用父选择器。如下所示:

stylus3

6、混合(混入、混写,Mixins)

混合(mixins)应该说是CSS预处理器最精髓的功能之一了。它提供了 CSS 缺失的最关键的东西:样式层面的抽象。它是CSS预处理器中语言中最强大的特性,简单点来说,Mixins可以将一部分样式抽出,作为单独定义的模块,被很多选择器重复使用。

在的CSS书写中,经常会遇到某段CSS样式需要被用于多个元素中,这样就需要重复的写多次。而在CSS预处理器语言中,我们可以为这些公用的CSS样式 定义一个Mixin,然后在需要使用这些样式的地方,直接调用定义好的Mixin。这是一个非常有用的特性,Mixin被当作一个公认的选择器,还可以在Mixin中定义变量或者默认参数。也就是说,混合可以将一个已定义好的classA轻松引入到classB中,从而简单的实现classB继承classA中的所有属性。Minxin还可以单参数,可以带参数地调用minxin,就像使用函数一样。

Stylus中的混合可以不使用任何符号,就是直接声明Mixins名,然后在定义参数、参数默认值等。如下所示:

stylus4

上面的Stylus代码定义了border-radius(n)方法,作为一个mixin(作为状态调用,而非表达式)调用,当border-radius()在选择器中被调用时,其属性会被扩展并复制在该选择器中,例如“form input[type=button]”“form input[type=text]”,而且参数是参数的圆括号,可以省去。

7、函数

Stylus自带了诸如色彩处理、类型判断、数值计算等内置函数,目前版本的数量在 80 个左右。

除了内置函数,stulys提供了强大的内置的语言函数定义,其定义与混入(mixins)一致,却可以返回值,如下:

stylus5

Stylus调用函数为直接指定参数名的方式传入参数,这样做的好处是,如果参数列表比较长,Stylus 可以直接为列表后面的参数赋值,而不需要一路将之前的参数填上null或默认值。Stylus 将这个特性称为【Named parameters】,在 Stylus 中,这些都是隐含的,最后一个表达式的值会作为返回值,可以返回多个返回值。

【函数与mixin的区别】

那么,这种写法和 mixin 有什么区别呢?当把函数作为 mixin 调用时,如果其中有 prop: value 这样格式的内容,就会被当做样式规则输出,mixin没有返回值。Stylus 中大量的内容都是根据调用时的 context 去隐式推断该使用什么逻辑进行输出,而非 Less 和 Sass 那样使用关键字去显式地进行区分。

8、继承

在传统的CSS中,在多个元素应用相同的样式时,通常在CSS中都是这样写:stylus6

这种写法,可以实现部分代码重用, 但是,当我们需要给某些元素单独添加另外的样式时,就需要把相应选择器单独出来写样式,如此一来,我们维护样式就相当麻烦。为了应对该问题,Stylus提供了继承机制,可以从一个选择器继承另一个选择器下的所有样式。

Stylus中,在继承另时需要使用“@extend”开始,后面紧跟被继承的选择器,如下代码:

 

stylus7

讲到这里,也许大家会觉得,那跟上面讲到的混入有点类似啊,混入也可以实现代码的重用,那我用混入,不用继承,还不是一样?混入很好用,可也有问题:如果多个地方都混入同样的代码,会造成输出代码的多次重复,这个时候继承就派上用场了。

9、导入

在CSS中,使用@import来导入样式,这种做法会增加http的请求。而Stylus中的导入(@import)规则和CSS的有所不同,当导入.styl文件时,它只是在语义上导入不同的文件,最终结果是生成一个CSS文件。但是,如果是通过“@import”导入“file.css”样式文件,那么效果跟普通CSS导入样式文件一样。

@import工作原理为:遍历目录队列,并检查任意目录中是否有该文件(类似node的require.paths)。该队列默认为单一路径,从filename选项的dirname衍生而来。 因此,如果你的文件名是/tmp/testing/stylus/main.styl,导入将显现为/tmp/testing/stylus/。@import也支持索引形式。这意味着当你@import blueprint, 则会理解成blueprint.styl或blueprint/index.styl. 对于库而言,这很有用,既可以展示所有特征与功能,同时又能导入特征子集。

Stylus中导入文件需要注意的是:导入文件中定义了变量、混合等信息也将会被引入到主样式文件中,因此需要避免它们的相互冲突。

10、补充

【插值】

Stylus Stylus支持通过使用“{ }”字符包围表达式来插入值,其会变成标识符的一部分。例如,-webkit-{‘border’ + ‘-radius’}等同于-webkit-border-radius。插值也可以在选择器上起作用。例如,我们可以指定表格前3行的高度,如下:

stylus8

【关键字参数】

Stylus支持关键字参数,允许你根据相关参数名引用参数,但是,我们可以在列表中的任何地方放置关键字参数,其余不键入参数将适用于尚未得到满足的参数。

【CSS字面量】

不管什么原因,如果遇到Stylus搞不定的特殊需求,你可以使用@css使其作为CSS字面量解决之。

【字符转码】

Stylus可以字符转码。这可以让字符变成标识符,或是渲染成字面量。

【错误报告】

Stylus内置梦幻般的错误报告,针对语法、解析以及计算错误,完整的堆栈跟踪,行号和文件名。

三、  实例与总结

上面介绍了Stylus的特点、用法,我们来对Stylus进行一个实例的应用。

1、Stylus应用实例

下面的CSS代码,是一个样式文件pageshame.css,因为文件较大,我们截取它比较有代表性的一段代码,如下:

stylus9

从这段CSS代码中,我们可以看到有大量的重复代码,例如, “.drillDataBackgroud_1”与“.drillDataBackgroud”下的类“.close”的样式代码完全一样,却要被书写两次;选择器因无法使用嵌套,导致选择器在子选择器前被一次又一次重写,例如“.popoverBody”;大量类似的样式,因无法使用变量和循环,也是需要一遍一遍书写大量重复的代码,例如“.popoverBody .popGongjilian > table > tbody > tr > td”;同一个选择器的样式,被分散在不同处,没有模块化开发的概念,等等。这些都是传统CSS代码无法避免的,因为它就是一个静态开发的过程。那如果使用Stylus来写,会是什么效果呢?我们来看下该CSS代码对应的Stylus代码:

stylus10

在上述的Stylus代码中,我们通过使用变量、混合(mixin)、选择器的嵌套、循环,使得代码精简不少。例如,定义混合close(),那么在“.drillDataBackgroud_1”与“.drillDataBackgroud”下的类“.close”就不用重复书写,只用在相关处调用close()就行;在“.popoverBody”的样式书写中,我们使用了选择器的嵌套,使代码更精简、紧凑,模块化开发比较明显;在“.popoverBody .popGongjilian > table > tbody > tr > td”的样式书写中,我们通过变量和for循环,使原本谢了7次的代码一次搞定。那么,我们再来看exp.styl文件编译生成的CSS代码exp.css,如下:

stylus11

可以看到,由exp.styl编译生成的exp.css代码,跟pageshame.css中的原始的CSS代码,效果是一模一样的。

2、总结

通过对Stylus的特点、优缺点、使用方法的介绍,再结合具体的应用实例,可以看到在CSS编程中,使用Stylus的确可以精简CSS代码、提高代码复用率,使用变量、循环,又可以大大提高代码灵活度,方便在样式需求变更时,做出统一的修改,等等。而且,Stylus简单易学,不会消耗过大的学习成本,更重要的是,Stylus兼容CSS的代码,即使在后期维护中,有人不懂Stylus,但是需要修改其中的CSS代码,也可以在Stylus文件中直接书写CSS代码,完全不会给不懂Stylus的同伴挖坑。因此,在以后的前端开发者,在书写CSS代码时,可以尝试使用Stylus,当熟练了Stylus,相信可以明显提高工作效率;而且在样式需求发生变更时,可以很快统一修改。

如果您需要了解更多内容,可以
加入QQ群:486207500、570982169
直接询问:010-68438880-8669

Spread the word. Share this post!

Meet The Author

Leave Comment