前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >如何在 React 中优雅的写 CSS

如何在 React 中优雅的写 CSS

作者头像
政采云前端团队
发布于 2019-12-20 08:20:37
发布于 2019-12-20 08:20:37
4.2K00
代码可运行
举报
文章被收录于专栏:采云轩采云轩
运行总次数:0
代码可运行

本文首发于政采云前端团队博客:如何在 React 中优雅的写 CSS https://www.zoo.team/article/react-css

引言

问题:CSS 文件分离 != CSS 作用域隔离

看下这样的目录结构:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
├── src                                  
│   ├──......                   # 公共组件目录
│   ├── components              # 组件
│   │   └──comA                 # 组件A
│   │       ├──comA.js                     
│   │       ├──comA.css                      
│   │       └── index.js                  
│   │   └──comB                 # 组件B
│   │       ├──comB.js                     
│   │       ├──comB.css                      
│   │       └── index.js                  
│   ├── routes                  # 页面模块                  
│   │   └── modulesA            # 模块A
│   │       ├──pageA.js         # pageA JS 代码
│   │       ├──pageA.css        # pageA CSS 代码

看目录结构清晰明了,由于“ CSS 文件分离 != CSS 作用域隔离”这样的机制,如果我们不通过一些工具或规范来解决 CSS 的作用域污染问题,会产生非预期的页面样式渲染结果。

假设我们在组件 A 和组件 B import 引入 comA.css 和 comB.css。

comA.css

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.title {
    color: red;
}

comB.css

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.title {
    font-size: 14px;
}

最后打包出来的结果为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.title {
    color: red;
}
.title {
    font-size: 14px;
}

我们希望,comA.css 两者互不影响,可以发现,虽然 A、B 两个组件分别只引用了自己的 CSS 文件,但是 CSS 并没有隔离,两个 CSS 文件是相互影响的!

随着 SPA 的流行,JS 可以组件化,按需加载(路由按需加载、组件的 CSS 和 JS 都按需加载),这种情况下 CSS 作用域污染的问题被放大,CSS 被按需加载后由于 CSS 全局污染的问题,在加载出其他一部分代码后,可能导致现有的页面上会出现诡异的样式变动。这样的问题加大了发布的风险以及 debugger 的成本。

小编我从写 Vue 到写 React , Vue 的 scoped 完美的解决了 CSS 的作用域问题,那么 React 如何解决 CSS 的作用域问题呢?

解决 React 的 CSS 作用域污染方案:

  • 方案一:namespaces
  • 方案二:CSS in JS
  • 方案三:CSS Modules

方案一:namespaces

“利用约定好的命名来隔离 CSS 的作用域

comA.css

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.comA .title {
    color: red;
}
.comA .……{
    ……
}

comB.css

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.comB .title {
    font-size: 14px;
}
.comB .……{
    ……
}

嗯,用 CSS 写命名空间写起来貌似有点累。

没事我们有 CSS 预处理器,利用 less、sass、stylus 等预处理器,代码依然简洁。

A.less

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.comA {
    .title {
        color: red;
    }
    
    .…… {
        ……
    }
}

B.less

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.comB {
    .title {
        font-size: 14px;
    }
    
    .…… {
        ……
    }
}

貌似很完美解决了 CSS 的作用域问题,但是问题来了,假设 AB 组件是嵌套组件。

那么最后的渲染 DOM 结构为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<div class="comA">
    <h1 class="title">组件A的title</h1>
    <div class="comB">
        <h1 class="title">组件组件的title</h1>
    </div>
</div>

comA 的样式又成功作用在了组件 B 上。

没关系,还有解,所有的 class 名以命名空间为前缀。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<div class="comA">
    <h1 class="comA__title">组件A的title</h1>
    <div class="comB">
        <h1 class="comB__title">组件组件的title</h1>
    </div>
</div>

A.less

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.comA {
    &__title {
        color: red;
    }
}

B.less

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.comB {
    &__title {
        font-size: 14px;
    }
}

如果,我们的样式还遵循 BEM (Block, Element, Modifier) 规范,那么,样式名简直不要太长!但是问题确实也解决了,但约定毕竟是约定,靠约定和自觉来解决问题毕竟不是好方法,在多人维护的业务代码中这种约定来解决 CSS 污染问题也变得很难。

方案二:CSS in JS

“使用 JS 语言写 CSS,也是 React 官方有推荐的一种方式。

从 React 文档进入

https://github.com/MicheleBertoli/css-in-js ,可以发现目前的 CSS in JS 的第三方库有 60 余种。

看两个比较大众的库:

  • reactCSS
  • styled-components

reactCSS

“支持 React 、Redux、React Native、autoprefixed、Hover、伪元素和媒体查询(http://reactcss.com/)

看下官网文档 :

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const styles = reactCSS({
  'default': {
    card: {
      background: '#fff',
      boxShadow: '0 2px 4px rgba(0,0,0,.15)',
    },
  },
  'zIndex-2': {
    card: {
      boxShadow: '0 4px 8px rgba(0,0,0,.15)',
    },
  },
}, {
  'zIndex-2': props.zIndex === 2,
})
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Component extends React.Component {
  render() {
    const styles = reactCSS({
      'default': {
        card: {
          background: '#fff',
          boxShadow: '0 2px 4px rgba(0,0,0,.15)',
        },
        title: {
          fontSize: '2.8rem',
          color: this.props.color,
        },
      },
    })
    return (
      <div style={ styles.card }>
        <div style={ styles.title }>
          { this.props.title }
        </div>
        { this.props.children }
      </div>
    )
  }
}

可以看出,CSS 都转化成了 JS 的写法,虽然没有学习成本,但是这种转变还是有一丝不适。

styled-components

“styled-components,目前社区里最受欢迎的一款 CSS in JS 方案(https://www.styled-components.com/)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const Button = styled.a`
  /* This renders the buttons above... Edit me! */
  display: inline-block;
  border-radius: 3px;
  padding: 0.5rem 0;
  margin: 0.5rem 1rem;
  width: 11rem;
  background: transparent;
  color: white;
  border: 2px solid white;
  /* The GitHub button is a primary button
   * edit this to target it specifically! */
  ${props => props.primary && css`
    background: white;
    color: palevioletred;
  `}
`
render(
  <div>
    <Button
      href="https://github.com/styled-components/styled-components"
      target="_blank"
      rel="noopener"
      primary
    >
      GitHub
    </Button>
    <Button as={Link} href="/docs" prefetch>
      Documentation
    </Button>
  </div>
)

与 reactCSS 不同,styled-components 使用了模板字符串,写法更接近 CSS 的写法。

方案三:CSS Modules

“利用 webpack 等构建工具使 class 作用域为局部。

CSS 依然是还是 CSS

例如 webpack,配置 css-loader 的 options modules: true。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        loader: 'css-loader',
        options: {
          modules: true,
        },
      },
    ],
  },
};

modules 更具体的配置项参考:https://www.npmjs.com/package/css-loader

loader 会用唯一的标识符 (identifier) 来替换局部选择器。所选择的唯一标识符以模块形式暴露出去。

示例:

webpack css-loader options

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
options: {
  ...,
  modules: {
    mode: 'local',
    // 样式名规则配置
    localIdentName: '[name]__[local]--[hash:base64:5]',
  },
},
...

App.js

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
...
import styles from "./App.css";
...
<div>
  <header className={styles["header__wrapper"]}>
    <h1 className={styles["title"]}>标题</h1>
    <div className={styles["sub-title"]}>描述</div>
  </header>
</div>

App.css

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.header__wrapper {
  text-align: center;
}

.title {
  color: gray;
  font-size: 34px;
  font-weight: bold;
}

.sub-title {
  color: green;
  font-size: 16px;
}

编译后端的 CSS,classname 增加了 hash 值。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.App__header__wrapper--TW7BP {
  text-align: center;
}

.App__title--2qYnk {
  color: gray;
  font-size: 34px;
  font-weight: bold;
}

.App__sub-title--3k88A {
  color: green;
  font-size: 16px;
}

总结

(1)如果是 ui 组件库中使用

“建议使用 namespaces 方案

原因:

  • ui 组件库维护人员基本固定,遵守约定的规范较为容易,可通过约定规范来解决不同组件 CSS 相互影响问题
  • 由于 ui 组件库会应用于整个公司的产品,在真正的业务场景中,虽然不建议,但是可能无法避免需要覆盖组件样式的特殊场景,如使用其他两种方式,不能支持组件样式覆盖

(2)如果是业务代码/业务组件中使用

“CSS in JS / CSS Modules

业务代码维护人员较多且不固定、代码水平不一致,只通过规范来约束不靠谱,无法保证开发人员严格遵守规范,不能根治 CSS 交叉影响问题,但是从 debug 角度考虑,建议组件外层都添加一个 namespaces 方面定位组件。然后加之 CSS in JS 或 CSS Modules 方案来解决 CSS 交叉影响问题。

CSS in JS 和 CSS Modules 谁优谁胜?

CSS Modules 会比 CSS in JS 的侵入性更小,CSS in JS 可以和 JS 共享变量,但个人更喜欢 CSS Modules ,但是谁优谁胜无法武断。

  • 如果你的团队还没有使用这任一技术,需要考虑的是团队成员的感受
  • 如果已经在使用其中某一种方案,保持一致性即可,相信并这样走下去

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-12-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 政采云技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
CSS Modules VS. styled-components,哪个才是解决 CSS 不足之处的更好方案?
CSS 是一门标记语言,用于元素布局及样式定义。它存在很多问题,例如书写效率和维护性低;缺乏模块机制、变量、函数等概念;容易出现全局样式污染和样式冲突等。目前前端社区存在很多解决上述问题的方案,主要包括 CSS Module以及 styled-components💅(CSS-in-JS 的代表)。 styled-components 在我的日常开发中用得很多,并且用得非常顺手。它的 CSS-in-JS 思想以及通过 props 来动态更改样式跟 React 的开发理念一脉相承,并且还基于 React Con
玖柒的小窝
2021/10/31
8.1K1
CSS Modules VS. styled-components,哪个才是解决 CSS 不足之处的更好方案?
react的css
与传统 html 标签类属性不同,react 中 class 必须编写为 className,比如
愧怍
2022/12/27
1.6K0
react的css
【React】:CSS 模块化
以下是 CSS Guidelines 中的一个示例,这个示例展示了一个问题:除了写这段代码的人,没有人知道这段代码是干什么的。
WEBJ2EE
2020/07/14
1.3K0
【React】:CSS 模块化
React 进阶 - 模块化 CSS
随着 React 项目日益复杂化、繁重化,React 中 css 面临很多问题,比如样式类名全局污染、命名混乱、样式覆盖等。这时, css 模块化就显得格外重要。
Cellinlab
2023/05/17
2K0
React 进阶 - 模块化 CSS
7. 精读《请停止 css-in-js 的行为》
styled-components 利用 ES6 的 tagged template 语法创建 react 纯样式组件。消除了人肉在 dom 和 css 之间做映射和切换的痛苦,并且有大部分编辑器插件的大力支持(语法高亮等)。此外,styled-components 在 ReactNaive 中尤其适用。
黄子毅
2022/03/14
2K0
7. 精读《请停止 css-in-js 的行为》
React基础(10)-React中编写样式CSS(styled-components)
React是一个构建用户界面的js库,从UI=render()这个等式中就很好的映射了这一点,UI的显示取决于等式右边的render函数的返回值.
itclanCoder
2020/10/17
4.5K0
在React项目中使用CSS Module
就在前几天,写了一篇CSS 20大酷刑,然后看后台数据,反馈还是挺好的,看来大家还是对这个「最熟悉的陌生人」,有种「食之无味,弃之可惜」的感觉。在上篇中,我们就说过,由于CSS庞杂的体系和令人眼花缭乱的属性,总是让人「望而却步」。但是,它也是我们翻身农奴做主人,势必要翻过的四座大山之一 CSS/Html/JavaScript/WebAsssembly。(自认为,WebAssembly也会成为一座我们需要逾越的大山,有关它的介绍,可以看我们之前写的浏览器第四种语言-WebAssembly)
前端柒八九
2023/09/10
1.6K0
在React项目中使用CSS Module
CSS Modules与Styled Components:提升CSS可维护性
CSS Modules和Styled Components都是现代Web开发中用于提升CSS可维护性的解决方案,它们通过不同的方式解决了传统CSS的一些问题,如样式冲突、命名约定和全局作用域。
天涯学馆
2024/08/17
1330
React 设计模式 0x4:样式
在每个 Web 应用程序中,样式化非常重要,因为样式使其对用户非常有吸引力,并为用户提供良好的体验。在 React 中有不同的方法来实现这一点。
Cellinlab
2023/05/17
1.3K0
React 中使用CSS
注意事项: 在正常的css中,比如background-color,box-sizing等属性,在style对象div1中的属性中,必须转换成驼峰法,backgroundColor,boxSizing。而没有连字符的属性,如margin,width等,则在style对象中不变。
grain先森
2019/03/28
1.4K0
styled-components不完全手册
大家好,我是「柒八九」。一个「专注于前端开发技术/Rust及AI应用知识分享」的Coder
前端柒八九
2024/03/25
1580
styled-components不完全手册
React组件设计实践总结03 - 样式的管理
CSS 是前端开发的重要组成部分,但是它并不完美,本文主要探讨 React 样式管理方面的一些解决方案,目的是实现样式的高度可定制化, 让大型项目的样式代码更容易维护.
_sx_
2019/08/07
7.2K0
React组件设计实践总结03 - 样式的管理
在Vite中接入现代化的CSS 工程化方案
对初学者来说,谈到开发前端的样式,首先想到的便是直接写原生 CSS。但时间一长,难免会发现原生 CSS 开发的各种问题。那么,如果我们不用任何 CSS 工程方案,又会出现哪些问题呢?
江拥羡橙
2023/11/12
1.7K0
在Vite中接入现代化的CSS 工程化方案
CSS样式组件:为什么你应该(或不应该)使用它
选择完全适合您需求的样式模块就像选择 JavaScript 框架一样困难。您的最终选择可能取决于项目的规模、公司现有的堆栈或仅仅是品味问题。如果 React 是您的框架,那么样式组件就不能从您的可能性列表中排除。Bas Bastiaans - PanCompany 的前端开发人员 - 最近从“更少”组件迁移到样式化组件,并分享了他之后经历的好处。接下来,他还讨论了在采取他所做的迁移步骤之前必须考虑的一些谈话要点。
哈德森sir
2024/05/16
1540
谈谈 CSS 预处理器
完整高频题库仓库地址:https://github.com/hzfe/awesome-interview
HZFEStudio
2021/09/26
2.6K1
react css组织的另一种选择styled-components
本文介绍了如何使用 styled-components 库来编写具有良好视觉效果和可维护性的 CSS 组件,同时介绍了该库的一些特性。
IMWeb前端团队
2018/01/08
9380
再见,CSS-in-JS
大家好,我 ssh。在过去的开发中,我一直在用 styled-component 库作为 CSS 的解决方案。它有很多优点,灵活、可复用性强、功能强大、可以接受动态 JS 变量传入组件等等…… 但今天我看到一篇文章,说都是 Spot 团队的人已经决定抛弃 CSS-in-JS 的方案了,因为对他们来说,性能损耗已经远远超过其灵活性的优势了。接下来,我来和大家分享一下这篇Why We're Breaking Up with CSS-in-JS
ssh_晨曦时梦见兮
2023/10/14
5890
再见,CSS-in-JS
技术天地 | CSS-in-JS:一个充满争议的技术方案
为了解决传统CSS在现代前端应用开发中遇到的痛点,FreeWheel评估了大量新一代的CSS框架/工具/方案。在本文中,作者以评估过程为线索,介绍了CSS-in-JS的背景、现状、开发特点和趋势。
用户6543014
2020/08/07
2.7K0
技术天地 | CSS-in-JS:一个充满争议的技术方案
[Next] 初见next.js
  Next.js 可与 Windows,Mac 和 Linux 一起使用.您只需要在系统上安装 Node.js 即可开始构建 Next.js 应用程序.如果有个编辑器就更好了
不会飞的小鸟
2019/10/01
5.2K0
[Next] 初见next.js
【说站】CSS中in JS是什么意思
1、CSS中in JS,意思就是使用js语言写css,完全不需要些单独的css文件,所有的css代码全部放在组件内部,以实现css的模块化。
很酷的站长
2022/11/24
6.3K0
【说站】CSS中in JS是什么意思
相关推荐
CSS Modules VS. styled-components,哪个才是解决 CSS 不足之处的更好方案?
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验