引入CSS的方式

235 阅读5分钟

前言

在项目开发中,如何选择书写css的方式是非常重要的,一般有以下的规则:

  1. 灵活:体现在可以编写动态的css
  2. 可控范围:体现在书写的样式可以局限在局部组件,不会污染到外部
  3. 简洁
  4. 特性支持:支持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
    }
    

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 也困难,有时会不知道对应样式写在哪
    • 样式写法定制,需要学习时间

参考文章