css 怎样实现样式隔离

798 阅读3分钟

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

前情提要

今年公司开始准备把一个巨石型海外项目进行结合微前端进行拆分,拆分的过程中遇到了css样式污染的问题。所以之后就研究了下css样式隔离的问题。
css 作用域是全局的,项目越来越大,人越来越多,命名慢慢也就成为了一个大问题,(在样式隔离没有出来之前,在不同的文件取了相同的类,肯定会冲突。)以下是几种解决命名问题的方案

BEM

以 .block__element--modifier 形式命名,命名有含义,block 可视为模块,有一定作用域含义 常用的样式隔离:约定-命名空间。比如所有的带global_ 就是代表全局的样式,比如在业务组件里面,header_XXX开头作为header组件的样式。

css-module

本质上是在编译过程中运用哈希等方式进行命名随机化,避免全局命名冲突

CSS的规则都是全局的,任何一个组件的样式规则,都对整个页面有效。产生局部作用域的唯一方法,就是使用一个独一无二的class的名字,不会与其他选择器重名。这就是 CSS Modules 的做法。

使用JS编译原生的CSS文件,使其具备模块化的能力。在 webpack中,作为处理css的css-loader,它实现了css module的思想,要启用css module,需要将css-loader的配置modules设置为true。原理极其简单,开启了css module后,css-loader会将样式中的类名进行转换,转换为一个唯一的hash值。由于hash值是根据模块路径和类名生成的,因此,不同的css模块,哪怕具有相同的类名,转换后的hash值也不一样。

CSS Modules 是对现有的 CSS 做减法。 为了追求简单可控,建议遵循如下原则:

  1. CSS Module只转换class和id,此外的标签选择符、伪类等都不会被转换。建议只使用class。
  2. 让 CSS 的优先级保持相对扁平,不层叠多个 class,只使用一个 class 把所有样式定义好
  3. 所有样式通过 composes 组合来实现复用
  4. 不嵌套,CSS Module 不适合使用包含选择符

建议只是建议,CSS Modules 并不强制你一定要这么做。具体的根据实际情况来

使用:

.container {
  background-color: #fff;
}
import styles from './index.module.css';
<div style={styles.container}></div>

css-in-js

在React社区中,CSS in JS被提及的次数很多,CSS-in-JS是一种技术(technique),而不是一个具体的库实现。简单来说CSS-in-JS就是将应用的CSS样式写在JavaScript文件里面,而不是独立为一些.css,.scss或者less之类的文件,这样你就可以在CSS中使用一些属于JS的诸如模块声明,变量定义,函数调用和条件判断等语言特性来提供灵活的可扩展的样式定义。 行内样式CSS-in-JS完全不同,如下图所示: 行内:

<span style="color: green">inline style</span>

css in js

<style>
.jss-xxx-green{
  color: green
}
</style>

<span class='jss-xxx-green'>inline style</span>

CSS-in-JS在DOM的顶部附加了一个标记,而内联样式只是将属性附加到DOM节点。 为什么这很重要?

并非所有CSS功能都可以使用JavaScript事件处理程序。 许多伪选择器(如:disabled,:before,:nth-child)是不可能的,不支持样式化html和body标签等。

scoped

scoped:相当于一个很小的沙箱

总结:

在众多解决方案中,没有绝对的优劣。还是要结合自己的场景来决定。
目前项目很多都是用 :约定+预处理的方式(sass,scss,less),
还有一些是css-module +预处理的方式(sass,scss,less)