随便说说
把我在贺老那某篇文章下讨论的一条评论再贴一下:
我觉得理想中,我们是想构造一个类似 Shadow DOM 的环境——不存在被外部样式_不小心_覆盖的可能,但保留了从外部对组件内样式修改的可能性(必须用明确的语义来描述——>>>)。
我也同意只有强制使用全局不冲突的 class/id 来选择元素,才能完全避免样式的侵入。不管按命名约定的扁平 class,还是像 CSS Modules 那样通过一些算法自动将 local class 转换为 global class, 本质上看上去是一样的。后者过程自动了,但是失去了对转换后名称的控制,HTML/JS 需要从 CSS 模块中再把这个名字导入进来。但实际上这两种方式的不同点在于,通过命名约定的方案没有进行「封装」,我可以在 A 模块直接输出 B 模块中的 class 来「复用」A 的样式。但通过 CSS Modules 全局化 class 以后,模块之间除非通过显式依赖,是可以做到完全的隔离的。
还有一种方案就是在组件根元素上加特定的 class/id/属性来给出一个「模块的钩子」供 CSS 使用。比如 Vue.js 目前用的是在组件根节点上增加一个自动生成的全局唯一属性,然后 CSS 上增加一个属性选择器(Scoped CSS)。但是这也不能排除被外层 specificity 更高的规则不小心覆盖掉的可能。比如理论上我写一个 #content .example 就能轻松突破防守。
但是实际上我们自己的项目中一直是用特定 class 来做 CSS 应用范围限定的(和 Vue.js 目前的方案没太大区别),也没有遇到很大的问题,因为当几乎所有的代码都是以这种方式书写的,是不太容易写出冲突的样式的。这个方案在所有代码都受控的情况下我觉得足够了,但是当我们的代码要嵌入第三方网页、或者一个页面里要集成多个产品的内容,可能就得用更严格确保「无法冲突」的方案了。
整理一下,CSS 的全局性导致了两个问题:
- 组件样式受外部影响,这可能是设计意图,也可能是无心之失(对应 ShadowDOM 解决的问题,要对下层语义明确地进行覆盖);
- 组件样式影响到外部内容,这是不应该发生的(对应
scoped要解决的问题,ShadowDOM 同样可解决)。
2 的问题其实很好解决,上面已经提了。1 才是难搞的。CSS Modules 是开发时用 local class name,发布/运行时重命名组件内 class,来尽可能避免冲突。最大的优势是省了脑子,开发时用最合适的命名而不用去考虑冲突的问题,模板、样式代码看起来爽。你这里的 POCss 其实就是基于约定人肉维护一个全局名字,因为随时对 class 可控,也就随时可以覆盖,灵活(不严格)。
我这的一些场景下,还需要对 class 做全局的混淆,甚至还可能是 runtime 的。因为 class 反正得动态生成,所以我正在考虑一个接近 CSS Modules 的方案,但是不是由 CSS 导出 class,而是 JS 生成好动态生成 <style> 的实际内容。可能在打包发布时要生成一些类似 HTML 模板的「CSS 模板」来用。
@Justineo 你的观点我完全同意,
先说两点:
- 我个人认为 CSS Modules 在解决问题 1 上其实做得很好了。对于 JSer 其实学习成本也不大,混淆也是很有必要的。虽然我觉得**“确实不应该是 CSS 的发展方向”**,但是我几乎也找不到太多问题(其实这里我很想听贺老详细讲讲,贺老这个待续就没下文了)
- POCss 的存在其实我在 Slides 里说了它其实还是就是个 “Naming Convention” 而已,并且是为 “有迁移成本、有 CSS-engineer (重构) 的团队” 服务的,更多的是出于公司现状的一些考虑。那么既然是命名规约那他肯定是人肉维护的
再说我认为的方向:
其实无论 reset 还是 <style scoped> (vue-loader 想要达到的效果),其实说白了就是为 CSS 带来一个真真切切的作用域,不是靠命名规约伪装的也不是靠 CSS Modules 这样通过“干脆都混淆得不认识算了”的,真正可控,且灵活的作用域。
什么是真正可控、灵活就是我想要这个作用域有就能有(比如正常编程语言里的局部作用域),不想有就没有(全局作用域),这样才能说层叠(或者说 override)是个 feature 不是个 bug。 这样的话通过简单的编程常识就可以做到 *“既保证组件不被随意侵入,又具备覆写的权力” *。
这么想完之后我又确实觉得 CSS 整体方向是没问题的的,比如 :root :scope ,比较麻烦的是这个东西是没法 polyfill 的(我不知道 polymer 1.0 的 shady DOM 有没有做成这个 polyfill)
最后……其实你最后提到的那个我没太明白 > < ,可以详细说说