[关闭]
@qinyun 2018-04-08T09:43:54.000000Z 字数 6639 阅读 620

现代的CSS

未分类


使用CSS预处理器获取新语法

到目前为止,我们已经将CSS用于基本样式和布局上,现在我们将从CSS预处理器开始介绍改善CSS语言本身工作体验的构建工具。

CSS预处理器允许你使用不同的语言编写样式,将其转换为浏览器可以理解的CSS,这在浏览器实现新功能速度非常缓慢的时候是极其重要的。第一个主要的CSS预处理器是2006年发布的Sass,它具有新型的简洁语法(缩进代替括号、没有分号等),并增加了CSS中缺少的高级功能,例如变量、辅助函数和计算。以下是使用带变量的Sass的示例:

  1. $dark-color: #4a4a4a
  2. $light-color: #f9f9f9
  3. $side-color: #eee
  4. body
  5. color: $dark-color
  6. header, footer
  7. background-color: $dark-color
  8. color: $light-color
  9. main
  10. background: $light-c olor
  11. nav, aside
  12. background: $side-color

请注意,如何使用$符号定义可重用变量,并消除括号和分号,使语法更清晰简洁。虽然Sass的语法简洁是一件好事,但当时变量是革命性的功能特性,因为它们为编写简洁且可维护的CSS开辟了新的可能性。

如果使用Sass,你需要安装Ruby,这是用于将Sass代码编译为常规CSS的编程语言。然后,你需要安装Sass gem,然后在命令行中运行将.sass文件转换为.css文件的命令,以下是一个示例:

  1. sass --watch index.sass index.css

这个命令会将一个名为index.sass常规CSS的文件中的Sass代码转换成一个名为index.css(在任何时候,--watch会提示它保存更改的内容,这很方便)。

这个过程称为构建步骤,这在2006年可是一个重大的难题。如果你能熟练使用Ruby这样的编程语言,那么这个过程将会非常简单。但当时许多前端开发者只使用不需任何此类工具的HTML和CSS,因此,对开发者来说,学习整个生态系统以获得由CSS预处理器提供的功能是一个很高的要求。

2009年,CSS的Less预处理器发布,它也是用Ruby编写的,并且提供了与Sass类似的功能。主要的区别在于语法,其语法的设计尽可能接近CSS,这意味着任何CSS代码都是有效的Less代码,下面是使用Less语法编写的示例:

  1. @dark-color: #4a4a4a;
  2. @light-color: #f9f9f9;
  3. @side-color: #eee;
  4. body {
  5. color: @dark-color;
  6. }
  7. header, footer {
  8. background-color: @dark-color;
  9. color: @light-color;
  10. }
  11. main {
  12. background: @light-color;
  13. }
  14. nav, aside {
  15. background: @side-color;
  16. }

它们几乎是相同的(@前缀代替$变量),只是不像Sass示例那样漂亮,但它与CSS具有相同的大括号和分号,这种与CSS相似的特点使得开发人员更容易接受它。2012年,JavaScript(特别是Node.js)代替Ruby用于重写和编译Less。这让Less比那些使用Ruby的同类速度要快,并且这让Less在那些已在工作流程中使用Node.js的开发人员中更受欢迎。

要将此代码转换为常规CSS,首先你需要安装Node.js,然后安装Less,最后运行如下命令:

  1. lessc index.less index.css

这个命令会将名为index.less文件中的Less代码转换为index.css中的常规CSS。请注意,Lessc命令并没有提供查看文件以及进行文件更改的方式(这与Sass命令不同),这意味着你需要安装不同的工具来自动监视和编译 .less文件,这为进程增加了复杂性。不过,这对于习惯使用命令行工具的程序员来说,并不是一件难事儿,但对于其他只想使用CSS预处理器的人而言,这是一个难以跨越的障碍。

伴随着Less在意识层面上获得很大的认可,Sass开发人员在2010年增加了一种名为SCSS的新语法(可以认定为CSS的高配版,与Less类似)。他们还发布了LibSass,这是Ruby Sass引擎的C / C ++端口,它的作用是使其加速,并且能够支持多种语言。

另一种替代CSS预处理器的是Stylus,它于2010年推出,采用Node.js编写,与Sass或Less相比,它更注重语法的清洁度。一般说来,谈论最多的三种CSS预处理器是Sass、Less和Stylus。它们在提供的功能方面都非常相似,所以无论你选择哪个,都不算选错。

然而,有些人认为CSS预处理器变得不那么重要了,因为浏览器最终会实现它们的一些特性(例如变量和计算)。此外,还有一种称为CSS后处理的方法,可能会使CSS预处理器过时(显然有争议),我们将在后面介绍这些方法。

使用CSS后处理器实现转换功能

CSS后处理器使用JavaScript来分析并将CSS转换为有效的CSS。从这个意义上讲,它与CSS预处理器非常相似,你可以将其视为解决相同问题的不同方法。关键的区别在于,虽然CSS预处理器使用特殊语法来标识需要转换的内容,但在无特殊语法下,CSS后处理器可以解析常规CSS并对其进行转换。下面这个例子来最好地说明了这一点。让我们来看看用上面最初定义CSS的一部分去设计标题标签的样式:

  1. h1, h2, h3, h4, h5, h6 {
  2. -ms-hyphens: auto;
  3. -moz-hyphens: auto;
  4. -webkit-hyphens: auto;
  5. hyphens: auto;
  6. }

粗体的部分称为浏览器前缀,在浏览器试验性地添加或测试新的CSS功能时会被用到,它为开发人员使用CSS的新特性提供了一种方法。-ms前缀是指Microsoft Internet Explorer,-moz前缀是指Mozilla Firefox,-webkit前缀是指使用Webkit渲染引擎的浏览器(如Google Chrome、Safari和Opera的新版本)。

请注意,添加所有这些不同的浏览器前缀以便使用CSS的新特性是非常麻烦的。如果有自动添加浏览器前缀的工具的话,将会很省心,我们可以用CSS预处理器来解决这个问题。例如,你可以用SCSS做这样的事情:

  1. @mixin hyphens($value) {
  2. -ms-hyphens: $value;
  3. -moz-hyphens: $value;
  4. -webkit-hyphens: $value;
  5. hyphens: $value;
  6. }
  7. h1, h2, h3, h4, h5, h6 {
  8. @include hyphens(auto);
  9. }

在这里,我们使用了Sass的mixin功能,这个功能允许你在定义了一个CSS块后,能在其他地方重用。当这个文件被编译成常规的CSS时,任何@include语句都将被替换成与之匹配的CSS @mixin语句。总的来说,这并非是一个糟糕的解决方案,但是你需要为任何需要浏览器前缀的CSS属性在首次定义mixin时负责。这些mixin定义需要维护,因为在浏览器更新其CSS兼容性之后,你可能希望删除一些你不再需要的特定浏览器前缀。

不是使用mixin,而是只写常规的CSS,并使用一个工具自动识别需要前缀的CSS,并相应地添加前缀,在这方面,一个CSS后处理器就能够做到。例如,如果你将PostCSS与autoprefixer插件一起使用,则可以在没有任何浏览器前缀的情况下编写常规的CSS,并让后处理器完成剩下的工作:

  1. h1, h2, h3, h4, h5, h6 {
  2. hyphens: auto;
  3. }

当你在此代码上运行CSS后处理器时,结果会是hyphens: auto,行将被替换为相应的浏览器前缀(正如autoprefixer插件中定义地那样,并不需要你直接管理)。也就是说你可以只写常规CSS而不必担心任何兼容性或特殊语法,这是一件非常好的事。

除了用于PostCSS的autoprefixer外,还有一些插件可以让你做很酷的事情。cssnext插件允许你使用CSS的试验性功能,该CSS模块插件可以自动改变类来避免名称冲突,stylelint插件识别CSS中的错误和不合常规的行为。这些工具在过去的一两年内才开始起步,为开发人员展示了从未有过的工作流程!

然而,这一过程需要付出代价。与使用CSS预处理器相比,安装和使用PostCSS之类的CSS后处理器更为重要。你不仅需要使用命令行来安装和运行工具,还需要安装和配置各个插件并定义一组更复杂的规则(例如,面向哪些浏览器等),而不是直接从命令行中运行PostCSS,许多开发人员将其整合到可配置的构建系统中,如Grunt、Gulp或webpack,这些可帮助你管理在前端工作流程中可能使用到的所有不同的构建工具。

注意:如果你以前从未使用过现代的前端构建系统,那么学习所有的必要组件可能会让你觉得是一件颠覆的事情。如果你想从头开始,请查阅我的文章Modern JavaScript Explained For Dinosaurs,它涵盖了前端开发人员所需的所有JavaScript工具。

值得注意的是,CSS后处理器的身上存在一些争议,有人说它们应该统称为CSS预处理器,还有别的说法认为它们应该简单地称为CSS处理器等,也有一些人认为CSS后处理器完全不需要CSS预处理器,而有些人认为它们应该一起使用。无论怎样,很显然,如果你有兴趣更深一步挖掘出CSS的潜能,那么学会使用CSS后处理器将值得你去尝试。

使用CSS的方法论进行维护

CSS预处理器和CSS后处理器等工具为改进CSS开发体验迈出了重要的一步,但单靠这些工具还不足以解决大型CSS代码库的维护问题。为了解决这个问题,人们开始记录关于如何编写CSS的不同的指导方针,通常称为CSS方法论。

在我们深入研究任何特定的CSS方法论之前,我们要清楚这么多年是什么使得CSS的维护变得如此困难?关键的问题在于CSS的全局性- 你定义的每种风格都会应用于页面的每个部分。想出一个详细的命名规则来维护唯一的类名或者用特殊规则来决定哪个样式应用于给定的元素,这将变成你的工作。CSS方法提供了一种有组织性的方式来编写CSS,以解决大型代码库的痛点,让我们以时间顺序粗略地看一下那些流行的方法。

OOCSS

OOCSS(Object Oriented CSS)是在2009年首次提出的,它遵循两种原则。第一个原则是将结构和表现隔开,这意味着定义结构(如布局)的CSS不应该与定义表现(如颜色、字体等)的CSS一起混用,这使得应用程序更容易重构其表现。第二个原则是将容器和内容隔开,这意味着将元素视为可重用的对象,而且不管对象在页面的哪个位置,看起来都应该是相同的。

OOCSS提供了成熟的指导方针,但没有具体的方案。后来的方法如SMACSS采用了OOCSS的核心概念并增加了更多细节,使其更容易入门。

SMACSS

SMACSS(Scalable and Modular Architecture for CSS)是在2011年推出的,它主要围绕CSS中5个属性展开,包括基本规则、布局规则、模块、状态规则和主题规则。SMACSS也提供了一些命名规则,对于布局规则,你可以用l-layout-作为类名称的前缀。对于状态规则,你需要在描述状态的类名加上前缀,比如is-hiddenis-collapsed

与OOCSS相比,SMACSS有更多的细节,但在决定哪些CSS规则应该进入哪个类别时仍需要慎重考虑。后来像BEM这样的方法避免了做决策的步骤,使其更容易被采用。

BEM

BEM(Block、 Element、 Modifier)于2010年推出,它是将用户界面划分为独立Block的一种方法论。一个Block是一个可重复使用的部件(例如搜索表单,定义)。Element为Block的一小部分,它不能独立重复使用(如搜索表单内的button,)。Modifier是一个实体,定义为外观、状态、Block或Element中的行为(例如禁用搜索表单里的按钮,定义为)。

BEM很容易理解,它具有特定的命名规则,新手在应用它时无需做出复杂的决策。它的缺点是类名非常冗长,并且不遵循传统的规则来编写语义类名。后来的方法如Atomic CSS会把这个非传统的方法带到了另一个层面上!

Atomic CSS

Atomic CSS(也称功能型CSS)是在2014年引入的一种方法,它的主要思想是基于视觉功能创建小而单一用途的类名。这种方法与OOCSS、SMACSS和BEM完全相反,它 不是将页面上的元素视为可重用的对象,而是完全忽略了这些对象,并使用可重用的单一实用工具类来对每个元素的样式进行设置。所以,你看到不是这样的:<button class="search-form__button">Search</button>,而是这样的:<button class="f6 br3 ph3 pv2 white bg-purple hover-bg-light-purple">Search</button>

如果你对这个例子的第一反应是害怕而退缩,那么你不是一个人,因为许多人认为这种方法与现有的CSS最佳实践方案完全背离。然而,不同场景下最佳实践方案的有效性引起了人们的质疑,在这个过程中也引起了不错的讨论。这篇文章做了很好的分析,重点阐述了传统的关注点分离是如何创建依赖于HTML的CSS(甚至是应当在什么时候使用BEM等方法),而Atomic CSS或功能型方法则是基于CSS创建的HTML。两者都没错,但经过仔细观察,你会发现CSS和HTML之间完全的分离从未真正地实现过!

其他的CSS方法,如CSS in JS,实际上包含了CSS和HTML总是相互依赖的概念,是最具争议性的方法之一。

CSS in JS

CSS in JS是2014年推出的一种方法,它的观点是:不在单独的样式表中定义CSS样式,而是直接在每个组件中定义。它是作为React JavaScript框架的一种方法而引入的(它采用了有争议的方法,直接在JavaScript中为组件定义HTML而不是在单独的HTML文件中)。最开始的时候,它采用内联样式,但后来使用JavaScript来生成CSS(使用基于组件的独一无二的类名),并使用样式标记将其插入到文档中。

CSS in JS再次完全违背了现有CSS最佳实践中的分离问题,这是因为我们使用网络的方式随着时间的推移发生了巨大变化。最初网站主要由静态网站组成,那时将HTML内容与CSS分离很有意义。如今,Web用于创建动态的Web应用程序,这时,通过可重用组件分离更有意义。

CSS in JS的目标是能够用HTML / CSS / JS封装的“硬边界”定义组件,使得每个组件中的CSS不会影响任何其他组件。React是最早被广泛采用的框架之一,它们为这些组件提供了“硬边界”的支持,随后影响了其他主流框架,如Angular,Ember和Vue.js等。需要注意的是, CSS in JS是新型的一种方法,在这期间开发人员试图在Web应用程序的组件时代为CSS建立新的最佳实践,并进行了大量的实验。

我们很容易被许多不同的CSS方法淹没,但重要的是要记住,没有一种完全正确的方法—— 当你面对足够复杂的CSS代码库时,你应该将它们视为几种不同工具作为备用。经过深思熟虑,为你的作品选择一个最佳的工具,并且在这个过程中进行的每一次试验都将为每位开发人员带来长远利益!

结论

综上所述,这就是现代的CSS。我们介绍了使用CSS进行基础设计的排版属性,将CSS用于使用浮点、flexbox和基于网格的布局,使用CSS预处理器以获取新语法(如变量和mixins),使用CSS后处理器实现转换功能,例如添加浏览器前缀,并使用CSS的几种方法论进行维护,克服CSS样式的全局性。我们没有机会深入了解CSS提供的许多其他功能,例如高级选择器、转换器、动画、形状、动态变量等待。

由于现代的CSS总是在不断地变化和快速发展,将其用在工作上难免让人头疼。但别忘了,随着时间的推移,网络也在不断发展,很高兴有很多聪明的人愿意加入这个行列,构建具体的工具和提出有效的方法来提升CSS的实践能力。我希望这些信息可以作为路线图,帮助你踏上旅程!

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注