AI实践哪家强?来 AICon, 解锁技术前沿,探寻产业新机! 了解详情
写点什么

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:004954

评论

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

世界顶级Linux技术大神,耗时一年力作1300页Linux开发实战

Java 程序员 后端

15个问题自查真的了解java编译优化吗

华为云开发者联盟

Java 编译 对象 语义 符号表

一篇文章带你深入了解MySQL 索引相关,linux视频教程下载

Java 程序员 后端

一线互联网大厂面经分享:阿里三面+头条四面(1),java基础入门第二版电子版

Java 程序员 后端

不是吧阿sir!System,java面试问项目中遇到的技术难点

Java 程序员 后端

为了进大厂,我深扒了阿里字节等大厂面经,总结了50道必考题

Java 程序员 后端

不是吧工作3年你都不知道这份超详细JVM内存结构,怎么涨薪?

Java 程序员 后端

两年半,50W的offer,三本,springboot运行原理生命周期

Java 程序员 后端

七、Redis持久化的两种方式RDB和AOF理解,mybatis接口实现原理

Java 程序员 后端

上线GitHub七天后就标星87,并发知识体系大全

Java 程序员 后端

不是吧阿sir,你这计算机网络也太熟了,震惊面试官一整年

Java 程序员 后端

一篇神文让你“一夜封神“Mycat 中间件 (最详细讲解),linux操作系统实用教程文东戈课后答案

Java 程序员 后端

不是吧阿sir,你这业务太熟了吧,震惊面试官第八年,献给真心想学Java的打工人

Java 程序员 后端

三年Java开发经验,四面阿里成功斩获offer,分享面经,java面试问项目部署

Java 程序员 后端

不是吧工作3年你都不知道这份超详细JVM内存结构,怎么涨薪?(1)

Java 程序员 后端

不能错过的分布式ID生成器(Leaf-),积累总结

Java 程序员 后端

两道面试题,带你解析Java类加载机制,零基础也能看得懂

Java 程序员 后端

一见面就脱裤子?这份Spring Cloud微服务笔记应对面试怎么这么骚?

Java 程序员 后端

三面阿里被灵魂追问,出门就被Java面试官逼哭!,java虚拟机的运行原理

Java 程序员 后端

三年Java开发每天增删改查,终于靠着这份面试题,成功上岸京东

Java 程序员 后端

世界顶级SQL技术专家呕心沥血半年才整理出这份:SQL优化核心思想笔记,手慢无

Java 程序员 后端

业务中台的困境、及可能的解,java基础笔试题判断题

Java 程序员 后端

两年Java开发经验,混迹“中浩科技,java全套百度云视频

Java 程序员 后端

为了你们不错过金三银四,我真是操碎了心!RabbitMQ面试真题来了

Java 程序员 后端

明道云在保险经纪公司中的应用场景例举

明道云

一篇文章!彻底弄透Java处理GMT-UTC日期时间,java百度天气接口api

Java 程序员 后端

一辈子也不容错过学习的微服务网关与用户身份识别,Zuul过滤器

Java 程序员 后端

三面美团Java岗,HR现场直接发offer,他是横着走出来的

Java 程序员 后端

丹丹学妹哭着对我说:学长,JVM如何实现动态类型语言支持的呢

Java 程序员 后端

一线互联网大厂面经分享:阿里三面+头条四面,Java面试心得必备技能储备详解

Java 程序员 后端

三、Redis在SpringBoot中使用案例,java程序员面试笔试真题与解析

Java 程序员 后端

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