一劳永逸!React中解决css样式污染问题

6,277 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情

先写个注意点,我最近一直容易搞忘记的

在scss中使用图片的绝对路径的时候需要加上~

background-image: url(~assets/login.png);

下面我们来演示一下css样式污染的问题

1、首先我们在APP组件里写结构,并且导入APP.SCSS,导入Login组件

import './App.scss';
import Login from './Login'
function App() {
return (
<div className="App">
  <div className="box">
    APP
  </div>
  <Login></Login>
</div>
);
}
export default App;

2、在Login页面里写结构

import React from 'react'
const Func = () => {
return <div className="box">
    Login
</div>
};
export default Func

3、在APP.SCSS文件里写样式

.box {
height: 200px;
width: 200px;
background-color: yellow;
}

代码运行结果

image.png 我们发现Login里的box盒子也生效了样式,但在Login组件里并没有导入APP.SCSS文件,这是为什么呢?

image.png 因为React会把每一个样式文件放在head里面,在配置路由时,APP和Login组件都被导入到项目中,那么组件的样式也就被导入到项目中了,也就是说最终的所有的样式文件全汇集到index.html中了。 如果多个组件的样式中出现选择器重复,那么一个组件中的样式就会在另一个组件中也生效,从而造成组件之间样式相互覆盖的问题。

解决方法 在react中推荐使用:CSS Modules (推荐原因:React脚手架已集成,可直接使用)。在vue中默认使用的是scoped css。

1、改样式文件名。从 xx.scss -> xx.module.scss (这是React脚手架中的约定,与普通 CSS 作区分)

2、组件中导入该样式文件(注意语法)

import styles from './index.module.scss'

3、通过 styles 对象访问对象中的样式名来设置样式

import styles from './App.module.scss';
import Login from './Login'
function App() {
return (
<div className="App">
  <div className={styles.box}>
    APP
  </div>
  <Login></Login>
</div>
);
}
export default App;

image.png 这样样式污染问题就被解决了! 实现的原理是CSS Modules 通过自动给 CSS 类名补足类名,保证类名的唯一性,从而避免样式冲突的问题 。

image.png 这个时候看类名已经默认被CSS Modules 补足,保证了类名的唯一性 掌握CssModules-维持类名

在没有做任何处理的情况下, 每一个类名都会被修改。

如果希望某个类名不被修改,可以使用: global。如下:

image.png 发现加了: global的类名会维持原状, 不会被修改

维持类名的应用场景

当我们想覆盖第三方组件的样式时,就需要给第三方组件的类名加上global

:global(.ant-btn) {
color: red !important;
}

日常开发时的最佳实践

在对应的index.module.scss

// index.module.scss
.root {
display: 'block';
position: 'absolute';
// 此处,使用 global 包裹其他子节点的类名。此时,这些类名就不会被处理,在 JSX 中使用时,就可以用字符串形式的类名
// 如果不加 :global ,所有类名就必须添加 styles.title 才可以
 :global {
.title {
  .text {
  }
  span {
  }
}
.login-form { ... }
}
}

在组件中使用就很方便

import styles from './index.module.scss'
const 组件 = () => {
return (
{/* (1) 根节点使用 CSSModules 形式的类名( 根元素的类名: `root` )*/}
<div className={styles.root}>
    {/* (2) 所有子节点,都使用普通的 CSS 类名*/ }
	<h1 className="title">
  	<span className="text">登录</span>  
  	<span>登录</span>  
   </h1>
<form className="login-form"></form>
</div>
)
}