写点什么

ReactJS 中的 CSS 架构

  • 2017-08-15
  • 本文字数:3253 字

    阅读完需:约 11 分钟

我们生活在一个新的时代,每一天都充满了各种各样的新工具和范式。我们总是试图将旧有的架构应用在新技术上,而那样极可能以失败告终。 其中的一个例子便是 BEM—— 一个 CSS 命名约定,它解决的是那些可能不会再次出现的问题。

先来讲一讲重要的背景知识。

BEM**** 是什么?

BEM 是 CSS 的一个命名约定,遵从简单而直接的哲学:代码的一致性、伸缩性和可重用性。这个方法论正是源于它的名字:Block-Element-Modifier。这意味着所有的类会被拆分成三个实体,每一个实体在架构和代码组织上都具有不同的目的和角色。

  • 块(Block)****: 具备独立逻辑和功能的组件。
  • 元素(Element)****: 块中没有独立意义的部分。
  • 修改器(Modifier)****: 定义块或元素的行为和外观。

当讨论遵从 BEM 规范的选择器时,有以下三条规则:

  • 只使用 CSS 类选择器。
  • 类名可以包含数字但不应该包含特殊字符。
  • 使用连字符来分隔单词。

BEM 实体应该是这样的:

复制代码
/* 块的名字,也是块中元素和修改器的命名空间 */
.block
/* 块的命名空间后面紧跟下划线和元素名字 */
.block__element
/* 块或者元素的命名空间后紧跟连字符和修改器的名字 */
.block--modifier,
.block__element--modifier

为什么要使用BEM

BEM 哲学的提出基于以下几个前提:代码的一致性、代码的伸缩性、代码的可重用性、生产力和团队协作。从 BEM 的哲学出发,不得不说 BEM 是非常好的范例,并且已经在全球范围内被来自大公司(如 Google 和 Twitter)的许多开发者所采用。

如果想要了解关于这个方法论更多的信息,可以阅读这篇文章: CSS Architectures

让我们开始吧

当谈到代码的命名规范和代码结构时,不得不提到 BEM。BEM 很简单并且功能完善。然而,当谈论到 CSS 架构时还有另外一点必须考虑,那就是目录结构。于是我们不得不提到另一种架构:ITCSS

ITCSS 是由 Harry Roberts 提出的一个方法论,用于创建、管理和衡量大型的 CSS 项目。他曾说:

ITCSS__ 是一种方法论,旨在将整个 __CSS__ 项目可视化为一个分层的倒置三角形。这种分层架构代表了一个模型,可以帮助你以最有效、最节省资源的方式使用 __CSS_。_

本文不会深入探讨这个方法论,不过我们推荐阅读 Harry 的文章以掌握其背后蕴含的概念。简而言之,ITCSS 主张以分层的方式组织代码,以倒三角的方式组织结构,这样我们就可以在顶层定义通用元素,在底部定义特定元素。

这里的关键在于我们可以使用分层的方式作为一种有效的目录结构来组织代码。在我之前的经验中,我所使用的方法与其提出的原始目的有一点不同,我会用以下的方式对代码进行分层:

  • Settings: 基本配置和变量。
  • Tools: 函数和 mixins。
  • Base: 应用到每一个页面的基本样式。在这里放置 reset/normalize 的代码最好不过了。
  • Components: 组成界面的 UI 组件。
  • Utilities: 非常具体的规则,这是唯一可以使用!important 的层。

现在我们需要做的事情是混合这两个方法,然后一个强大且简单的 CSS 架构便唾手可得。

ReactJS**** 的方式

在过去几年中,BEM+ITCSS架构满足了我们所有的需求,直到一切都开始发生变化。当 ReactJS 成为主要的单页面应用库,以组件化进行思考的方式较以前便有些不同。现在,每一个组件是一个 JS 模块,并且每个模块中的 HTML 结构完全关联该组件,并且通过自定义属性可以动态变更组件状态和变量。不再需要将样式标签与语义化的 HTML 结构关联起来,现在你可以创建完全逻辑化的动态功能性组件。

所以在新的场景下我们怎样处理样式和代码结构呢?保持样式和 React 组件相分离,使用 BEM+ITCSS 方法,或者彻底改为使用CSS-in-JS方式?我会建议介于这两者之间,并且利用我们之前所积累的知识。

Think-Adapt-First**** 方式

使用这些方法论和命名约定的想法源于以下原因:保持样式隔离、创建具有唯一性的选择器并在组件作用域内理清选择器之间的关系。人们使用BEM约定并不是因为他们喜欢使用双下划线或双连字符,而是因为 BEM 有助于提升代码的一致性、伸缩性、可重用性、生产力和可预测性。这些都是可行性的前提,所以为什么不一直用它呢?

因为我们不能。当我们决定在项目中引入React时架构发生了改变。于是,一些限制、模式和新的可能性出现了。这是将我们以前的规则应用于新环境的最佳时机。下面是我强烈推荐给你的工具。

CSS**** 模块

为了说明 CSS 模块的所有优势和功能,我想引用其作者 Glen Maddern 的话。除了它能够带来成堆的好处,最主要的就是CSS**** 本地作用域。现今,所有的 React 组件都可以在逻辑和呈现状态上进行完全的隔离。下面是代码结构的直观显示:

在 style.css 中不再需要保持经典的 BEM 约定。依据 BEM 约定,我们应该将第一个实体作为组件的命名空间,但是现在有了 CSS 模块,这种关系会基于 JS 组件名进行动态的创建。

复制代码
/*
* Reset
*/
.button {
appearance: none;
border: 0;
background-color: white;
cursor: pointer;
color: #333;
font-size: .9rem;
font-weight: bold;
}
.button:focus,
.button:focus:hover {
border-color: #51a7e8;
box-shadow: 0 0 5px rgba(81, 167, 232, .5);
outline: 0;
}
/*
* Sizes
*/
.small {
padding: .5em 1.4em;
}
.medium {
padding: .8em 1.4em;
}
.large {
padding: 1.2em 2.2em;
}
/*
* Themes
*/
.default {
border: 1px solid #ddd;
border-radius: 3px;
background: linear-gradient(to bottom, #fefefe 0%, #ddd 100%);
}
.default:hover {
border-color: #bbb;
background: #ddd;
}
.default:active {
border-color: #aaa;
background: linear-gradient(to bottom, #bbb 0%, #ddd 44%);
}

按照规则,你的组件中应只包含需要的类。我们可以通过下面的方式来描述一个按钮:

复制代码
import PropTypes from 'prop-types'
import React from 'react'
import styles from './styles.css'
export const ButtonType = {
BUTTON: 'button',
RESET: 'reset',
SUBMIT: 'submit',
}
export const ButtonTheme = {
DEFAULT: 'default',
POSITIVE: 'positive',
DANGER: 'danger',
}
export const ButtonSize = {
SMALL: 'small',
MEDIUM: 'medium',
LARGE: 'large',
}
const Button = ({ type, onClick, children, theme, size }) => {
const className = `${styles.button} ${styles[theme]} ${styles[size]}`
return ({children})
}
Button.propTypes = {
type: PropTypes.oneOf(Object.keys(ButtonType)),
theme: PropTypes.oneOf(Object.keys(ButtonTheme)),
size: PropTypes.oneOf(Object.keys(ButtonSize)),
onClick: PropTypes.func.isRequired,
children: PropTypes.node.isRequired,}
Button.defaultProps = {
type: ButtonType.BUTTON,
theme: ButtonTheme.DEFAULT,
size: ButtonSize.MEDIUM,
}
export default Button

好的,下面我们给出组件分层的解决方案。那么如何定义全局样式呢,比如设置、规范化和重置?

ITCSS**** 复活

既然基于 ITCSS 的分层目录结构仍然可以完美匹配我们的需求,那么为什么不继续使用它呢?

上面的想法是在src**** 目录中创建与 ITCSS 同风格的样式文件目录,除了组件的文件目录外,因为 React 已经默认定义了组件的文件目录结构。

现在,我们会得到下面的目录结构:

我们可以使用:global标签在主应用程序中导入样式文件,样式可以作为全局的类来使用。

再应用Think-Adapt-First方式

该结构背后的理念是通过以一种可伸缩的方式保持CSS**** 架构创建更好的 ReactJS 项目,可以支持成千上万的组件和开发人员协同工作。

然而本文的真正关键点在于打开你的思维,去适应新事物!有时候适应是很困难的,因为对于难以掌控的事物,你必须放手,但是请不要忘记,你已经解决的问题可能将以一去不复返。

所以,年轻的朝圣者们,请持续探索知识。

查看英文原文 CSS Architecture with ReactJS


感谢薛命灯对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2017-08-15 19:004651

评论

发布
暂无评论
发现更多内容

问:React的setState为什么是异步的?

beifeng1996

前端 React

可观测指标管理体系建设落地及插件功能设计和生态打造

嘉为蓝鲸

可观测 自动化运维 嘉为蓝鲸

开发者体验:现代企业架构的关键一环

SEAL安全

平台工程 企业号 3 月 PK 榜 开发者体验

CutLER:更好地训练无监督识别模型

Zilliz

从一次CPU打满到ReDos攻击和防范

京东科技开发者

正则表达式 Web 企业号 3 月 PK 榜 ReDoS

前端必会react面试题

beifeng1996

前端 React

浅析大促备战过程中出现的 fullGc,我们能做什么?

京东科技开发者

JVM 内存 GC java 企业号 3 月 PK 榜

Vue的computed和watch的区别是什么?

bb_xiaxia1998

Vue 前端

前端一面常见vue面试题合集

bb_xiaxia1998

Vue 前端

山东大学数字图像处理实验:MATLAB的图像显示方法

timerring

数字图像处理

Python:Excel自动化实践入门篇 乙【送图书活动继续】

eng八戒

Python Excel Python自动化办公

“堆内存持续占用高 且 ygc回收效果不佳” 排查处理实践

京东科技开发者

前端 堆内存 回收器 JavaScrip 企业号 3 月 PK 榜

推荐系统[四]:精排-详解排序算法LTR (Learning to Rank)_ poitwise, pairwise, listwise相关评价指标,超详细知识指南。

汀丶人工智能

自然语言处理 推荐系统 搜索算法

干货 | 中小型金融企业该如何进行灾备建设?

嘉为蓝鲸

金融 自动化运维 嘉为蓝鲸 灾备建设

不要因为这件小事,让你的网站在危险中“狂飙”

嘉为蓝鲸

自动化运维 weops 嘉为蓝鲸

重磅福利!阿里云机器学习平台PAI+AI开源项目测评来啦

阿里云大数据AI技术

AI

云原生可观察性工具泛滥的思考

HummerCloud

云原生 可观察性

新一代通信协议—— RSocket

老周聊架构

响应式编程 2月月更 rsocket

Vue.$nextTick的原理是什么-vue面试进阶

bb_xiaxia1998

Vue 前端

企业号 3 月 PK 榜,火热开启!

InfoQ写作社区官方

热门活动 企业号 3 月 PK 榜

直播 | StarRocks 实战系列第三期--StarRocks 运维的那些事

StarRocks

数据库 开源 运维

Switchquery:移动端秒级配置触达平台

京东科技开发者

App 配置原理 用户触达 企业号 3 月 PK 榜

如何快速理解事务隔离

Dinfan

数据库 innodb 事务隔离

前端常见vue面试题(必备)

bb_xiaxia1998

Vue 前端

网络性能总不好?网络调优专家AOE帮你来“看看”

华为云开发者联盟

人工智能 华为云 网络性能 华为云开发者联盟 企业号 3 月 PK 榜

还不知道线程池的好处,快来了解一下

华为云开发者联盟

开发 华为云 华为云开发者联盟 企业号 3 月 PK 榜

顶层设计出台 浪潮云破局再生长丨与千行百业扬帆数字蓝海

云计算

美团前端常见react面试题(附答案)

beifeng1996

前端 React

老生常谈React的diff算法原理-面试版

beifeng1996

前端 React

基于头肩部检测的过线客流统计

华为云开发者联盟

人工智能 华为云 华为云开发者联盟 企业号 3 月 PK 榜

MASA MAUI Plugin (九)Android相册多选照片(使用Android Jetpack套件库)

MASA技术团队

.net MASA MAUI

ReactJS中的CSS架构_语言 & 开发_Douglas Gimli_InfoQ精选文章