前端项目中css管理方案

417 阅读3分钟

众所周知,CSS 根据选择器名称去全局匹配元素,它没有作用域可言,比如你在页面的两个不同的地方使用了一个相同的类名,先定义的样式就会被覆盖掉。CSS 一直缺乏模块化的概念,命名冲突的问题会持续困扰着你。每次定义选择器名称时,总会顾及其他文件中是否也使用了相同的命名,这种影响在组件开发中尤为明显。(mp.weixin.qq.com/s/v0IB2mZHr…

相对应的就诞生了几种解决方案:

  • CSS 命名方法论:通过人工的方式来约定命名规则
  • CSS Modules:一个 CSS 文件就是一个独立的模块。
  • CSS-in-JS:在 JS 中写 CSS。

CSS 命名方法论

共同的特点—为选择器增加冗长的前缀或后缀,并试图通过人工的方式来生成全局唯一的命名

.card {
  &__head {}
  &__menu {
    &-item {
      &--active {}
      &--disable {}
    }
  }
  &__body {}
  &__foot {}
}

CSS Modules

基于上面这种手写命名前缀后缀的方式,诞生的css模块化方案

CSS Modules 允许我们像 import 一个 JS Module 一样去 import 一个 CSS Module。每一个 CSS 文件都是一个独立的模块,每一个类名都是该模块所导出对象的一个属性。通过这种方式,便可在使用时明确指定所引用的 CSS 样式。并且,CSS Modules 在打包时会自动将 id 和 class 混淆成全局唯一的 hash 值,从而避免发生命名冲突问题。(www.ruanyifeng.com/blog/2016/0…

CSS Modules 特性:

  • 作用域:模块中的名称默认都属于本地作用域,定义在 :local 中的名称也属于本地作用域,定义在 :global 中的名称属于全局作用域,全局名称不会被编译成哈希字符串
  • 命名:对于本地类名称,CSS Modules 建议使用 camelCase 方式来命名,这样会使 JS 文件更干净,即 styles.className
  • 组合:使用 composes 属性来继承另一个选择器的样式
  • 变量:使用 @value 来定义变量,不过需要安装 PostCSS 和 postcss-modules-values 插件。

CSS-in-JS

对于 HTML,衍生了 JSX 这种 JS 的语法扩展,可以将其理解为 HTML-in-JS;对于 CSS,衍生出一系列的第三方库,用来加强在 JS 中操作 CSS 的能力,它们被称为 CSS-in-JS。

Emotion:

  • 不用关心繁琐的 Class 命名规则
  • 不用担心样式被覆盖
  • 便利的样式复用(样式都是 js 对象或字符串)
  • 代码共享,轻松在 JS 和 CSS 之间共享常量和函数
  • 组件化思考模式,不再需要维护一堆样式表。CSS-in-JS 将 CSS 模型抽象到组件级别,而不是文档级别(模块化)。
  1. Object Styles 和 String Styles
// yarn add @emotion/react @emotion/styled

// object styles
import { jsx } from '@emotion/react'
render(
  <div
    css={{
      backgroundColor: 'hotpink',
      '&:hover': {
        color: 'lightgreen'
      }
    }}
  >
    This has a hotpink background.
  </div>
)

// string styles
import { jsx, css } from '@emotion/react'
const paragraph = css`
  color: turquoise;
  a {
    border-bottom: 1px solid currentColor;
    cursor: pointer;
  }
`
render(
  <p css={paragraph}>
    Some text.
    <a>A link with a bottom border.</a>
  </p>
)
  1. Styled Components 基础用法 Styled Components 导出了一些带有 html 标签的内置组件
import styled from '@emotion/styled'
let SomeComp = styled.div({
  color: 'hotpink'
})
let AnotherComp = styled.div`
  color: ${props => props.color};
`
render(
  <SomeComp>
    <AnotherComp color="green" />
  </SomeComp>
)

//  props 传递
import styled from '@emotion/styled'
const Button = styled.button`
  color: ${props =>
    props.primary ? 'hotpink' : 'turquoise'};
`
const Container = styled.div(props => ({
  display: 'flex',
  flexDirection: props.column && 'column'
}))
render(
  <Container column>
    <Button>This is a regular button.</Button>
    <Button primary>This is a primary button.</Button>
  </Container>
)

组件化做到了极致,自然形成了将HTML、CSS、JavaScript集中编写管理的方式

CSS Modules 与 styled-components 是两种截然不同的 CSS 模块化方案,它们最本质的区别是:前者是在外部管理 CSS,后者是在组件中管理 CSS。

扩展: 在 Vue 中编写 CSS 的姿势:使用 Scoped CSS,为 区块添加 scoped 属性即可开启组件样式作用域(Scoped CSS)

<template>
  <header class="header">header</header>
</template>

<style scoped>
.header {
  background-color: green;
}
</style>

// 编译之后
<header class="header" data-v-5298c6bf>header</header>

<style>
.header[data-v-5298c6bf] {
  background-color: green;
}
</style>