前言
在项目开发中,如何选择书写css的方式是非常重要的,一般有以下的规则:
- 灵活:体现在可以编写动态的css
- 可控范围:体现在书写的样式可以局限在局部组件,不会污染到外部
- 简洁
- 特性支持:支持css的新特性,例如动画、选择器、媒体查询等
下面就让我们一起来看看在vue和react中引入css的方式:
Vue
引入外部css文件
index.scss
.error {
font-size: 24px;
color: red
}
index.vue
@import 'index.scss'
<div class='.error'>
This is an error message!
</div>
组件内写css
<style lang='less' scoped>
.error {
font-size: 24px;
color: red
}
</style>
因为vue单文件有style标签编写样式,使用lang来设置预处理器,使用scoped来决定局部生效
使用这种方式时有一个注意点:因为我们为了不让组件的样式影响其他组件样式,都会在style标签中添加scoped,这样组件中的样式就只适用于本组件而不会影响其他组件,这样我们就不能修改到第三方组件样式,这个问题有以下解决方法:
- 写一个全局CSS文件,将这个文件引入到入口文件中,或者也可以直接在入口文件中写
common.css
.modify {
color: blue
}
App.vue
@import 'common.css'
<div id='app'>
</div>
这种做法是在全局将所有的组件中的第三方组件的样式都修改了,那么如果我们想要单独修改某个组件中的第三方组件的样式呢?那么需要采用下面这种做法:
-
使用CSS拓展语言stylus/sass/less等进行样式透穿
- stylus中使用
>>>
.wrapper >>> .swiper-container { background-color: blue }- sass / less中使用
/deep/
.wrapper /deep/ .swiper-container{ background-color: blue } - stylus中使用
React
在react中,引入css就不如vue简洁,有以下的集中方式:
Inline Styles
import React, { Component } from 'react'
const div = {
backgroundColor: blue
}
class App extends Component {
render() {
return (
<div>
<div className='div'>Test</div>
<div style={{backgroundColor: 'blue'}}>Test</div>
</div>
)
}
}
- 优点:
- 有利于动态获取状态来更改样式
- 使用内联样式书写,避免样式冲突和污染外部
- 缺点:
- 必须使用驼峰
- 有些特性不支持,例如伪类、伪元素
- 不利于复用样式
CSS in JS
对于网页开发来说,应该满足“关注点分离”,即:
- HTML语言:负责网页的结构,又称语义层
- CSS 语言:负责网页的样式,又称视觉层
- JavaScript 语言:负责网页的逻辑和交互,又称逻辑层或者交互层
也就是说不要写行内样式和行内脚本,例如
<div style="color:blue">
Hello
</div>
但是在react出现后,这种情况就发生了改变。因为react强调组件的概念,会强制把HTML、CSS、JS写在一起。
import React, {Component} from 'react'
const style = {
color: 'red'
}
class App extends Component {
render() {
return(
<div style={style}>Hello</div>
)
}
}
但是,这样有助于组件的相互隔离,低耦合,使得组件的复用性高。
其实,React 的这种写法是使用 JS 写 HTML 和 CSS,React 在 JS 实现了对 HTML 和 CSS 的封装,我们通过封装去操作 HTML 和 CSS。
但是,由于 React 对 CSS 的封装比较弱,所以出现了许多第三方库来加强 React 的 CSS 操作,统称为CSS in JS。以下列举了一些常用的库:
styled-components
const Button = styled.button`
/* Adapt the colors based on primary prop */
background: ${props => props.primary ? "palevioletred" : "white"};
color: ${props => props.primary ? "white" : "palevioletred"};
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
render(
<div>
<Button>Normal</Button>
<Button primary>Primary</Button>
</div>
);
-
优点
- 样式写在js文件中,降低js对css文件的依赖
- 样式灵活,可以使用变量
- 开箱即用,不需要配置webpack
- 查找样式方便,因为用styled-components定义的组件是一个JS变量,可以很容易地在定义和使用的地方之间相互跳转
-
缺点
-
css和js一起写,比较混乱
-
标签名不能一样看出,也额外增加了标签变量
-
生成的className是随机字符串,不方便debug (安装babel-plugin-styled-components解决这个问题)
-
styled-components每次渲染都会重新计算cssRule,并且计算出新的className,如果样式表中还没有对应的className,则会插入到样式表中,所以会产生很多冗余的样式
- 举个例子:
const Button = styled.button` color: red; font-size: 16px; background: ${props => props.active ? 'pink' : 'blue'}; `; // active 切换时会生成两个类名 .sfDSDA { color: red; font-size: 16px; background: pink; } .eFDFER { color: red; font-size: 16px; background: blue; }因此也不推荐用来实现动画,如果动画值通过props传入,则会生成很多样式,造成性能降低
-
样式需要使用js来书写,不利于缓存
-
Emotion
JSS
tailwindcss / Windi CSS
-
优点
- 相当于在写原子类,可以按需生成CSS,节省代码体积
- 解决了样式冲突问题
-
缺点
- 有时候样式很多的时候,会在className上面会留下很长的一段字符串,比较丑
- 记忆成本比较高,记不住要查官网,花费时间
CSS Modules
style.css
.className {
color: blue
}
App.tsx
import style from "./style.css"
// import { className } from "./style.css"
element.innerHTML = '<div class={style.className}/>'
-
优点:
- 通过编译生成全局唯一的类名,不用担心冲突
- 写样式扁平,不需要嵌套
-
缺点
- 语法比较定制,需要学习成本
Sass / Less / Stylus / PostCSS
这些是CSS预处理器
-
优点
- 类名容易冲突。为了解决冲突需要自己写嵌套,但是结构容易越写越深
-
缺点
- 从CSS找组件困难,删出完一出组件后,不太敢删对应样式,怕别处也用到,没有安全感
- 组件找 CSS 也困难,有时会不知道对应样式写在哪
- 样式写法定制,需要学习时间