初遇 CSS,一见倾心

记得刚遇见css的时候,咱像是见了美人儿一样,简直是爱不释手啊,简简单单写几行算不上代码的代码,就能做出这么漂亮的东西,这也成了咱前端之路的最初动力。

然而,随着项目体量和页面复杂度的增加,咱很快就发现这美人儿非但不漂亮,而且缺胳膊少腿儿的:

  • 缺少模块系统。模块系统是软件工程化的基石,CSS 的这个缺陷对前端项目的工程化管理造成了很大阻力,导致开发大型应用时编码和维护都异常困难。js 一开始也没有模块系统,后来各种轮子频出,什么CMD,AMD,UMD全蹦出来了,乱哄哄的,好在 ES6 从语言层面引入了模块系统才终结了这种乱象,以后 js 的模块化终于可以统一了。css 你怎么不好好向你的好基友 js 学习呢,人家都有了,你还傻了吧唧的一点动静都没有。
  • 没有变量机制。这对控制多个地方会引用到的属性值很不方便。比如一个颜色值,页面好多地方用到,设计MM突然心血来潮把这个值换成了另一个颜色,咱们怎么办,ctrl+f 全局替换?万一换掉了不该换的,或者漏掉了几个怎么办。
  • 嵌套的层级写法非常蛋疼。经常会出现

    .page .content .left-side .profile .name{};
    .page .content .left-side .profile .age{};


    这种看起来很不爽,写起来更不爽的写法。这是程序员最不能忍受的——重复。
  • 复用困难。复用是软件工程的核心思想,css 不仅没提供模块系统,而且巧妙地避开了工程化的诸多实践。更加觉得 css 这门语言设计的跟闹着玩儿似的。
  • blabla.. 其它的都不是很严重啦。

CSS 没有模块系统,你当我 @import 是空气?

CSS 的 @import 规则是可以在一个 css 文件导入其他 css 文件,但这货需要执行到它时才能触发浏览器去下载它所 import 来的 css 文件,导致页面加载起来特别慢,还不如直接在 里写一大坨 标签的引入效率高,是名副其实的鸡肋功能,演员一般的存在,用你一次算我输。

有需求就会有市场,Sass(Syntactically Awesome Style Sheets) 应运而生。

老规矩,先来看看 Sass 官网的原话:

Sass 是世界上最成熟、最稳定、最强大的专业级 CSS 扩展语言!

这货还真是一点也不谦虚,“最成熟,最稳定,最强大”。

通过这几年项目中的实际运用,咱发现这句简短霸气的描述其实并没有丝毫的浮夸,Sass 的确厉害,完全可以 hold 住这三个“最”字,实至名归。

什么是预处理器

预处理器是在程序源文件被编译之前根据预处理指令对程序源文件进行处理的程序。说白了,预处理器只不过是一个文本替换工具而已。CSS 预处理器则是通过将有特殊语法和指令的源代码处理成浏览器可使用的 CSS 文件的程序。

是 Sass 还是 SCSS?

SCSS 是 Sass 3 引入的新语法,语法上完全兼容原生 CSS,功能上完全继承 Sass,可以说是 CSS 和 Sass 的完美融合。SCSS 之于 Sass 犹如 CSS3 之于 CSS,ES6 之于 JS。所以别纠结,其实是一个东西啦。

接下来就细数 Sass 带给咱们的四大实用特性,想必你一定已经使用过它们中的一个或几个。

一、嵌套写法

想想之前咱们是怎样写原生 css 的:

 .page .content .left-side .profile .name{
font-size: 2rem;
}
.page .content .left-side .profile .age{
color: red;
}

现在使用 scss 可以这样写:

.page{
.content{
.left-side{
.profile{
.name{
font-size: 2rem;
}
.age{
color: red;
}
}
}
}
}

编译后

.page .content .left-side .profile .name{font-size: 2rem;}
.page .content .left-side .profile .age{color: red;}

这种嵌套写法的好处是显然的:

  • 结构清晰简洁,并且可与 html 文档结构对应起来;
  • 减少了大量冗余重复的选择器编码;

二、属性值的复用——定义变量

变量一直是所有编程语言的标准配置。然而 CSS 就没有,再次证明 CSS 可能是一门假语言。好在 Sass 补上了这个短板。

没有变量之前的代码(这里以定义一系列表示成功风格的样式组件为例):

.success-bg{
background: #dff0d8;
}
.success-panel{
.panel-heading{
background: #dff0d8;
}
.panel-body{
border: 1px solid #dff0d8;
}
}

使用了变量后的代码:

$success-color: #dff0d8;

.success-bg{
background: $success-color;
}
.success-panel{
.panel-heading{
background: $success-color;
}
.panel-body{
border: 1px solid $success-color;
}
}

使用变量的好处是显而易见的:

  • 方便了多人协同作战,将频繁使用的属性值定义成变量放在单独的文件里,各个开发人员可方便引用而不必再关注这些小细节,有语义的变量名使用起来也要比单调的CSS值容易的多;
  • 极大地增强了代码的可维护性,便于局部和全局的样式风格统一控制;

三、文件级的复用——模块系统

模块化是软件工程的第一要务,是大型项目的必需建筑。软件工程的主要目标就是控制复杂度,这也正是模块化的目的。通过将一个大型复杂的工程拆解成一个个的小模块,使得校验、调试、测试都轻而易举。

CSS原生的 @import 提供了一个并没有卵用的假模块系统。Sass 对 @import 进行了拓展,实现了一个真正意义上甚至功能更强大的模块系统。Sass 选择对 @import 进行扩展,而不是新建一个指令,可见 import 这个关键字的语义之强,JavaScript 模块系统的关键字也是 import

没有模块系统之前:

<!-- index.html -->
<link rel="stylesheet" href="/your/site/common.css">
<link rel="stylesheet" href="/your/site/popup.css">
<link rel="stylesheet" href="/your/site/module_a.css">
<link rel="stylesheet" href="/your/site/site.css">

有了模块系统之后:

/* site.scss */
@import "common";
@import "popup";
@import "module_a";
<!-- index.html -->
<link rel="stylesheet" href="/your/site/site.css">

好处嘛自然不用多说了:

  • 增删改模块以后是 css 自己家的事,别麻烦别人,不用再去动 html 了吼;-
  • 模块系统使得项目并不会随着业务复杂度增加而变得更加复杂。增加功能时只需要横向扩展就行了,不会纵向延伸,从而能始终保证每个模块完整而简单;-

四、展示层的复用——混合指令

混合(mixin)特别类似于 JavaScript 中的函数,然而 Sass 提供了用于表达式计算的 @function 函数指令,这里就不好这么类比了。但其实就是这么个东西,调用的时候会返回一段样式。

比如下面一段存在重复样式的代码。

复用之前:

.description{
color: red;
border: 1px solid #e3e3e3;
border-radius: 2px;
}
.article{
color: #444;
border: 1px solid #e3e3e3;
border-radius: 2px;
}

稍作优化:

.description, .article{
border: 1px solid #e3e3e3;
border-radius: 2px;
}
.description{
color: red;
}
.article{
color: #444;
}

似乎不错,但是之后再新加类似样式时,

.description, .article, .style01, .style02{
border: 1px solid #e3e3e3;
border-radius: 2px;
}
.
.
.
.style01{}
.style02{}

每次都要改两个地方,很麻烦,很容易漏,尤其是将通用样式分离出来的话更容易出错。

再做优化:

.grey-border-radius{
border: 1px solid #e3e3e3;
border-radius: 2px;
}
.description{
color: red;
}
.article{
color: #444;
}

似乎好了一点,但这样的话,html 每个使用的标签都需要多加上一个 .grey-border-radius 类。很显然这是多余的。这种做法可以说是“凑合”。

使用 Sass 复用之后:

@mixin grey-border-radius{
border: 1px solid #e3e3e3;
border-radius: 2px;
}
.description{
@include grey-border-radius;
color: red;
}
.article{
@include grey-border-radius;
color: #444;
}

编译后的 css 输出:

.description {
border: 1px solid #e3e3e3;
border-radius: 2px;
color: red;
}
.article {
border: 1px solid #e3e3e3;
border-radius: 2px;
color: #444;
}

看到了吧,这种做法简直“完美”:

  • 抽离公共的样式片段,便于多处复用;
  • 将公共的样式片段放在单独的文件里,便于项目的多个文件复用;
  • 对 html 的使用没有任何要求,css 自己家的事自己关起门来解决,绝不麻烦别人;

其他不常用且慎用的强大特性

如果熟练合理地运用上面的四大特性,你已经是CSS代码工程化方面的砖家了,所写出来的代码必是清晰易维护的。Sass 提供了更多的功能,但对普通开发者来讲,上面的四点只要使用熟练,已经完全够用了,其他的可看可不看。下面提供的功能希望大家慎用,有的是出于性能考虑,有的则是从开发维护的角度考虑。尤其不要为了秀技术而去使用它们,过犹不及,事缓则圆,此为中庸之道。

# 语义层的复用——继承机制

继承是面向对象程序设计的三大特性之一,这也是为什么说它是语义层复用的原因。你可以说一个错误信息框继承了一个信息框,而不能说一个错误信息框继承了一个灰色圆角,虽然也是可以强行这么说,但难免有些别扭哈哈。

比如说下面定义一组信息框的样式,包括默认,成功和错误的样式。

使用继承之前:

.msg{
border: 1px solid #e3e3e3;
background: #dff0d8;
}
.msg-success{
color: #4cae4c;
}
.msg-error{
color: #d43f3a;
}

同样是上面说到的问题,编写 html 时每个使用的标签都需要多加上一个 .msg 类,很多余。

使用继承之后:

.msg{
border: 1px solid #e3e3e3;
background: #dff0d8;
}
.msg-success{
@extend .msg;
color: #4cae4c;
}
.msg-error{
@extend .msg;
color: #d43f3a;
}

编译后

.msg, .msg-success, .msg-error {
border: 1px solid #e3e3e3;
background: #dff0d8;
}
.msg-success {
color: #4cae4c;
}
.msg-error {
color: #d43f3a;
}

可以看出,上面的效果使用混合(mixin)也可以完成。但不同的是:继承拷贝的是选择器,而混合(mixin)拷贝的是样式片段。

使用混合(mixin)还是继承(extend)?

你肯定以为既然继承拷贝的是选择器,而混合拷贝的是大段的样式,那当然是优先选择继承了。然而恰恰相反,推荐做法是 尽可能使用混合(mixin),具体原因 戳这里

# 用于复杂计算的函数

这个功能主要用于值的计算,和 JavaScript 中的函数类似。

比如移动端开发时可以封装成一个函数用于把 px 转成 rem。

$baseFontSize: 20;
@function px2rem($val) {
@return $val/$baseFontSize + rem;
} .big-text{
font-size: px2rem(30);
}

编译后:

.big-text {
font-size: 1.5rem;
}

这样在拿到设计MM给的视觉稿之后就可以直接使用 px 进行测量使用了。

# 完善的控制流

控制流即程序语言中的 if/elseforwhile 等控制语句。Sass 同样提供了指令实现:

  • @if
  • @for
  • @each
  • @while

它们通常配合 @function 指令使用,然而功能虽强,却不常用到。毕竟样式表的功用主要是描述页面样式,而不是提供更多控制。因此在这里不展开研究,感性趣的 戳这里

小结

Sass 完美弥补了上面原生 CSS 暴露的几个短板,同时新语法 SCSS 使 CSS 开发者可以无缝过渡,是 CSS 预处理器中当之无愧的佼佼者。使用 Sass 容易编写出结构清晰,可复用,易维护的工程样式文件,这正是工程化的期望。这么好的东西,速速用起来。

本文主要参考了 Sass 中文网

前端CSS的工程化——掌握Sass这四大特性就够了的更多相关文章

  1. less 前端css利器 工程化、逻辑化 css 文件

    less LESS 将 CSS 赋予了动态语言的特性,如 变量, 继承,运算, 函数. 1. 浏览器方式 1.1 html <!DOCTYPE html> <html lang=&q ...

  2. 前端css框架SASS使用教程(转)

    一.什么是SASS SASS是一种CSS的开发工具,提供了许多便利的写法,大大节省了设计者的时间,使得CSS的开发,变得简单和可维护. 本文总结了SASS的主要用法.我的目标是,有了这篇文章,日常的一 ...

  3. 关于前端CSS预处理器Sass的小知识!

    前面的话   "CSS预处理器"(css preprocessor)的基本思想是,用一种专门的编程语言,进行网页样式设计,然后再编译成正常的CSS文件.SASS是一种CSS的开发工 ...

  4. CSS预编译器:Sass(入门),更快的前端开发

    SASs是由美国注册会计师协会(AICPA)下属审计准则委员会(ASB)发布,是为了便于注册会计师执行和落实一般公认审计准则(GAAS). Sass 扩展了 CSS3,增加了规则.变量.混入.选择器. ...

  5. 前端CSS(3)

    前端基础CSS(3)   一.文本属性和字体属性(常用的) 1.文本属性 text-align:left|right|center|justify(两端对齐,只适用于英文);   /*对齐方式*/ c ...

  6. 前端CSS编程之道-LESS

    由于前端css编写繁琐,最近开始学习LESS,用LESS编写文件.less文件可以直接编译成我们要的.css文件 学习Less 我下面是我练习时的截图,希望小伙伴也能动手自己写一下,而不是复制粘贴模式 ...

  7. 扯一扯前端css的整体架构设计:(2)base基础类的那些事儿

    周一下午在实验室写了第一篇博文,有几个人捧场,那咱就得接着下去啊.然后我觉得现在写的内容更多的偏向于谈一下我对于前端css架构的理解和前端经验的一个小总结,所以就把标题里原来的[项目总结]给删掉了.但 ...

  8. CSS预处理器 Less Sass,Scss 编译 Sourcemap调试

    sass.less和stylus的安装使用和入门实践     SASS用法指南    Sass Basics CSS预处理器 css preprocessor 预处理器即preprocessor,预处 ...

  9. 20190421-那些年使用过的CSS预处理器(CSS Preprocessor)之Sass and Less

    写在前面乱七八糟的前言: emmm,还是决定把Sass与Less单独出来写成一篇,可能会稍微好辣么一丢丢?TAT语法特性是真的香,通篇下来能吸收个10%自我感觉已经很nice了,毕竟渣渣的我有渣渣的自 ...

随机推荐

  1. .6-Vue源码之AST(2)

    上一节获取到了DOM树的字符串,准备进入compile阶段: // Line-9326 function compileToFunctions(template,options,vm) { // 获取 ...

  2. Rank of Tetris

    Rank of Tetris Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...

  3. 交换知识 VLAN VTP STP 单臂路由

    第1章 交换基础 1.1 园区网分层结构 层次 作用 出口层 广域网接入 出口策略 带宽控制 核心层 高速转发 服务器接入 路由选择 汇聚层 流量汇聚 链路冗余 设备冗余 路由选择 接入层 用户接入 ...

  4. Flex中宽度计算

    flex 有三个属性值,分别是 flex-grow, flex-shrink, flex-basis,默认值是 0 1 auto. 发现网上详细介绍他们的文章比较少, 今天就详细说说他们,先一个一个看 ...

  5. cookie在不同域名domain、path下的读取规则

    cookie 子域名可以读父域名中的cookie 如在 .ping.com域下注入cookie,则该子域下的网页如p1.ping.com.p2.ping.com 都能读取到cookie信息 path的 ...

  6. strict 严格模式

    严格模式可以让你更早的发现错误,因为那些容易让程序出错的地方会被找出来   打开严格模式:"use strict" 不支持的javascript引擎会忽略它,当作是一个未赋值字符串 ...

  7. curl模拟带验证码的登录

    首先说明,不是用php自动识别验证码,而是有验证码的情况下,让你通过curl 带着cookies去请求远程资源,从而通过合法的身份验证.主要用来抓取需要登录后才能访问的资源. 思路就是获取到验证码之后 ...

  8. IE6中 PNG 背景透明的最佳解决方案

    为什么要使用 PNG 图片? 简 单来说,使用 PNG 格式比起 GIF 来表现色彩更丰富,特别是表现渐变以及背景透明的渐变要比GIF格式出色很多.目前,最新的浏览器基本上都支持PNG格式.唯独有万恶 ...

  9. 百度地图Marker优化方案

    简介 在使用百度地图的时候,我们需要在地图上增加标注Marker来展示设置信息.随着用户需要不断增多,加载更多的Marker标注信息成为了一种奢望.然而通过自己技术的提升,归结出来了一下方案. 引入百 ...

  10. C#抓取和分析网页的类

    抓取和分析网页的类. 主要功能有: Ontology 1.提取网页的纯文本,去所有html标签和javascript代码 2.提取网页的链接,包括href和frame及iframe 3.提取网页的ti ...