今天我们来聊一个在实际开发中经常遇到的问题——样式冲突。你有没有遇到过这种情况:改了一个页面的样式,结果另一个页面的样式也跟着乱了?别担心,CSS Module 就是来解决这个问题的!
开发过程中,我们遇到样式冲突如何解决?
先来说说我们平时是怎么遇到样式冲突的。比如你在写一个按钮组件:
/* button.css */
.button {
background: blue;
color: white;
}
然后在另一个地方也写了一个按钮:
/* submit.css */
.button {
background: red;
padding: 10px;
}
结果两个按钮样式互相影响,蓝色的按钮突然有了10px的内边距,红色的按钮文字变成了白色... 这就是典型的样式冲突!
传统的解决方案有:
- 使用 BEM 命名规范(比如
.btn--primary__text) - 增加额外的包裹层(比如
.page-1 .button) - 使用
!important(千万别!)
但这些方法要么太麻烦,要么会带来新问题。这时候,CSS Module 闪亮登场!
什么是CSS Module?
简单来说,CSS Module 就是一个让你写的 CSS 只作用于当前组件的技术。它会在编译阶段自动给类名加上一串随机哈希值,这样就绝对不会和其他组件的类名冲突了。
比如你写的 .button,编译后会变成 .button_1a2b3c_xyz 这样的形式。
CSS Module 的背景
为什么会有 CSS Module 呢?因为前端项目越来越复杂,组件越来越多,传统的全局 CSS 已经撑不住了。想想一个大型项目有几百个组件,每个组件都有 .container、.title、.button,这不冲突才怪呢!
CSS Module 的出现就是为了让 CSS 也拥有"模块化"的能力,就像 JavaScript 的模块一样,每个组件的样式都是独立的作用域。
CSS Module 解决了哪些问题?
1. 彻底解决样式冲突
这是最核心的!每个组件的类名都是唯一的,再也不用担心重名问题了。
2. 嵌套层次过深的选择器
以前我们经常写出这样的 CSS:
.header .nav .list .item .link .icon {
color: red;
}
有了 CSS Module,你只需要写:
.icon {
color: red;
}
因为类名已经是唯一的了,不需要用长长的选择器来保证特异性。
3. 更好的维护性
组件和它的样式紧密关联,删除组件时也不用担心会影响到其他地方的样式。
CSS Module 如何使用?
说了这么多,怎么用呢?超级简单!
在 React 中使用
首先,你的 CSS 文件要命名为 [name].module.css:
/* Button.module.css */
.primary {
background: blue;
color: white;
}
.secondary {
background: gray;
color: black;
}
然后在组件中这样使用:
import React from 'react';
import styles from './Button.module.css';
const Button = ({ type }) => {
return (
<button className={styles[type]}>
点击我
</button>
);
};
export default Button;
// 使用方式:<Button type="primary" />
编译后的 HTML 会变成:
<button class="primary_1a2b3c_xyz">点击我</button>
在 Vue 中使用
Vue 单文件组件天然支持 CSS Module:
<template>
<button :class="$style.button">点击我</button>
</template>
<style module>
.button {
background: blue;
color: white;
}
</style>
高级用法:组合样式
CSS Module 还支持样式组合:
/* base.module.css */
.base {
padding: 10px;
border-radius: 4px;
}
/* button.module.css */
.button {
composes: base from './base.module.css';
background: blue;
color: white;
}
这样 .button 类就会同时拥有 base 和 button 的样式。
实际项目中的小技巧
1. 多个类名怎么处理?
// 使用模板字符串
<div className={`${styles.title} ${styles.highlighted}`}></div>
// 或者使用 classnames 库
import cn from 'classnames';
<div className={cn(styles.title, styles.highlighted)}></div>
2. 全局样式怎么办?
有时候确实需要全局样式,可以用 :global:
:global(.global-style) {
/* 这个样式不会被处理,保持原样 */
}
.title {
/* 这个会被处理 */
}
3. 如何覆盖第三方组件样式?
.wrapper :global(.ant-btn) {
/* 覆盖 Ant Design 按钮样式 */
}
总结
CSS Module 真是个好东西啊!它解决了长期困扰我们的样式冲突问题,让大型项目的样式维护变得轻松多了。
使用建议:
- 新项目强烈推荐使用 CSS Module
- 老项目可以逐步迁移,先从新组件开始
- 结合 CSS 预处理器(Sass/Less)使用效果更佳
不要再被样式冲突折磨了,快去试试 CSS Module 吧!相信我用过一次之后,你就再也回不去了~