CSS中的艺术
本文介绍了用于大型Web应用程序(通常是SPA)的CSS最新趋势。我不想质疑这是对的还是错的,而是把它们列出来。以供大家参考和讨论。
最初,Web页面被设计成具有超链接的信息页面(即使图像也不应该是内联的——它被解释为,在1990年,带宽和计算机资源非常小),类似交互式图书的东西。CSS的设计是为了添加一些基本的样式,最初它看起来像是一个好主意,用你自己的风格覆盖外部风格。现在,它绝对是一个疯狂的想法 —— 尝试应用自己的样式,比如说页头。开发人员绝对不会期望这些样式是来自于用户。
其中最有趣的一点是,它是由微软推动的,你可以在这里阅读到它。这篇文章涉及面非常广泛,但我将跳过最初的部分,直接进入重要的内容中。
大型应用程序
从历史上看,前端被认为是二等公民,通常是由设计师或特别的人来实现的,他们通常不太了解编程 —— 通常是一些后台的模板语言。早在10多年前,这并不是一个大问题,因为一个典型的Web应用程序的大小并不大,所以使用类的样式设计已经很好了。不理想,但不是很烦人。 虽然互联网在不断的增长,应用程序变得越来越大,在某种程度上,人们开始意识到CSS有一系列问题,这些问题变得越来越严重:
- **权重的烦恼:**新的样式规则可以不小心地覆盖一些旧的样式,而且通常是在完全意想不到的地方就发生了
- **没有类名:**在大型应用程序中,很容易意外地重用某些类名(比如:
header
、content
、container
等) - **脆弱:**增加新规则、改变旧的规则是凶险的,因为我们不确定它将如何影响项目的哪些地方
- **大文件:**最好把所有东西都保存在一个文件中(这样浏览器就不会再花更多的往返请求服务的时间),要维护一个大文件真的很困难
- **冗余:**我们必须经常重复很多东西(例如,如果我们想添加
text-overflow:ellipsis
),而且最近很难改变它们。同一个类可能无法工作,因为我们可能想传递一些参数 - **没有办法与应用程序代码共享变量:**我们可以在两个地方硬编码它们,但是如果我们想要改变,就有很大的机会错过一些东西
CSS并不是一种编程语言 —— 尽管引入了变量,但它没有函数、条件和循环的功能,因此没有办法自动化生成代码。如果你基于代码中的某些属性创建类名,那么必须在CSS代码中重复所有这些属性,这是不可避免的。对于变量来说也是一样的,如果你需要把所有的green
颜色换成稍微不同的颜色。有时候颜色可能是一样的,但在语义上是不同的颜色(比如primary
和header-title
)。所有这些都导致了预处理器的诞生,这些语言与CSS非常相似,但具有扩展功能 —— Sass、LESS、Stylus和PostCSS。
CSS处理器
在计算机科学中,处理器是一个程序,它处理它的输入数据产出输出,作为另一个程序的输入。—— Wiki
处理器具备的基本特点如下:
- **变量(最重要的事情之一):**颜色和大小现在是语义化的
- 导入: 比CSS的方法创建大文件更好,为每一个链接创建一个新文件,仅仅导入所需的文件
- **循环:**允许很容易创建重复的样式。例如,它请允许你以极其简单的方式创建和更改网格系统
- 函数(或者称为混合宏): 可以很容易地与不同的参数共享相同的功能
- **嵌套:**允许将相关的样式放在一起,当我们在CSS中手工编写嵌套时,可以削除错误的可能性
处理器肯定能帮助冗长的样式分离到小文件(它们都能连接到一起合并成一个文件),并将变量保存在一个地方,它们对你没有任何帮助,因为它们都逃脱不了CSS的权重和脆弱的烦恼。为了解决这些问题,一些所谓的方法被发明和推广。
CSS方法论
所有的方法都主要解决全局类名(可能重叠)和权重冲突的问题。由于CSS缺乏作用域,所以我们必须使用类名规则来解决这个问题。它们都有不同的方法,但这个想法是一样的 —— 我们在一些规则的基础上使用一些前缀。
例如,让我们看一下BEM方法。它不仅仅是一个CSS方法,但是我们将只考虑命名规则。BEM代表Block
、Element
和Modifider
。让我们来看一个小例子。比如,我们想要在页脚内的列表中设计标题(它看起来是最后一个,也就是粗体)。我们有以下的组成部分:
- Block:
footer
- Element:
list-header
- Modifier:
last
因此,完整的类名:footer--list-header
、 footer--list-header__last
。它非常冗长,但是它允许我们编写有语义的类名,并且(在某种程度上)不会发生类似的冲突。另外,你可以看到这里的元素由两个逻辑部分组成,所以这样做很好,但是因为我们只有这三个部分,这意味着我们需要分开另一个块,footer-list
,在里面我们可以有一个元素header
。我知道,现在很多人会说,我不知道BEM的命名是什么,但它仅仅是一个结果的细节 —— 我们有独特的前缀,它帮助我们避免类名冲突,但这是用冗长的方式换来的。BEM方法不鼓励任何嵌套,如果你需要共享一些样式,在这种方法的上下文中,你需要共享的是组件,而不是仅仅的类名。其他方法使用嵌套,但是它们有严格的规则,哪些是嵌套,哪些是类名。
问题是它们只部分地解决了全局变量的问题。我们仍然需要使用它们,我们依旧要通过使用特殊的规则来避免问题,从长远来看,这并不是一个非常可靠的解决方案。但是,如果你不能使用CSS模块(自动添加前缀),那么一定要检查它们。
然而,我想指出的是,BEM通过阻止任何嵌套,几乎完全解决了一个权重冲突的问题,但是,与往常一样,作为交换,在CSS中删除了C;如果没有它,就不可能发生连锁反应(这是好是坏—— 又是一个燃烧大脑的话题)。
下面列出来了一些不同的CSS方法:
到翻译这篇文章的时间为止,CSS中的方法除了上面列的几个之外,还有其他的一些CSS方法,比如:SUIT CSS、ITCSS、Atomic CSS、RSCSS、MCSS、Enduring CSS、CCSS等。
CSS Modules
在进行 CSS Modules的实际讨论之前,我们必须先后退一步,这本身就是加载器的规范。
在Gmail成功使用AJAX之后,AJAX使用就越来越多,因此,应用程序开始变得更加前沿,这不仅仅是大小,遭遇是语言 —— JavaScript。人们开始构建更加复杂的应用程序,一些人开始将所有内容都呈现在客户端上 —— 使用来自JavaScript的模板。因此在某些情况下,后端代码开始变得无关紧要,因此在CVS(如git)中解耦它们是有意义的。它引发了用于处理资产的工具的必要性,与后端框架分离。
因为Node.js的出现,人开始使用它来构建工具。Grunt、Gulp和后面出来的Browserify。最后一个特别重要,因为Grunt和Gulp在文件上执行一组任务,而Browserify则根据一组规则来处理所有事情。本质上,这意味着我们可以处理所有东西,包括CSS。它的意思是,我们可以请求(require
)CSS文件,并得到一些输出。它正是这样 —— 我们需要一个CSS文件,这是解析的,我们有一个普能的JS对象,它的键是我们的类,但是值是不同的唯一字符串!
这是一个惊人的突破,我想再次强调一下。我们可以有尽可能多的标题类,只要它们在不同的文件中出现 —— 这对我们来说完全是可以的,因为我们希望将它们放在附近的模板、组件和UI中使用它们。CSS模块实际上是一个有作用域的概念,它就像BEM的块元素系统,block
是唯一的前缀(我们不必要考虑它),元素就是我们的类。因为我们可以尽可能地模块化,并且前缀将是唯一的,我们根本不需要引入修饰符。我们可以再次使用整个BEM命名系统,或者使用嵌套,或者绝对的任何东西,但是要确保它不会与其他东西重叠。这是一个非常强大的技术。
最大的缺点仍未解决,就是在应用程序和我们的样式之间共享代码。使用处理器,我们可以在构建步骤中定义相同的变量,但是如果我们想在运行时定义一些东西,我们必须退回到旧的样式,这自然把我们带到最后要聊的一个点 —— CSS In JS。
CSS-in-JS
以前在这个领域有过一些探讨,但所有的讨论声都是在这个演讲之后开始的:
它触及了一个非常凶险的话题,我们应该把所有样式都移到JavaScript上,现在有很多库可以这样做,但是它们都只有两种不同的方法。第一个方法非常明显,它们确实把所有样式移到JavaScript上。这里有几个问题:
- 这里根本没有类,所以你可以修改所有列表元素样式
- 查看开发人员控制台,很难理解这里的组件是什么
- 我们传输更多的字节 —— 因为所有东西都是内联的,我们不得不在很多地方重复相同的样式
使用内联样式的项目示例。
另外一种方法是使用DOM规范的样式表。它和界面部分几乎一样。
因为我们写正常的JavaScript,它允许我们解决绝对性的样式问题,甚至更多,我们可以在运行时改变我们的样式,所以你的应用程序可以根据一些参数的呈现完全不同的样式风格,甚至可以根据一些切换重新剪切。如果使用传统的方法,这将是一个非常复杂的任务。
当然,有几个问题:
- 工具还没有准备好。多亏了JS生态系统和社区,它对于基于Electron的编辑器来说是很好的,但是更多的传统IDE将不会很快就开始使用它(我指的是Emmet和Linting)
- 许多库没有任何嵌套
- 它是JavaScript,因此如果没有丰富经验的开发人员用于HTML和CSS开发,那么这可能会使开发更加复杂
- 这是一个非常快速的领域(像在JS世界中一样),所以很有可能在几年内你的库会被废弃
下面列出几种CSS-in-JS的库:
总结
现在,当你开始一个新的Web项目时,你一定要根据应用程序的大小和需求选择一个策略。如果你没有很多东西具有动态样式,你知道所有变量和构建步骤,和你不想分享一些组件和皮肤,那么你可以放心地选择一个更传统的方法(但我强烈推荐使用CSS模块,解决所有问题与类名的全局作用域和权重冲突)使用你所选择的一些方法坚持下去。有百分之百的机会,你的选择在接下来的五年里仍然是正常的,这是JS选择的一个大问题。
如果你需要一个大的灵活性,大的主题,或者一些动态的改变,那么CSS-in-JS是一个不错的选择。你需要自己评估所有现有的解决方案,选择你认为最合适的解决方案,并且最适合你。这个选择过程是一个有风险的赌注,但它肯定会解决许多传统的CSS问题,特别是在项目和运时风格变化之间共享的组件。
本文根据@Seva Zaikov的《State of the art in CSS》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:https://medium.com/@bloomca/state-of-the-art-in-css-54df6b211d07。
如需转载,烦请注明出处:https://www.fedev.cn/css/state-of-the-art-in-css.htmlTravis Scott x Jordan 1 Backwards Swoosh Mocha