持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第15天,点击查看活动详情
主要讲当前的几种css场景, css-in-js 概括、优缺点、使用场景、常见库(emotion)里面源码的大致实现。
css命名方法
- BEM、模块名__元素名--修饰器名
- OOCSS、面对对象,将元素样式抽象分成多个独立的小型样式类、
- ITCSS,
- SMACSS
css modules
一个css文件就是一个独立的模块,通过组件名的唯一性代表选择器的唯一,保证样式不会污染到组件外
每一个类名都是该模块导出对象的一个属性,打包时自动将id和class混淆成全局唯一的hash避免冲突
import styles from './xx.module.less'
<p className={styles.p}>
css-in-js
因为组件化概念,html、js、css写在了一起
react对于html,出现了jsx,即html-in-js
对于css,同样出现了css-in-js
最流行的库有
styled-components、emotion
-
案例 material-ui
-
优点
1、让css拥有独立的作用域,实现局部样式,防止样式冲突
2、避免无用的css样式堆积
3、重要的css放头style标签里,其他的异步加载减少渲染阻塞
4、通过组件状态动态生成样式
5、让组件能更好的移植和复用
- 缺点
1、陡峭的学习曲线
2、运行时消耗
可读性差
没有统一的业界标准
特点连贯总结:
有独立作用域,不会样式冲突,但是hash生成的类名可读性差
由于跟着组件异步加载,可以避免无用的css样式堆积,可以把重要的css样式放在头style标签里,其他的通过异步加载减少渲染堵塞,根据组件状态动态加载样式,但会运行时消耗。
让组件有更好的移植和复用,但有陡峭的学习曲线,也暂时没有统一的业界标准(istf制定中)。
- 选型
功能简单,重视代码可读性和维护性不用
逻辑复杂,重视封装和移植可以用。
emotion/css
通过生成唯一的css选择器来达到css局部作用域的效果
安装:npm i @emotion/css -save
使用:
import {css} from '@emotion/css'
const className = css`
color:red;
`
function App(){
return <div className={className}>app</div>
}
渲染:
<style data-emotion='css' data-s>.css-lqvvwil{color:red;}</style>
<div class='css-lqvvwil'>
app
</div>
模板字符串的特性复习
es6.ruanyifeng.com/?search=Ref…
let a = 5;
let b = 10;
tag`Hello ${ a + b } world ${ a * b }`;
// 等同于
tag(['Hello ', ' world ', ''], 15, 50);
tag函数的第一个参数是一个数组,该数组的成员是模板字符串中那些没有变量替换的部分。其他参数都是模板字符串各个变量被替换后的值
基础实现
以上面的例子为例
css模板字符串需要实现的是:
1.拿到
color:red;,生成hash2.在head新加style标签,注入hash类和
color:red;3.返回hash
代码
// args[0] = ['color:red;]
function css(...args) {
// 用 模板字符串传的东西转成 classname和styles
const serialized = serializeStyles(args);//{name:'名字',styles:'color:red;'}
// 将东西插入head作为style标签
insertStyles(serialized);
//返回 classname 给元素安排上
return 'css-' + serialized.name;
}
function serializeStyles(args, props) {
const strings = args[0];//color:red;
let styles = strings
const name = hashString(styles);
return {
name,
styles
};
}
// 转16进制,截前7位当hash
function hashString(keys) {
let val = 10000000;
for (let i = 0; i < keys.length; i++) {
val += keys.charCodeAt(i);
}
return val.toString(16).slice(0, 7);
}
// 插入style标签
function insertStyles(serialized) {
const className = 'css-' + serialized.name;//类名
const rule = `.${className}{${serialized.styles}}`;
const style = document.createElement('style');
style.setAttribute('data-emotion', 'css');//没有什么用
style.appendChild(document.createTextNode(rule));//style.innerHTML = rule;
document.head.appendChild(style);
}
传入对象
css({
color:'red'
})
实现过程:
需要在原先的基础上判断传入的是否是对象,可以通过判断是否有
strings.raw,有即代表是模板字符串将属性和值拼起来
其他的步骤一样
代码
const strings = args[0];
let styles = ''
if (strings.raw === undefined) {//说明传的是对象
for (const key in strings) {
string += (key + ":" + obj[key] + ";");
}
}
还有种 emotion/react,等下一期说