在最近的一个 CSS 见面会上,我向与会者提问,“有人会在日常的工作流中使用 Sass 吗?”回答结果压倒性的表示肯定——保守谨慎地使用 Sass 已经成为过去式。Sass 正迅速成长为编写 CSS 的标准方式。

这真是难得的好消息!Sass 包含了诸多 CSS 规范未定义的特性,比如变量、控制指令、混合宏等。这些特性赋予了开发者强有力的工具,以应对复杂和持续更迭的样式表。Sass 的灵活性和健壮性,足以实现开发者任何天马行空的创意思维。

令人遗憾的是,虽然 Sass 的使用规模在持续扩大,但生成的 CSS 质量却在不断降低。合理的解释是:Sass 在开发者和样式表之间引入了一层抽象层。过去,我们曾经反复修正 web 标准,现在,我们需要一种方式将其融合入新的开发环境中。目前的问题是,Sass 规范扩展了太多东西,以至于需要持续修正以应对任何 web 标准的改变。实际上,我们需要一种指导思想——适用且独立于 Sass,指导开发者的编程方式。

为了更深入的探讨问题,我们有必要再回顾一次当下面临的困境。

症结

对于 Sass 的诸多特性,最常见的滥用方式就是——选择器的过度嵌套。这里请不要误解我的意思:嵌套选择器确实是非常有用的编程方式,它组织起了局部的代码,使之更易于管理;但是,过度嵌套就是一种灾难了。

举例来说,有时候嵌套会生成冗长的选择器列表,而这会严重影响渲染性能:

body #main .content .left-col .box .heading { font-size: 2em; }

使用如此详细的选择器弊大于利。当未来需要重写级联样式时,开发者就必须使用权值更高的选择器列表。甚至,最终需要借助 !important 的权值 —— 这种写法,上帝都看不下去,严重影响后续的可维护性。

body #main .content .left-col .box .heading  [0,1,4,1]
.box .heading [0,0,2,0]

最后,由于选择器依赖于 HTML 文档结构,那么如此冗长的嵌套就会降低样式的可维护性和可移植性。未来,如果我们想要给一个父级不是 leftcol 的 box,同样设置 heading 样式,我们就需要再写一条样式来实现(合理的开发方案应该是复用这条样式的)。

生成的 CSS 代码质量低下,最大的原因就应该归罪于过度嵌套。其他存在的问题,还包括代码的重复和耦合——有必要再次指出,这些都是使用 Sass 的不合理方式所引起的。那么,我们应该如何更缜密的使用 Sass 呢?

对策

一种方式是创建一些规则,限制和掌控那些存在风险的特性。比如,Mario Ricalde 使用 Inception-inspired 准则限制嵌套:“嵌套永远不要超过四层”。

这些规则往往非常适用于新手,为他们制定了明确的使用权限。但是,一方面这种公认的规则少之又少,另一方面 Sass 规范又在持续扩展。对于每一次新版本发布,都会带来诸多新的特性,并且使用起来会束缚开发者的创造力。单独的几条规则是无法掀起革命性影响的。

我们应该高度重视开发过程中的最佳实践,而不是去整理收集零散的规则。这种最佳实践的核心内容如下所示:

  • 编程准则,或者是特定编程语言的编程规范,包含建议的编程风格、最佳实践和方法。
  • 框架,或者是标准化编程的文件/文件夹结构,可以用作网站开发的基础。
  • 样式指南,或是在线文档,详述了开发网站和应用的所有元素和代码模块。

每个方面各有所长:

  • 在一个大型代码库中,编程准则有利于统一团队的编程风格,改善整体代码的可维护性。更多信息请参考 Chris Coyier 的 Sass guidelines
  • 框架兼具实用性和灵活性,同时也将开发过程中的决策压力降到了最低。正如所有的前端开发者所熟知的那样,即使是决定 CSS 的命名方式都会让人感到压力重重。
  • 样式指南将编程语言的语法规则和实际生成的效果联系在了一起,指南中使用详细的示例解释了系统中每一个组件的特点。

每个方面也各有难点:

  • 编程准则往往是冗杂繁重的,必须持续更新保持准确性。对于新手和缺乏经验的开发者,都存在不小的学习难度。
  • 框架往往会让整体代码变得有些臃肿,其灵活性是需要付出一定代价的。
  • 样式指南在不同的开发主题中是迥然不同的,往往为了适应特定的上下文环境需要付出一定的修正时间和精力。

不幸的是,虽然这些方法指出了一些使用 Sass 的技巧,但没有解决我们的实际问题。我们使用 Sass 的难点并不是源于语法规范本身,而是我们使用 Sass 的方式。归根结底,Sass 只是一个 CSS 预处理器;所以我们的问题实际上是,处理过程。

那么,我们又该如何处理?

再看症结

每一份工作都或多或少受到人为因素的影响,当我们将工作投入实际生产之后,问题就会被放大出来。我们需要认清,Sass 帮助了我们构建 CSS,但这并不是我们奋斗的终点。实际上,如果 CSS 中引入了变量,那么大多数的事情都要改写,而 Sass 和 CSS 规范也将逐渐融合为一体——这也意味着 Sass 的消亡。

我们实际上所需要的解决方案,并不应该针对代码本身,而应该针对作为开发者的我们。该解决方案需要包含技术准则,以辅助开发者使用 Sass,同时还要深思熟虑放眼未来。所以,我们需要一份了包含了相关意图和目标的公开声明,换言之,一份宣言。

Sass 宣言

当我学会 Sass 之后,我就建立了一些个人准则。时间匆匆,它们形成了宣言的雏形,常常被我用来评估新的特性和技巧——以判断它们是否适用于我的工作流程。当 Sass 羽翼丰满频频被用于我的团队时,这些信条就变得举足轻重了。

我的 Sass 宣言包含了六个信条,或者说是条款,详列如下:

  1. 输出胜过输入
  2. 可用胜过依赖
  3. 易懂胜过简洁
  4. 稳固胜过反复
  5. 功能胜过表现
  6. 一致胜过新奇

虽然每个信条都可能逐步发展为规范建议的条款,但固定不变的运用它们显然是没有意义的。接下来,让我们进一步解析每个信条背后的深层次思考。

1. 输出胜过输入

最终生成的 CSS 的质量和完整性,显然要比预编前的代码更重要。

该信条是其他信条的根本。有必要认清,Sass 只是整个流程的一个处理过程,它转换为 CSS 文件,还要经过浏览器的解析。这可不是说 CSS 需要优雅的格式和极高的可读性(这往往不是关注的重点,尤其是在开发者遵循最佳实践使用压缩的 CSS),但你必须时刻警惕最终的渲染性能。

当你使用了 Sass 规范最新的特性,有必要扪心自问,“这种方式输出的 CSS 是怎样的?” 如果疑惑不清,那么就要看一看源码——可以查看生成的 CSS 代码。深度理解 Sass 和 CSS 相互之间的关系,将有助于你发现潜在的性能瓶颈,并拿出相应的对策优化 Sass 结构。

举例来说,使用 @extend 指令继承选择器中的每个样式。Sass 代码如下:

.box {
background: #eee;
border: 1px solid #ccc; .heading {
font-size: 2em;
}
} .box2 {
@extend .box;
padding: 10px;
}

编译结果:

.box, .box2 {
background: #eee;
border: 1px solid #ccc;
}
.box .heading, .box2 .heading {
font-size: 2em;
} .box2 {
padding: 10px;
}

如你所见,.box2 不仅仅继承了 .box 的样式,还像 .box 一样成为了 .heading 的父级选择器。虽然这只是一个小例子,但如果你不理解 Sass 的生成方式,那么就会生成意想不到的结果。

2. 可用胜过依赖

项目应该具有可移植性,远离对外部的过度依赖。

只要你使用 Sass,那么你就需要引入相关的依赖。最简单的例子就是 Sass 的安装和编译依赖于 Ruby 和 Sass gem。需要牢记的是,使用的依赖越多,做出的妥协越多,就会逐渐丧失了使用 Sass 的带来的收益:团队协作不因噎废食。

举例来说,使用 Sass gem 可以安装很多额外的软件包——它们往往可以完成大量的工作。最常用的框架就要属 Compass 了,此外你还可以安装编写栅格的 gems,以及 Bootstrap 之类的框架。这些 gems 对完成大量的细碎工作非常有用,比如创建一个调色板,或是添加阴影等。

这些 gems 内建了一系列的混合宏,可以被开发者引用到自己的 Sass 文件中。不同于开发者在项目内编写的混合宏,gem 中的混合宏存放在安装目录。gems 在外部被引用的方式,非常类似 Sass 核心功能的使用方式,而且只能通过 @include 指令调用。

这就是 gem 棘手的地方。现在我们假设一种场景,有一支团队正致力于某个项目:团队成员之一,John,决定安装一个 gem 来辅助管理栅格。他安装后就将 gem 引入了项目,并在开发者中使用它。与此同时,另一个团队成员,Mary,下载了项目的最新版本,想要更改一下网站的字体。她下载之后尝试进行编译,却突然编译中断抛出了错误。由于 John 在项目中引入了额外的依赖,而 Mary 的文件中缺少相关的依赖,导致她必须调试错误并下载相关的依赖。

在大型团队中,这种问题屡见不鲜。如果再算上错综复杂的版本和 gem 的内部依赖,处理起来令人崩溃。对于 Ruby 项目,维护统一的开发环境,其最佳实践就是追踪和安装确实需要的 gems 和版本。但最简单的方法,还是尽量避免使用额外的 gems。

免责声明:我最近正在实用 Compass 框架,而且也感觉利大于弊。不过,由于 Sass 规范的建议,我已经开始考虑适时和 Compass 说拜拜了。

3. 易懂胜过简洁

编写 Sass,代码结构要清晰易懂,方便后续开发者的维护工作。

Sass 可以输出严格压缩的 CSS,所以无需手动优化编译前的代码。不同于 CSS 的注释,Sass 中的行内注释并不会出现在最终的 CSS 中。

这对于书写混合宏的文档非常有用,如下所示的注释不会被输出到最终的 CSS 中:

// Force overly long spans of text to truncate, e.g.:
// @include truncate(100%);
// Where $truncation-boundary is a united measurement. @mixin truncate($truncation-boundary){
max-width:$truncation-boundary;
white-space:nowrap;
overflow:hidden;
text-overflow:ellipsis;
}

无论怎样,一定要考虑 Sass 中的哪些部分需要导入到最终的 CSS 文件中。

4. 稳固胜过反复

不要重复。认清并合理编写复用模式。

在开始任意项目前,明确且尝试定义既定设计中所有不同的模块,是非常明智的做法。这也是编写面向对象的 CSS 的第一步。当然,有一些模式可能无法预测,直到编写了三四遍重复的代码之后才会意识到。

尽快抽象出这些模式,并运用到你的 Sass 中去。

将复用的值设为变量:

$base-font-size: 16px;
$gutter: 1.5em;

将复用的视觉样式设为占位符:

%dotted-border { border: 1px dotted #eee; }

为需要传参的模式编写混合宏:

//transparency for image features
@mixin transparent($color, $alpha) {
$rgba: rgba($color, $alpha);
$ie-hex-str: ie-hex-str($rgba);
background-color: transparent;
background-color: $rgba;
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#{$ie-hex-str},endColorstr=#{$ie-hex-str});
zoom: 1;
}

如果拟采用了这一方法,就会发现,Sass 文件和生成的 CSS 文件,都会更小且易于管理。

5. 功能胜过表现

命名约定,要专注于 HTML 的功能,而不是视觉表现。

使用 Sass 的变量,可以非常简单的主题化网站。然而,我常常会看到这样的代码:

$red-color: #cc3939; //red
$green-color: #2f6b49; //green

将变量与表现效果联系在一起,只有一时的成效。如果设计效果改变了,红色被替换为了其他颜色,就会混淆变量和值的关系。

$red-color: #b32293; //magenta
$green-color: #2f6b49; //green

更好的方式是基于特定的功能来命名这些颜色变量:

$primary-color: #b32293; //magenta
$secondary-color: #2f6b49; //green

Presentational classes with placeholder selectors

当我们不能将视觉样式和功能性类名联系起来的时候,又该如何做呢?假设一个站点中有两个 box,分别是 “Contact” 和 “References”。设计师将两个 box 都设置为了蓝色的边框和背景。我们想最大程度的保持灵活性,但又要尽量缩减冗余的代码。

我们可以在 HTML 中串联这些类名,但需要严格限制:

<div class=“contact-box blue-box”>
<div class=“references-box blue-box”>

牢记,我们要专注于功能而不是表现效果。幸运的是,使用 Sass 的 @extend 指令和占位符,将会使这种方式变得非常简单。

%blue-box {
background: #bac3d6;
border: 1px solid #3f2adf;
} .contact-box {
@extend %blue-box;

}
.references-box {
@extend %blue-box;

}

生成结果如下所示,其中并没有 %blue-box 的代码,只有确实需要的代码被实现了。

.contact-box,
.references-box {
background: #bac3d6;
border: 1px solid #3f2adf;
}

这种方式切断了与 HTML 中描述性类名的联系,但在 Sass 文件中仍然可以被理解。为通用样式设计功能性类名,比如 base-box,将会更有意义。

6. 一致胜过新奇

避免向编译后的 CSS 引入不必要的改动。

如果你希望将 Sass 引入自己的工作流中,且没有新项目的话,你可能会疑问,如何在已有代码库中使用 Sass。Sass 完全支持 CSS,所以最基本的转变就像是将扩展名从 .css变为 .scss 一样简单。

一旦完成了这种转换,你也许会尝试深入理解代码,或者重构整个文件,化整为零,将选择器嵌套,引入变量和混合宏。对于接替后续开发的人来说,前面的转变一定会带来诸多问题。虽然重构不会影响网站的显式效果,但会生成完全不同的 CSS 文件,而且任何改动的影响都不是孤立的。

转换为 Sass 工作流的最佳方法是按需更新文件。如果你需要改变导航的样式,可以在使用前将其分离为部件。这有助于保护现有的级联样式,并且后续的改动也会非常容易。

展望

最近,我喜欢思考使用 Sass 的难点。这些都是我们使用新的工作方式,所要面临和亟待解决的症结。随着对 Sass 理解的深入,我们最终将会找到合理的答案。

这就是我的愿景,相信这份宣言将有助于调整我们的姿态,继续向前:使用它,改变它,甚至书写自己的宣言。要以专注于书写代码的方式为始,而不是书写的内容。

致谢

http://www.jianshu.com/p/aa1be52204a7

本文翻译自 ALISTAPART 的 A Vision for Our Sass,非常感谢 Felicity Evans 的杰出工作。

Sass 愿景的更多相关文章

  1. oneM2M标准发展神速 实现万物联网的愿景

    http://m2m.iot-online.com/news/2013102224849.html oneM2M则将负责解决独立于接取网路中通用的M2M服务层的关键需求:使其可更方便地嵌入于各种软硬体 ...

  2. .NET平台技术体系梳理+初学者学习路径推荐+我们的愿景与目标

    文章出自:http://www.cnblogs.com/ice-river/p/3475041.html 一 .NET平台技术体系梳理 .NET平台应用领域众多(桌面开发,web开发,移动开发),不断 ...

  3. 在线制作GIF图片项目愿景与范围

    在线制作GIF图片项目愿景与范围 a. 业务需求 a.1 背景 在当今社会中,随着聊天软件和web网站的普及,原创动画制作越来越吸引人们的眼球,一个好的动态图片,可能就会为你的网站或本人赢得更多人的认 ...

  4. Java九阳真经论述及愿景

    Java九阳真经论述及愿景 “他强由他强,清风拂山冈,他横由他横,明月照大江.” <倚天屠龙记>中张无忌被玄冥二老的玄冥神掌打伤后,体寒难耐,到处求解决之法.一次被韦蝠王打下山谷后,偶遇一 ...

  5. Spark新愿景:让深度学习变得更加易于使用——见https://github.com/yahoo/TensorFlowOnSpark

    Spark新愿景:让深度学习变得更加易于使用   转自:https://www.jianshu.com/p/07e8200b7cea 前言 Spark成功的实现了当年的承诺,让数据处理变得更容易,现在 ...

  6. .NET平台系列10 .NET统一平台愿景

    系列目录     [已更新最新开发文章,点击查看详细] 2019年,微软分享了[统一的.NET堆栈和生态系统的愿景].给开发者带来的价值是,将能够使用一组API,语言和工具来针对广泛的应用程序类型,包 ...

  7. Maven的作用、用途、内涵、愿景

    maven被许多人认为是一个构建工具.许多人最初是从熟悉ant而转到maven的,因此很自然地这样认为maven是一个构建工具.但是maven并不仅仅是一个构建工具,也不是ant的一个替代工具.mav ...

  8. DOTS原则和愿景

    Unity Data Oriented Tech Stack基于一系列原则.这些原则为我们正在努力实现的目标提供了良好的背景.一些原则清楚地反映在代码中.其他则只是我们为自己设定的目标. 默认情况下的 ...

  9. 现状、趋势如何?——《2019 年度 SaaS 行业【企业愿景】展望 · 总结篇》

    SaaS 行业产业地图和行业规模 看完SaaS的概念介绍,聪明的小伙伴们应该都理解了SaaS到底是个什么东西,但TOB的应用一般会离生活比较远,这里直接上产业地图,让大家对常见的SaaS产品有一个直观 ...

随机推荐

  1. html5--1.3 元素的概念与3个常用标签

    html5--1.3 元素的概念与3个常用标签 学习要点 1.元素的概念 2.3个常用的标签 HTML 元素指的是从开始标签到结束标签的所有代码. 开始标签 元素内容 结束标签 <h1> ...

  2. 前端多媒体(2)—— xhr异步接收处理二进制数据

    有时我们需要把远程的视频.图片数据异步下载下来,然后在js里进行特殊处理.比如把VR的图片特殊处理,把不同封装格式的视频做一次 转封装 处理等等,这类操作都要先获取二进制数据,然后特殊处理. 这个时候 ...

  3. dynamic 作为参数传入另一个程序集,获取值

    dynamicOBJ.GetType().GetProperty("key").GetValue(dynamicOBJ, null)

  4. 如何通过giihub下载软件

    因为不懂英文, 所以找到了网站也不知道要怎么下载? 需求: 假设要下载的的一个jar包,  mybatis-generator 1.  利用搜索引擎 2. 点进去, 看到那个release  (rel ...

  5. Mesos以及Marathon安装总结

    安装了将近一周的环境了,终于把Mesos以及Marathon给安装上了,我指的离线安装. 策略1: 严格的按照官网的流程: http://mesos.apache.org/gettingstarted ...

  6. BZOJ1382:[Baltic2001]Mars Maps

    浅谈树状数组与线段树:https://www.cnblogs.com/AKMer/p/9946944.html 题目传送门:https://www.lydsy.com/JudgeOnline/prob ...

  7. zk 09之:Curator之二:Path Cache监控zookeeper的node和path的状态

    在实际应用开发中,当某个ZNode发生变化后我们需要得到通知并做一些后续处理,Curator Recipes提供了Path Cache 来帮助我们轻松实现watch ZNode. Path Cache ...

  8. session和cookie(2)

    会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话.常用的会话跟踪技术是Cookie与Session.Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端 ...

  9. [allmake] -- 交叉编译原来如此简单

    原创作品,允许转载,转载时请务必以超链接形式标明文章原始出处.作者信息和本声明.否则将追究法律责任.:http://www.cnblogs.com/johnd/p/5060530.html 作者:Jo ...

  10. SQLServer 微软团队开源项目 (web 版?)

    http://www.codeplex.com/site/users/view/SQLTeamAdmin