写在前面
问:什么是Scoped CSS规范?
Scoped CSS规范是Web组件产生不污染其他组件,也不被其他组件污染的CSS规范。
面对组件化的普及,组件的复用很普遍的需求,然而CSS相互污染是经常遇见的问题,建立规范让开发者放心使用各种组件,甚至跨生态的组件是很有必要的一件事情。
目前业界的一些方案
方案一:
如果用webpack的话,可以参考css-loader的这个功能:
一段hash + 组件名,这个可能兼顾了辨识度 + 命名污染的问题。
方案二:
用webpack和scss,less写成模块化css就可以一定程度避免CSS污染,不能完全避免
方案三:样式规范上,使用与组件同名的嵌套命名空间
如果只用自己的生态可以这么搞,但是有的时候会引入第三方生态,第三方和自己的命名空间一样还是很有可能,比如scroller插件,社区里也有很多scroller插件loading uplader插件等等。
现有方案的局限性
这里还是会有污染的情况,因为:
- 模块化的粒度是大于等于组件化粒度,意思就是一个模块可能有多个组件
- 非less和sass项目下的组件怎么保证
- 难以保证不污染第三方组件
- 难以保证不被第三方组件污染
- 同名组件的问题
- 组件在第三方项目使用的问题
- 组件自身生态闭环的问题
所以得出:
用意念或者规范约定不然注入程序自动化避免冲突
好处:
- 能保证不污染别的组件并且不被被的组件污染可以更放心的复用
- Scoped CSS规范是运行时产生唯一id~~ 永远不会css碰撞
- 返回的这个id那个指定给组件的顶层div就行,实施简单
如果把这个过程放在构建过程就是工程问题。但是组件单独抽离出来给第三方用,其实就是组件本身的问题。总之要保证:
- 不污染第三方的项目或组件
- 不被第三组件或项目污染(由于是层叠样式,这个无法完全保证)
Scoped CSS代码
;(function () {
function scoper(css) {
var id = generateID();
var prefix = "#" + id;
css = css.replace(//*[sS]*?*//g, '');
var re = new RegExp("([^
,{}]+)(,(?=[^}]*{)|s*{)", "g");
css = css.replace(re, function(g0, g1, g2) {
if (g1.match(/^s*(@media|@keyframes|to|from|@font-face)/)) {
return g1 + g2;
}
if (g1.match(/:scope/)) {
g1 = g1.replace(/([^s]*):scope/, function(h0, h1) {
if (h1 === "") {
return "> *";
} else {
return "> " + h1;
}
});
}
g1 = g1.replace(/^(s*)/, "$1" + prefix + " ");
return g1 + g2;
});
addStyle(css,id+"-style");
return id;
}
function generateID() {
var id = ("scoped"+ Math.random()).replace("0.","");
if(document.getElementById(id)){
return generateID();
}else {
return id;
}
}
var isIE = (function () {
var undef,
v = 3,
div = document.createElement('div'),
all = div.getElementsByTagName('i');