Facebook’s challenges are applicable to any very complex websites with many developers. Or any situation where CSS is bundled into multiple files and loaded asynchronously, and often loaded lazily. ——@vjeux 将Facebook换成Tencent同样适用。
同行们是怎么解决的?
- Shadow DOM Style
Shadow DOM的样式是完全隔离的,这就意味着即使你在主文档中有一个针对全部 <h3>
标签的样式选择器,这个样式也不会不经你的允许便影响到 shadow DOM 的元素。
举个例子:
<body>
<style>
button {
font-size: 18px;
font-family: ‘华文行楷‘;
}
</style>
<button>我是一个普通的按钮</button>
<div></div>
<script>
var host = document.querySelector(‘div‘);
var root = host.createShadowRoot();
root.innerHTML = ‘<style>button { font-size: 24px; color: blue; } </style>‘ +
‘<button>我是一个影子按钮</button>‘
</script>
</body>
这就很好地为Web Component
建立了CSS Namespace机制。
- Facebook: CSS in JS
http://blog.vjeux.com/2014/javascript/react-css-in-js-nationjs.html
比较变态的想法,干脆直接不要用classname,直接用style,然后利用js来写每个元素的style……
例如,如果要写一个类似button:hover
的样式,需要写成这样子:
var Button = React.createClass({
styles: {
container: {
fontSize: ‘13px‘,
backgroundColor: ‘rgb(233, 234, 237)‘,
border: ‘1px solid #cdced0‘,
borderRadius: 2,
boxShadow: ‘0 1px 1px rgba(0, 0, 0, 0.05)‘,
padding: ‘0 8px‘,
margin: 2,
lineHeight: ‘23px‘
},
depressed: {
backgroundColor: ‘#4e69a2‘,
borderColor: ‘#1A356E‘,
color: ‘#FFF‘
},
},
propTypes: {
isDepressed: React.PropTypes.bool,
style: React.PropTypes.object,
},
render: function() {
return (
<button style={m(
this.styles.container,
// 如果压下按钮,mixin压下的style
this.props.isDepressed && this.styles.depressed,
this.props.style
)}>{this.props.children}</button>
);
}
});
几乎等同于脱离了css,直接利用javascript来实现样式依赖、继承、混入、变量等问题……当然如果我们去看看React-native和css-layout,就可以发现,如果想通过React打通客户端开发,style几乎成了必选方案。
我们的方案
我们期望用类似
Web Component
的方式去写Component的样式,但在低端浏览器根本就不支持Shadow DOM
,所以,我们基于BEM来搭建了一种CSS Namespace的方案。
我们的Component由下面3个文件组成:
- main.html 结构
- main.js 逻辑
- main.css 样式
可参考:https://github.com/miniflycn/Ques/tree/master/src/components/qtree
可以发现我们的css是这么写的:
.$__title {
margin: 0 auto;
font-size: 14px;
cursor: default;
padding-left: 10px;
-webkit-user-select: none;
}
/** 太长忽略 **/
这里面有长得很奇怪的.$__
前缀,该前缀是我们的占位符,构建系统会自动将其替换成Component名,例如,该Component为qtree,所以生成结果是:
.qtree__title {
margin: 0 auto;
font-size: 14px;
cursor: default;
padding-left: 10px;
-webkit-user-select: none;
}
/** 太长忽略 **/
同样道理,在main.html
和main.js
中的对应选择器,在构建中也会自动替换成Component名。
这有什么好处呢?
- 基于路径的Namespace,路径没有冲突,那么在该项目中Namespace也不会冲突
- Component可以任意改名,或复制重构,不会产生任何影响,便于Component的重构和扩展
- Component相对隔离,不会对外部产生影响
- Component非绝对隔离,外部可以对其产生一定影响