TAT.bizai 全局 CSS 的终结 (狗带) [译]
In CSS3,Web开发 on 2015年10月22日 by view: 15,660
23

CSS 类名总是作用在同一的全局作用域里面。

任何一个跟 CSS 有长时间打交道的开发者,都不得不接受 CSS 那具有侵略性的全局特性,明显地这是一种文档流时代的设计模型。而对于今天现代 web 应用,更应该积极提出一种更健全的样式环境。

每一个 CSS 类名都有可能与其它元素产生的意想不到副作用,又或者产生冲突。更令人吃惊的是,我们的 class 的效果可能在全局作用域的互相影响下(原文这里比喻为全局唯一性战争),最终在页面上产生很少的效果或者根本没有效果。

任何时候我们改变一个 CSS 文件,我们都需要小心翼翼地考虑全局环境是否产生冲突。没有其他前端技术是需要如此之多的规范和约束,而这仅仅是为了保持最低级别的可维护性

、、、

 

但我们不能一直这样下去。是时候摆脱这种全局样式的折磨。开启局部 CSS 的时代!

“ 在其他语言,全局环境的修改需要变动的代码很少”

在 javascript 的社区中,感谢 BrowserifyWebpackJSPM,让我们的代码变得模块化,每个模块有明确的依赖及其输出的 API。然而,不知怎么的,CSS 视乎总时被忽略掉。

我们中许多人,包括我自己,一直使用 CSS 工作这么长时间,我们都没有发现缺少局部性作用域,是一种问题。因为没有浏览器厂商的重大帮助下我们也能够解决。即使这样,我们仍然需要等待着,大部分用户能使用上浏览器的 ShadowDOM 的支持。

在全局作用域问题上,我们已经使用一系列的命名规范来编码。想 OOCSSSMACSSBEMSUIT,每一个都提供着一种方式模拟健全的作用域规则,达到避免命名冲突效果。

虽然驯服 CSS 无疑是一个巨大的进步,但这些方法都没有解决我们样式表上真正的问题。无论我们选择哪个规范,我们依然被卡在全局类名上。

但,在 2015 年的四月 22 号将会发生改变。

、、、


正如我们此前的一篇文章涉及到——“Block,Element,修改你的 JavaScript 组件”—— 我们可以利用 Webpack 把我们的 CSS
作为一种 JavaScript 模块来引用。如果这听起来很陌生,去读读这篇文章会是一个 good idea,以免你错失接下来要讲的内容。

使用 Webpack 的 css-loader,引用一个组件的 CSS 如下:

乍一看,这很奇怪,我们引用的是 CSS 而不是 JavaScript

通常,一个 require 引入的应该提供一些局部作用域。如果不是,明显低会产生全局作用域的副作用,这是一种拙劣的设计。而 CSS 的全局作用域特性,却必定产生这样的副作用。

因此我们在思考

、、、

2015 年 4 月 22 日,Tobias Koppers 这位对 Webpack 孜孜不倦的代码提交者,提交了一个 css-loader 新特性的版本提交。当时叫 placeholder,而现在叫 local-scope。这个特性允许我们输出 classname 从我们的 CSS 到使用中的 JavaScript 代码。

简而言之,下面这种写法:


我们改为

看看我们导出的 CSS 是怎么样的,我们的代码大概如下:


在上面的例子中我们使用 css-loader 的定制的语法  :local(.idntifier) ,输出了两个的标识符,foo 和 bar。
这些标识符对应着 class strings,这将用在 javascript 文件中去。例如,当我们使用 React

重要的是,这些标识符映射的 class strings,在全局作用域上是保证唯一的。
我们不再需要给所有的类名添加冗长的前缀来模拟范围。多个组件可以自定义自己的 foo 和 bar 标识符。—— 不像传统的全局作用域的模式,也不会产生命名冲突。

、、、

非常关键的一点,不得不承认这已经发生了巨大转变。
我们现在更有信心地大胆修改我们的 CSS,不用小心翼翼地怕影响其他页面的元素。我们引入了一个健全的作用域模式

全局 CSS 的好处是,组件间通过通用的 class 来达到复用的效果—— 这仍然可以在局部作用域模型上实现。关键的区别是,就像我们编码在其他语言上,我们需要显式地引入我们依赖的类。假想一下在全局命名环境,我们引入的局部 CSS 不需要很多。

“ 编写可维护的 CSS 现在是值得提倡的,但不是通过谨慎地准守一个命名约定,而是在开发过程中通过独立的封装”

由于这个作用域模型,我们把实际的 classname 的控制权移交给 Webpack。幸运的是,这是我可以配置的。默认情况下,css-loader 会把标识符转换成为 hash。
例如:


编译为:


在开发环境调试来讲,会带带来一些阻碍。为了令到我们的 classes 变得更加有用,我们可在 Webpack 的 config 里面设置 css-loader 的参数,配置 class 的格式。


在这一次,我们的 foo 这个 class 会比之前编译的更加好辨认:


我们能清晰地看得到标识符的名字,以及他来自哪个组件。使用 node_env 环境变量,我们能根据开发模式和生产环境配置不同的 class 命名模式。


、、、

一旦我们发现这个特性,我们不用犹豫地在我们最新的项目上本地化起来。如果按照惯例,我们已经为组件化而使用 BEM 命名 CSS,这真是天作之合。

有趣的是,一种现象很快地出现了,我们大部分 CSS 文件里只有局部化 class:

全局性的 class 仅仅在 web 应用里面的一小部分,本能地引开出一个重要问题:

“ 如果不需要特殊语法,我们的 class 默认是局部性的,而让全局性的 class 需要例外。怎么样?”

如果这样,我们上面的代码就变成如下:

虽然这 class 通常会过于模糊,但当他们转换为 css-lodaer 的局部作用域的格式后将会消除这一问题。并且确保了明确的模块作用域来使用。

少数情况,我们无法避免全局样式,我们可以明确地表明一个特殊的全局语法。例如,当样式使用 ReactCSSTransitionGroup 来生成一个无作用域 classes。

.panel :global .transition-active-enter{...}

在这个例子中,我们不只是使用本地化方式命名我的模块,我们也命名了一个不在我们的作用域上的全局 class。

、、、

一旦我开始调查我如何实现这个默认局部化 class 语法,我们意识到它不会太困难。
为了达到这个目的,我们推荐 PostCSS—— 一个神奇的工具允许你编写自定义的 CSS 转换插件。今天最受欢迎的 CSS 构建工具 Autoprefixer 实际上是 PostCSS 插件,同时为一个独立的工具而已。

为让局部 CSS 正式地使用,我已经开源了一个高度实验性质的插件 postcss-local-scope。它仍然在发展,所以在生产环境中使用你需要控制风险。

如果你使用 Webpack,这是非常简单的流程:挂上 postcss-loaderpostcss-local-scope 在你的 CSS 构建流程。比起文档,我已经创建了一个示例库——postcss-local-scope-example。里面显示了怎么使用的例子。


令人激动的是,引入局部作用域仅仅是一个开始。
让构建工具处理 classname 有一些潜在的巨大影响。从长远来看,我们应该停止人为的编译器,而是让计算机来优化输出。

“ 在未来,我们可以在一个最优的编译时间内,自动化找出可重用的样式,生成可组件之间共享的 class”

一旦你尝试了局部 CSS,你就回不去了。真正体验过,样式的局部作用性在所有浏览器上运行正常,你会难以忘记的体验。

引入局部作用域对我们处理 CSS 有重大的的连锁反应。命名规范,重用模式,潜在的样式抽离,分包等等,都会直接受到这种转变的影响。我们仅仅在这里开始了局部 CSS 的时代。

理解这种转变的影响是我们依旧需要努力。伴随你有价值的投入和实验,我希望这是作为一个更大的社区的一次谈话

“ 加入我们,check 出 postcss-local-scope-example 的代码,眼见为实”

一旦你行动了,我认为你会同意这并不夸张: 全局 CSS 的日子将会终结,局部 CSS 才是未来。

 

后记:
2015 年 5 月 24 日: postcss-local-scope 的最初想法已经被 Webpack 的 TobiasKoppers 所接受。这意味着改项目已经被弃用了。现在我们初步确认在 css-loader 上通过一个 module 的标志可以支持 CSS Modules。我创建了一个库来演示 CSSModules 在 css-loader 上的用法,包括类的继承及职能组件间共享样式等。

 

译文原地址:

https://medium.com/seek-ui-engineering/the-end-of-global-css-90d2a4a06284

 

原创文章转载请注明:

转载自AlloyTeam:http://www.alloyteam.com/2015/10/8536/

  1. 前端学习需要的资源网站集合_亿浪博客 2017 年 2 月 7 日

    […] cs – [url=http://bouncejs.com/]bouncejs 触摸库- css3 按钮动画- animate.css- 全局 CSS 的终结 (狗带) [译] ####7. […]

  2. 史上最全的前端资源大汇总 | 神刀安全网 2017 年 1 月 15 日

    […] 全局 CSS 的终结 […]

  3. 前端资源教程 – w3cmart 2016 年 11 月 3 日

    […] 全局 CSS 的终结 (狗带) [译] […]

  4. {转}最全前端资源汇集 – 前端笔记 2016 年 10 月 24 日

    […] animate.css http://daneden.github.io/animate.css 全局 CSS 的终结 (狗带 [译] http://www.alloyteam.com/2015/10/8536 browserhacks http://browserhacks.com […]

  5. 前端代码—中级进阶 – 杨旭龙随笔|一名菜鸟设计师的成长之路 2016 年 5 月 25 日

    […] CSS| 地址 — | — CSS 语法参考|http://tympanus.net/codrops/css_reference CSS3 动画手册|http://isux.tencent.com/css3/index.html 腾讯 css3 动画制作工具|http://isux.tencent.com/css3/tools.html 志爷 css 小工具集合|http://linxz.github.io/tianyizone css3 js 移动大杂烩|http://www.note12.com/category/blog/2014-6-5/538fe0a9f786f1b7019a4dfb bouncejs 触摸库|http://bouncejs.com css3 按钮动画|http://fian.my.id/Waves animate.css|http://daneden.github.io/animate.css 全局 CSS 的终结 (狗带 [译]|http://www.alloyteam.com/2015/10/8536 […]

  6. err 2016 年 4 月 15 日

    禁用 js 的情况就别考虑了,什么年代了…

  7. [转]最全的资源教程-前端涉及的所有知识体系 | @Sting (atSting.com) 2016 年 3 月 20 日

    […] 全局 CSS 的终结 (狗带) [译] […]

  8. 77 2016 年 1 月 13 日

    现在这么重的前端交互 ,关闭了 js。即便页面能渲染,大部分功能也无法正常使用

  9. 可馨 2015 年 11 月 30 日

    不错! 不错! 不错!

  10. 84 2015 年 11 月 27 日

    实际应用中,肯定不只一个 css-loader。这个能和现有的 less 或者 sass 兼容吗,less-loader 遇到这种奇怪的定义不会报错吗?

  11. 岑锦超_Jin_C 2015 年 10 月 29 日

    但这样 层叠样式表 可能就失去它本来的 意思了。

    • TAT.bizai 2015 年 11 月 2 日

      不会的。仅仅变动的地方只是些了 classA 你根本不用担心命名冲突。
      叠层样式表的语法都正常使用,一概不变。

  12. Maxsh 2015 年 10 月 23 日

    我在想如果用户禁用 js 岂不是连样式都看不到了

    • TAT.bizai 2015 年 10 月 23 日

      。。。。听你这样一说,的确会有这样小众情况的问题。[黑线][黑线]
      可是一般除了局部 CSS 外,我们都会有一个全局 index.css 用于渲染页面的整体结构,用户硬要禁用 JS 的话,页面大体还是能正常渲染的。

    • z x 2015 年 10 月 26 日

      那只是构建过程,和生产环境没有关系

      • cat 2015 年 11 月 4 日

        indeed

    • eyas 2015 年 11 月 22 日

      生产环境可以把 css 分开打包的吧

发表评论到 前端代码—中级进阶 – 杨旭龙随笔|一名菜鸟设计师的成长之路