穷尽一生,一事无成是常态,更是这个世界上99%的人真实写照
大家好,我是柒八九。
前言
就在前几天,写了一篇CSS 20大酷刑,然后看后台数据,反馈还是挺好的,看来大家还是对这个最熟悉的陌生人,有种食之无味,弃之可惜的感觉。在上篇中,我们就说过,由于CSS
庞杂的体系和令人眼花缭乱的属性,总是让人望而却步。但是,它也是我们翻身农奴做主人,势必要翻过的四座大山之一 CSS/Html/JavaScript/WebAsssembly
。(自认为,WebAssembly
也会成为一座我们需要逾越的大山,有关它的介绍,可以看我们之前写的浏览器第四种语言-WebAssembly)
而,今天我们讲点轻松的东西,内容有点少,可以在茶余饭后,当个配菜来品尝。
在React
中,CSS模块(CSS Module
)只是一个.css
文件,类似于JavaScript中的局部变量。它减少了React
样式的全局作用域。此外,它是一种通过生成一个随机字符串
作为className
名称并添加一个唯一的哈希来使每个className
都唯一的工具,从而防止和全局作用域冲突。我们可以使用CSS模块
来防止CSS类的命名冲突。只需将CSS模块
文件导入到我们的组件中,就可以在各种CSS
文件中使用相同的CSS类
。
任何CSS
文件都可以安全地更新,而无需担心会影响其他页面,因为它只具有局部作用域,只能影响使用了更改后的CSS模块
文件的其他组件。当使用CSS模块
在浏览器中呈现时,它会生成随机的CSS
类,只有在仔细检查页面时才可见。
你能所学到的知识点
- 前置知识点
- CSS模块的红与黑
- CSS模块使用语法
- 创建一下CSS模块
- 在React中使用 CSS 模块
- 全局 CSS
好了,天不早了,干点正事哇。
1. 前置知识点
前置知识点,只是做一个概念的介绍,不会做深度解释。因为,这些概念在下面文章中会有出现,为了让行文更加的顺畅,所以将本该在文内的概念解释放到前面来。如果大家对这些概念熟悉,可以直接忽略
CSS-in-JS
简介
CSS-in-JS
是一种前端开发方法,它将样式表达式嵌入到 JavaScript
中,以便更好地管理和组织样式。这种方法的主要思想是将组件的样式与组件本身紧密耦合在一起,以提高可维护性、可读性和复用性。CSS-in-JS
有许多不同的库和工具,每个都有自己的语法和特性,但核心思想是相似的。
以下是 CSS-in-JS
的一些主要特点和优势:
- 组件化样式:
CSS-in-JS
允许我们将样式与组件一起定义,将它们封装在一起。这使得代码更具可读性,因为我们可以在组件的定义中直接查看和理解样式。 - 动态样式:与传统的
CSS
不同,CSS-in-JS
允许我们根据组件的状态或属性来动态生成样式。这使得样式更加灵活,能够根据应用的不同情况进行调整。 - 自动前缀:许多
CSS-in-JS
库会自动添加浏览器前缀,以确保样式在不同浏览器中都能正常工作。 - 组件级别作用域:样式是组件级别的,不会与其他组件的样式冲突,从而避免全局样式表的问题。
- 性能优化:某些
CSS-in-JS
库会使用类似于样式提取(style extraction
)的技术,将样式提取为单独的CSS
文件,以提高性能。 - 可维护性:将样式与组件紧密结合使得代码更易于维护,因为我们可以在同一个文件中查找组件的样式定义,而不必在多个文件之间跳转。
像比较常见的库有
由于它们的语法还有使用方式相差无几,所以我们就挑一个比较常见的库进行演示。如果想了解其它的使用方式,可以根据上面链接,直接访问其官网。
Styled Component
下面展示了如何使用 styled-components
创建一个简单的按钮组件:
首先,我们需要安装 styled-components
:
npm install styled-components
然后,我们可以创建一个按钮组件:
// 导入 styled-components 库 import styled from 'styled-components'; // 创建一个样式化的按钮组件 const Button = styled.button` background-color: #007bff; color: #fff; border: none; padding: 10px 20px; cursor: pointer; &:hover { background-color: #0056b3; } `; // 在我们的应用中使用这个按钮组件 function App() { return ( <div> <h1>前端柒八九</h1> <Button onClick={() => alert('Helllo, 骚年')}>关注走一波</Button> </div> ); } export default App;
在上面的示例中,我们导入 styled-components
库,然后使用 styled.button
创建一个按钮组件。我们使用模板字符串定义了按钮的样式,包括背景颜色、文字颜色等。&:hover
是一个伪类选择器
,用于定义按钮的鼠标悬停样式。
最后,在应用中使用这个按钮组件,就像使用普通的 React 组件一样。
2. CSS模块的红与黑
优点:
- 通过使用
CSS模块
,可以避免CSS类的命名空间冲突。多个CSS文件可以包含相同的CSS类。 - 在
CSS模块
中,我们可以将类发送到多个组件。 - 使用
CSS模块
的一个关键优点是,我们可以放心地编辑任何CSS文件,而不必担心它会影响其他模块。 - 使用
CSS模块
创建可移植和可重用的CSS文件。不再需要担心规则会影响其他组件的样式或选择器名称冲突。 - 尽管项目复杂,但
CSS模块
可以使我们的代码看起来整洁,以便其他开发人员可以阅读和理解它。
缺点:
- 在将样式集成到项目中时,必须将样式包含为带有
点号
或方括号
表示法的对象。 - 与
Styled Components
不同,CSS模块
不接受props
。
那么,为什么要使用CSS模块呢?
- 在使用
CSS模块
时,我们可以确保给定组件的每个样式都位于一个位置,并且仅适用于导入它的组件。 - 借助
CSS模块
和默认的局部作用域概念,可以避免全局作用域的问题。 - 在编写样式时,我们总是怕和别人起了相同的类名影响现有的业务,总是畏首畏尾,战战兢兢的编写自己的样式代码。
3. CSS模块使用语法
现在属于SPA
的天下,那在使用框架时候就绕不开,模块化构建工具(如Webpack
、vite
、Rspack
)来管理样式。
下面我们简单分别介绍一下,它们对CSS模块
的支持程度。
当我们安装create-React-app
时,React
会为我们处理一切;因此,我们目前不需要为Webpack
配置CSS模块
。
在使用CSS模块
时,不需要额外的代码或添加到CSS模块
的第三方代码。我们只需要将CSS文件的名称更改为[文件名].Modules.css
;我们可以用任何其他名称替代[文件名]
。在使用CSS模块
时,我们必须使用import
关键字将文件导入到特定组件中。在将CSS模块
集成到我们的React项目中时,我们必须指定类,就像在标准JavaScript中使用点符号或方括号语法访问对象的属性一样。
使用点符号表示法:
<div className={classes.parent_div}></div>
如果我们的CSS类包含连字符,应使用方括号表示法:
<div className={classes["parent-div"]}></div>
我们可以组合样式:
const buttonClasses = classes.myBtn + " " + classes.extra_classes;
这些是纯粹的普通JavaScript对象的基本概念。
Vite
天然支持CSS模块
Rspack
也天然支持CSS模块
4. 创建一下CSS模块
像Styled Component、Emotion和styled-jsx等CSS库现在都广泛使用。但是,我认为CSS模块
是会在未来大放异彩,特别是全局范围和可重用性,这使得我们以后写样式时,不用如履薄冰。CSS模块
越来越广泛地用于在特定组件中本地描述样式并避免全局作用域。
让我们从一个简单的项目开始。我们将创建一个[文件名].module.css
文件。我们将导入我们的[文件名].module.css
的组件如下所示。
TypeScript
用户必须添加一个.d.ts
文件;在这种情况下,我们将创建[文件名].module.css.d.ts
”。
// [fileName].module.css.d.ts export const styles: string; export const someStyles: string; export const moreStyles: string;
这个文件定义了一些CSS模块
中的样式类,可以在组件中使用。
[fileName].module.css
的内容如下所示:
.container { width: 500px; padding: 20px; background-color: white; box-shadow: 17px 18px 10px #767676; text-align: center; line-height: 3; margin: 20px; } .border_radius { border-radius: 40px; } .counter-title { color: cornflowerblue; font-family: cursive; font-weight: bolder; } .container button { background-color: cornflowerblue; padding: 15px 20px; border-radius: 10px; color: white; border: none; outline: none; }
要将CSS模块
的样式表导入到组件中,最好在[classes]
或[styles]
前缀下导入它。样式或类的前缀并不是强制性的,但我们将使用类以符合最佳实践。要使用样式,请确保路径包含./[fileName].module.css
对应的文件。
import classes from "./Styles.module.css";
5. 在React中使用 CSS 模块
在使用CSS 模块
时,可以将样式写在CSS
文件中,然后使用上面所示的点号
或方括号
表示法来引用导入的CSS模块
。在下面的代码中,我们演示了如何在React
组件中利用CSS Modules
。
函数组件
在React函数组件中,我们将使用CSS Modules
。下面的代码增加了计数器的值并使用useState
在将要创建的FunctionCounter.js
组件中。
import React, { useState } from "react"; import classes from "./Styles.module.css"; const FunctionCounter = () => { const [counter, setCounter] = useState(0); const handleClick = () => { setCounter(counter + 2); }; return ( <> <div className={classes.container}> <p className={classes["paragraph-text"]}>前端柒八九</p> <h2 className={classes["counter-title"]}>{counter}</h2> <button onClick={handleClick}>数字加2</button> </div> </> ); }; export default FunctionCounter;
这个组件使用了从CSS模块
导入的样式类,并且在点击按钮时会增加计数器的值。这样,我们可以在React函数组件中利用CSS模块
来管理样式。
类组件
我们将看到一个使用CSS模块
的类组件。我们将创建一个名为ClassCounter.js
的Class组件。下面的代码会将计数值增加2。
import React from "react"; import classes from "./Styles.module.css"; class ClassCounter extends React.Component { constructor() { super(); this.state = { counter: 0 }; // 这个绑定是必要的,以使`this`在回调中正常工作 this.handleClick = this.handleClick.bind(this); } handleClick = () => { this.setState({ counter: this.state.counter + 1, }); }; render() { return ( <div className={`${classes.container} ${classes.border_radius}`}> <p className={classes["paragraph-text"]}>前端柒八九</p> <h2 className={classes["counter-title"]}>{this.state.counter}</h2> <button onClick={this.handleClick}>数字加1</button> </div> ); } } export default ClassCounter;
最后,让我们看一下App.js
组件。我们将在App.js
组件中导入FunctionCounter.js
和ClassCounter.js
组件。
import React from "react"; import ClassCounter from "./ClassCounter"; import FunctionCounter from "./FunctionCounter"; const App = () => { return ( <div> <FunctionCounter /> <br /> <ClassCounter /> </div> ); }; export default App;
以下是我们的CSS模块
中的Class
和Function
组件的输出。
并且我们在浏览器中进行元素审查时,可以看到指定元素中的class
使用从CSS模块
获取的哈希值。
6. 全局 CSS
CSS模块
并不禁止使用全局CSS。我们可以使用与导入ES6相同的方法导入样式表。
import './App.css'
此外,我们可以使用关键字global
来更改类的范围,以防止CSS模块
修改它。
:global(.class) { color:red; } :global .button {}
以下是上面代码的解释:
:global(.class)
:这是一个CSS Modules中的语法,:global
告诉CSS模块不要将此类名限制在模块范围内,而是将其视为全局CSS类名。这意味着任何地方都可以使用.class
类名,而不受模块化的限制。
/* 在CSS模块中 */ .class { color:red; }
- 在这里,
.class
类名的样式会在整个应用程序中全局生效。 :global .button
:这也是使用:global
将样式声明为全局的示例。.button
类名可以在整个应用程序中任何地方使用,不受模块化的限制。
/* 在CSS模块中 */ .button { /* 样式规则 */ }
- 在这里,
.button
类名的样式也会在整个应用程序中全局生效。
需要注意的是,:global
是一种逃逸机制,用于在CSS模块中定义全局样式。通常情况下,CSS Modules的目标是将样式局部化,以避免全局污染和冲突。但有些情况下,我们可能需要使用全局样式,这时可以使用:global
。
7. 多个 CSS模块混合使用
CSS模块不限制使用多个类;我们可以按照以下方式使用CSS模块
来添加多个类:
<div className={`${classes.container} ${classes.border_radius}`}></div> function Footer( props) { return ( <div className={styles.section}> <div className={`${styles.description} ${styles.black}`}> <p>CSS模块的使用说明</p> </div> </div> ); }
8. 伪类选择器
伪类选择器
用于选择处于特定状态的元素。由于CSS模块
通过为我们的元素添加类来工作,因此添加伪类选择器非常简单。
// Button.module.css .button:hover {background-color;: } .button:disabled {color: #ddd} .button:active {color: grau} //============ import classes from "./Button.module.css"; import React, { Component } from "react"; export default class Text extends Component { render() { return <button className={classes.button}>关注我,给你一个不一样的技术分享</button>; } }
后记
分享是一种态度。
参考资料:
全文完,既然看到这里了,如果觉得不错,随手点个赞和“在看”吧。