写CSS的姿势

发布于 大漠

前两天去帝都参加第三届FEDay前端开发者大会,见了很多老朋友,也认识了很多新朋友。最主要的是听了很多大神的分享,涨了不少的姿势。想写这篇文章的出发点是PostCSS作者@Andrey Sitnik分享完之后有些同学提问,让我有感而发。希望这篇文章对一些同学有所帮助。

写CSS的姿势

对于前端而言,会写CSS并不难,因为这是基础之一,但能写好CSS那就不一定了。在整个社区也经常会碰到类似这些问题:

  • 怎么写CSS
  • 如何组织管理和维护CSS
  • CSS处理器是不是只能在大型项目中使用
  • 需不需要从Sass(或者其他的处理器,比如LESS之类)转到PostCSS

其实从这些问题中,我们就能简单的总结出写CSS的姿势无外呼有:

  • 直接写CSS,不采用任何的CSS处理器
  • 通过CSS处理器写,然后在编译出CSS
  • 直接写CSS,通过PostCSS再处理
  • 通过处理器编译出CSS,再使用PostCSS二次加工
  • CSS in JavaScript

那么在这些过程或姿势当中,有不少同学存在一定的困惑。接下来简单的聊聊我自己的一些看法和认识。

直接写CSS

很多初学者或者刚接触Web开发的同学一般都会采用直接写CSS,来给需要的Web页面添加样式。这种方式简单,无需了解CSS的处理器一些语法。简而言之,你只要懂CSS的语法、属性,你就能写出CSS。只不过写得好与不好之分,好不好管理和维护之分,特别是一些大型的项目。

当然,有些同学具有一定的基础之后,具有一定的实战经验之后常常会有新的困惑出来:

  • 怎么更好的管理和维护CSS
  • CSS的管理方法对于小型项目实用吗

其实看上去是两个命题,但我个人觉得是一个命题,那就是:**怎么能更好的管理和维护CSS?**针对这个问题,经过这么多年的发展和进化,业内同行朋友也提出和总结出一些管理CSS的方法。比如@INESSA BROWN 前段时间整理的《Methods to Organize CSS》一文中就提到了几个优秀的方案。比如说:

OOCSS

写CSS的姿势

OOCSS提倡内容和容器分开;设计和结构分开。这也是社区之内提出较早的一种编写、维护和管理CSS的方案.

SMACSS

写CSS的姿势

Atomic Design

写CSS的姿势

除了前面提到的,还有其他的类似方法,比如BEMSUITCSSMCSSAMCSS等。

看到上面这些列出来的方法,可能你已经有点放弃治疗或者说吃药了,甚至有点自生自灭的想法。其实不管上面哪一种方法,他们都是围绕CSS编写中最蛋疼的三个地方做的处理:

虽然上面的CSS方法论能解决我们CSS很多问题,但面对这些层出不穷的CSS方法论(或许后面还会有新的方法论出来),我又应该怎么根据自己的需求来选择自己需要的方法论呢?特别是一些初级的CSS同学经常会这样问。

@simurai曾经总结过一些选择方法,但原文地址已经404了。大致摘取下来的内容是这样的:

Q: 我只需要创建一个单页面或简单的站点。内容以文本为主。没有人和我协作,就我自己。

A:简单就好。直接给 HTML 元素添加样式,连 class 都不需要。依赖级联关系,利用样式继承。随着站点增长,可能需要开始看看 OOCSS,或不时使用一些工具类。

Q:我们是一个中型团队。项目复杂度增长较快,采用多人协作。

A:使用 BEMSUITSMACSSITCSSEnduring CSS 等。它们各不相同,但也有相似点,在某些方面亦有重叠之处。它们所使用的命名约定,能保证你们之间不会发生冲突。和团队一起讨论下,在作出最终决定前,可能需要多进行一些尝试。

Q: 我们是有多个团队的大公司,产品庞大而复杂。跟踪变化相当困难。代码库不断变化,而我们又不想顾此失彼。 A: 使用 JSXJSS,或其他类似的 CSS-in-JS 库。将 CSS 与 HTML/JS 绑在一起,更容易修改、移动或删除组件,而又不影响其他部分。还可以看看 ACSS 这样的 Atomic CSS,这是另一种解决相同问题的思路

上面三种有可能是我们最常见的几种类型了。最后一种其实是更为高级的一种处理方式了,后面我们会简单的聊一下。

那么做为有下中级或者高级的CSS开发者而言,你在设计自己的CSS“架构”应该需要去思考。

一个好的 CSS 架构是具有良好的可扩展性。可扩展性是在任何项目开发中都是具有挑战性的,范围的扩大或者团队人数的增加,这些挑战在 CSS 中也不例外。层级和全局的特性使 CSS 很强大,反之在开发过程中也是脆弱的。如果你写了一段时间 CSS,你会发现当改变一行 CSS 来修复一个功能的时候会破坏一批其他的 CSS 功能,这将让你很头痛。细心的规划能提供下列的好处:

  • 更少的样式
  • 更少的样式冲突
  • 更长的维护周期
  • 更快的提升新团队成员
  • 团队成员之间更容易交流
  • 更平稳的项目交接

为此,我们创建的CSS具体规则。

  • 模块化:设计系统在每一个方面都是模块,这是非常实用写CSS的方法。这在组件之间需要清晰分隔。
  • 可读性是关键:开发者必须在第一眼理解CSS代码,并且理解每一个选择器的目的。
  • 清晰胜过简洁:设计系统有时候看上去很冗长,但是作为交换,它提供清晰和韧性。保持CSS可读性和可扩展性意味着牺牲简洁的语法。
  • 保持平面化:长的选择器要回避,无论什么地方,尽可能保持CSS独立DOM和模块化。
  • 避免冲突:因为组件会部署许多不同的应用,保证设计系统之间的CSS不会和其他的库和系统有冲突,这很重要。通过系统空间命名Class名可以完成这个,更多的会在之后描述。

CSS预处理器

CSS预处理器是指类似Sass、LESS和Stylus之类的CSS处理器。后来我个人喜欢把他们也称之为CSS的处理器。

这里为了能更好的和后面要介绍的PostCSS区分开来,我暂把它们称为CSS的预处理器。

CSS预处理器相对于CSS而言更强大了一些,因为在CSS的预处理器中添加了类似于编程语言的一些特性,比如说变量、混合宏、扩展、逻辑运算等。就早期而言,这些东东在CSS中是不敢想像的。这些特性也给我们编写CSS和维护CSS带来很大的方便之处

  • 通过变量,更好的维护要变化的样式
  • 通过混合宏之类可以将共性的代码块提取出来
  • 通过逻辑运算符可以选择性的使用需要的代码块
  • ...

这也是CSS预处理器为什么会越来越受欢迎的原因。那么随着这些CSS预定处理器出现之后,也有新的问题出现了。很多同学会问,是不是直接在项目中加载CSS预处理器的代码即可在浏览器运行?如果你稍微的去了解过之后,你就不会问出这样的问题。为什么这么说呢?因为CSS的预处理器大致的原理都是相同的,比如Sass:

链路很简单,先在项目中写SCSS,然后处理器会将.scss文件编译成.css,然后在项目中引入.css文件。也就是说,最终浏览器加载的还是CSS文件。(其他的预处理器是一样的)。

采用这样的方式和以前编辑习惯将会有所不同,比如说:

  • 你需要配置CSS预处理器的运行环境
  • 需要了解CSS预处理器的语法和特性
  • 同样要懂CSS的语法和特性

平时在社区会碰到同学会问我,是不是学习了CSS预处理器的语法,就可以不需要懂CSS了。那么看到这里,你应该不会再问出类似的方法了。也就是说,如果你的CSS写得不好,你就是借用了CSS预处理器,也不一定能写好CSS。

CSS预处理器只是一种工具,用来帮助你更好的管理和维护CSS。能更好的让你积累优秀的代码块,通过一些独有的特性,让你写CSS没那么累等等...

很多时候,社区经常在探计Sass、LESS和Stylus哪个更好,应该使用哪一个之类的话题。我个人的想法是它们其实都类似,只是使用语法和特性略有不同。都是用来处理CSS的一种工具,都是用来帮助大家更好维护和管理CSS的工具。也就是说,具体选择哪一款CSS预处理器,应该根据你们团队的成员而定,或者自身更易于接受哪一款。就我个人的爱好,我就是从LESS转向Sass的。

CSS后处理器

严格意义上来说,是没有CSS后处理器。这里仅是为了更好的区分而这么称呼。那么CSS的后处理器就是PostCSS。PostCSS官方是这样描述的:

PostCSS is a tool for transforming styles with JS plugins. These plugins can lint your CSS, support variables and mixins, transpile future CSS syntax, inline images, and more.

简而言之,PostCSS是CSS变成JavaScript的数据,使它变成可操作。PostCSS是基于JavaScript插件,然后执行代码操作。PostCSS自身并不会改变CSS,它只是一种插件,为执行任何的转变铺平道路。

本质上是没有很制PostCSS插件操纵CSS,也就是说它可以适用于任何CSS。只要你能想到的,你都可以编写一个PostCSS插件,让它来转成CSS。

那么PostCSS不是什么?又是什么?感觉很拗口:

PostCSS不是什么

  • 尽管表面上它看起来是一个预处理器,其实它不是一个预处理器
  • 尽管表面上它看起来是一个后处理器,其实它也不是一个后处理器
  • 尽管它可以促进、支持未来的语法,其实它不是未来语法
  • 尽管它可以提供清理、优化代码这样的功能,其实它不是清理、优化代码的工具
  • 它不是任何一件事情,这也意味者它潜力无限,你可以根据自己的需要配置你需要的功能

PostCSS特别之处

  • 多样化的功能插件,创建了一个生态的插件系统
  • 根据你需要的特性进行模块化
  • 快速编译
  • 创建自己的插件,且具可访问性
  • 可以像普通的CSS一样使用它
  • 不依赖于任何预处理器就具备创建一个库的能力
  • 可以与许多流行工具构建无缝部署

其实更形象的可以将PostCSS视为CSS中的Babel。你可以通过JavaScript开会任何你想要的功能插件,并且运用于项目中去处理你的CSS。简单的用一张图来描述,如果你的工作中开始使用PostCSS,又应该是怎么一个流程:

简单的说,你以前是怎么写CSS的照样怎么写,不同的是在你的工程中使用了PostCSS的一些插件,这些插件帮你更好的处理你的CSS。比如@Andrey Sitnik在大会上分享的Stylelint。除些之外你还可以使用任何你想要的PostCSS插件,只要这个插件能帮你更好的处理你的CSS。就算是在庞大的PostCSS插件库中没有你所要的插件,你也可以基于JavaScript编写出你想要的功能插件。当然要在项目中使用PostCSS,并不能说简单的引用一个文件即可搞定,这个时候你需要一些工程化方面的知识和经验,比如Gulp、Webpack之类。如果你没有这些工程化方面的东东,你也只能看看而以,并不能帮你解决任何问题。

这个时候问题又来了,前面提到的CSS处理器有Sass、LESS和Stylus,这里提到的CSS处理器PostCSS。有人就问了,我怎么从Sass或者说LESS过渡到PostCSS?看到这样的问题,我一般会问,为什么要从Sass过渡到PostCSS。往往我得到的答案是:

  • PostCSS很牛逼
  • PostCSS很多人都说好
  • ...

这个时候很想质问,**你真的懂我(PostCSS)吗?**事实上你真不懂,你只是听说他好,你只是想跟跟风而以。

感觉有点跑题了,回到正题上来。正如大会上有同学提出类似问题,我怎么从Sass之类的过渡到PostCSS?当时我就觉得 @Andrey Sitnik 内心是崩溃的。为什么这么说呢?让我先上一张图:

看到上图,再配合一张@一丝姐姐的手绘图:

那么我想之后你应该不会再问出如何从Sass过渡到PostCSS之类的问题。事情上,现在的CSS也开始在借助CSS处理器一些特性。我想不久之后,原生的CSS也会具备CSS处理器的特性,比如CSS变量。如果你的项目中配置了cssnext这个PostCSS插件,你可以使用CSS很多新特性规则。

人都是会喜新厌旧的,你总是想抛弃旧爱,事实上PostCSS也是可以帮你做到的,你只需要了解一些CSS的新特性或者一些PostCSS的插件使用规则或语法之类,就可以完成你所谓的过渡。但事实上,这能不能让你更爽就有待尝试了之后才能知道。因为我没法回答。

就我个人而言,一前一后,还是蛮爽的,再配合CSS的自定义属性特性更爽。

CSS in JS

前面了解好多种写CSS的姿势了,但随着技术不断的革新,写CSS的姿势也在不断的革新。@Perezpriego的《CSS Evolution: From CSS, SASS, BEM, CSS Modules to Styled Components》一文中详细介绍了CSS的进化过程。感兴趣的同学可以看看这篇文章。

前端开发人员一直都在提组件化,其中CSSer也不断的在提组件化。我碰到很多同学会问如何组件化写东西?其实很多时候我自己的回答不清楚,我不知道怎么能更好的将这个怎么写能阐述的更为清晰,让人家一听就能明白。在我个人的印象中,就是怎么用最少最可复用性最可维护性来写。当然在这个过程中会碰到很多的细节,比如组件拆分以什么样的单元来划分?组件又是怎么来组装?等等。

这些问题一直都在探讨。至今也是个所以然。

随着React、Vue这样的框架的兴起,写CSS的姿势又变了,兴起CSS in JS。当初看到这个概念的时候,说实话让我一下子无法接受。因为遵从了多年的样式与结构的分离,现在要变了。但是后面自己去尝试之后,和我们当初的行内样式还是有所区别的。这又回到那句话:

只有实践过,才有话语权。

在这个实践过程中,我接触了两个新概念CSS ModulesStyled Components

如果你一直都有使用工程化来维护和管理自己的项目的话,那么不管是CSS Modules还是Styled Components都可以轻易的切入到你的工程中。比如下图所示的一个工作流,也是CSS Modules的一个典型的工作流:

但上面这种流程,也有可能会出现共享类名的情形,为了解决这个可能性的现象,我们可以将工作流换成这样:

从原生的 Css 到 CSS Modules,再到 Css In Js,目标是让开发者更高效地写组件的样式。Styled Components 是基于 Css In Js 方式实现的一个库。目前主要服务于React。

虽然它是为React开发者服务,但相比之下它是解决了以前CSS社区一直想解决,但未能很好的解决的一些问题:

Styled Components对于适当的扩展至关重要,即使用纯CSS和BEM也可以实现,主要的区别是每个实现方式所需的工作量和代码行数,总体而言,Styled Components就像一个给几乎所有的React项目的伟大套装。

当然,社区有关于CSS In JS方面的争议也是不少,具体问题还是需要具体分析。

总结

无论是Sass,BEM,CSS Modules还是Styled Components,无论使用什么技术,都不能单独成为一种能够直观地为其他开发人员提供代码参照,而不影响或引入新的模块到系统中来的完美的样式架构。

面对众多的写CSS姿势和管理维护方式,你在确定项目中或者说团队怎么去写CSS和维护CSS时,建议你可以先按下图的流程进行:

最后我想表达的是,没有最好的,只有最合适的! 如果真的有最好的,我也不会花这么长的时间来梳理这篇文章提到的各种姿势或者说工具。

有些人喜欢坚持已经被证明的成熟的工具。如果是这样的话,你可以使用LESS或SCSS,然后继续前进。许多开发人员喜欢使用单一工具,也不应该受社区的风向而影响。

我个人更喜欢那些更新的、更现代的工具,比如PostCSS和CSS模块。但这些不足以证明这些方式对你或是你的团队来说是最佳的。选择还是需要遵循一定的习惯原则。记住:没有最好的,只有最合适的。

大漠

常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《图解CSS3:核心技术与案例实战》。

如需转载,烦请注明出处:https://www.fedev.cn/css/css-evolution.htmlAir Max 1 Master