和样式污染说不

1,243 阅读3分钟

全局样式污染

全局样式污染(Cascading Style Sheets Contamination)通常指的是一个CSS文件或样式规则意外地影响了其他组件或页面的样式。

可能是由以下原因造成:

  1. 选择器优先级不足,导致规则被其他更具体或更靠后的样式覆盖
  2. 使用了全局选择器*,使得所有元素都受到影响
  3. 样式文件被错误地引入到了多个页面或组件中,导致重复应用
  4. 样式文件中的规则被意外复制或合并到其他文件中

可行的解决方法:

  1. 检查并提高样式规则的特异性,使用更具体的选择器,如类选择器或ID选择器
  2. 避免使用全局选择器*,除非绝对必要
  3. 确保样式文件只被引入到需要它的组件或页面中,避免全局污染
  4. 对样式文件进行组织和管理,避免不必要的复制或合并

在实际操作中,可以使用以下方法来减少或避免全局样式污染:

  • 使用CSS模块化,每个模块或组件拥有自己的样式文件,并通过特定的类名或ID将样式局部作用于元素上
  • 使用CSS-in-JS库(如styled-components),它们允许你用JavaScript编写样式,从而避免全局样式污染
  • 使用CSS预处理器(如Sass、Less)的嵌套规则,减少不必要的全局选择器
  • 使用CSS框架时,遵循其命名空间和作用域的最佳实践,避免全局样式污染
  • 进行代码审查,确保没有重复的样式文件被引入到不同的页面或组件中

CSS模块化

CSS模块化是一种组织和管理CSS代码的方法,可以减少样式冲突,提高代码复用性,并增加样式的可维护性。

  1. BEM (Block Element Modifier) 命名规范

BEM是块、元素、修饰符(Block, Element, Modifier)的缩写。它是一种命名约定,有助于开发人员编写可重复使用、易于维护和扩展的CSS代码。

.button {
  display: inline-block;
  padding: 10px 20px;
  border: 1px solid #000;
  text-align: center;
}
.button__text {
  font-size: 16px;
}
.button--large {
  padding: 15px 30px;
}
  1. Atomic CSS模块化

将每个样式都视为原子,尽量避免组合样式。

.mr10 {
  margin-right: 10px;
}
.p20 {
  padding: 20px;
}
.bg-blue {
  background-color: blue;
}
.container {
  @extend .mr10;
  @extend .p20;
  @extend .bg-blue;
}

CSS-in-JS

将CSS和JavaScript混合在一起的方法,它允许你以JavaScript的方式编写样式。

下载安装插件npm install styled-components

import styled from "styled-components";

const StyledButton = styled.a`
  padding: 20px 40px;
  background-color: ${ ({ primary }) => ( primary ? "#07c" : "#333" ) };
  color: white;

  &:hover {
    background-color: #111;
  }
`;

export default StyledButton;

创建的标签样式可以在任何组件中使用

import StyledButton from './components/styles/Button.styled';

function App() {
  return (
    <div className="App">
      <StyledButton href="...">Default Button</StyledButton>
      <StyledButton primary href="...">Primary Button</StyledButton>
    </div>
  );
}

export default App;

image.png

CSS预处理

像Sass/LESS这样的第三方插件,都提供了变量、混合(mixins)、嵌套规则等高级功能,可以帮助写出更模块化的CSS代码。

$base-font-size: 16px;
// Mixin
@mixin center-block {
  display: block;
  margin-left: auto;
  margin-right: auto;
}
// Usage
.button {
  font-size: $base-font-size;
  @include center-block;
}

CSS @layer

项目开发中,经常出现第三方库代码和本地代码冲突,最常用的解决办法是增加本地代码的权重,如下所示:

.container .some-button {} 改为 body .container .some-button {}

这样的代码虽然可以解决问题,但是又长又臭,而CSS @layer的出现就是为了解决这个问题。

使用@layer将样式优先级降低

<style>
  @layer {
    #app .item {
      color: black;
      width: 100px;
      padding: 1em;
    }
  }
  .item {
    color: red;
  }
</style>
<div id="app">
  <div class="item">测试文案</div>
</div>

image.png

@import中使用

@import './zxx.lib.css' layer(lib);

zxx.lib.css 里面所有 CSS 声明的优先级都会低于常规设置的 CSS 声明。

元素引用(*)

<!-- zxx-lib.css的样式属于名为 lib 的级联层 -->
<link rel="stylesheet" href="zxx-lib.css" layer="lib">

<!-- 样式引入到一个匿名级联层中 -->
<link rel="stylesheet" href="zxx-lib.css" layer>

CSS作用域划分(兼容性差)

CSS处理库提供的:global:local分别表示全局作用域和局部作用域,

  • :global:选择器用于指定某个样式规则应用于全局范围内的元素,而不受当前样式封装作用域的影响
  • :local:标记本地作用域内的样式
:global(.map){ 
  color:#333; 
} 
.map{ 
  padding-top: 45px; 
  height: 100%; 
} 

:local(.map) { 
  color: red; 
}

Vue框架避免样式污染

  1. scoped

作用:当前样式只作用于当前组件,不会造成全局样式污染

<style lang="scss" scoped>
  .key {
    width: 250px;
    height: 30px;
  }
</style>
  1. ::v-deep

作用:修改第三方库样式,实现样式穿透

::v-deep .confirm .el-button {
  width: 50px;
  height: 30px;
  padding: 2px 2px 2px 2px;
  border-radius: 3px;
}

React框架避免样式污染

  1. css modules
  2. styled-components
  3. CSS预处理器

Sass

image.png

变量

使用$声明一个变量,变量也存在作用域,可以通过标识符改变变量的作用域。

  • !global:将局部变量改为全局变量
  • !default:设置变量的默认值,如果在声明变量时赋值了则使用声明的值,否则就使用默认值

变量的数据格式包括以下几种:

  • 数字:10px
  • 字符串:“foo”, ‘bar’, baz
  • 颜色:blue, #04a3f9, rgba(255,0,0,0.5)
  • 布尔型:true, false
  • 空值:null
  • 数组:list,用空格或逗号作分隔符,1.5em 1em 0 2em, Helvetica
  • maps:相当于 JavaScript 的 object,(key1: value1, key2: value2)
$main-color: red; // 全局变量
h1 { 
  $main-color: green; // 局部变量 
  color:$main-color; // green
} 
h2 { 
  color:$main-color; // red
}

嵌套

  1. 标签嵌套
div{ 
  height: 100px; 
  ul{ 
    height: 80px; 
    li{ 
      height: 50px; 
    } 
  } 
}
  1. 选择器嵌套
#app{ 
  color:while; 
  .content{ 
    color:red; 
  } 
}
  1. 父级选择器 &
#app{ 
  color:while; 
  & .content{ 
    color:red; 
  } 
}

运算

  1. 数学运算
$number: 12px; 
p{ 
  width: $number * 2; 
}
  1. 颜色值运算
.color1{ 
  color: #010120 + #234234; 
}
  1. 字符串运算
.string1:before{ 
  font-family: icon + font; 
  content: "带引号字符串" + 不带引号字符串; 
}
  1. 布尔值运算
.bool1:before{ 
  content: $bool and false; 
}

@import导入

@import "test2.scss";

@media特定尺寸样式

@media screen and (orientation: landscape) { 
  width: 500px; 
}

@extend继承

.item{
  width:100%;
  background:#ffffff;
  line-height:40px;
}
.light_item{
  //继承上面.item的样式
  @extend .item ;//父级并行使用.item的样式
  // 特殊样式(其他样式)
  background:#f0f0f0;
}

@extend支持多重继承和延续继承

@if

当 @if 的表达式返回值不是 false 或者 null 时,条件成立,输出 {} 内的代码

p { 
  @if 1 + 1 == 2 { border: 1px solid; } 
  @if 5 < 3 { border: 2px dotted; } 
  @if null { border: 3px double; } 
}

mixin 混合指令

混合指令(Mixin)用于定义可重复使用的样式,避免了嵌套class。混合指令可以包含所有的 CSS 规则,绝大部分 Sass 规则,甚至通过参数功能引入变量,输出多样化的样式。

  1. 无参混入
@mixin big_text{ 
  font:{ 
    size:22px; 
    weight:bold; 
  } 
  color:#555; 
}
div{ 
  @include big_text; 
}
  1. 带参混入
@mixin big_text2($size,$weight){ 
  font:{ 
    size:$size; 
    weight:$weight; 
  } 
  color:#555; 
} 
.p_big_text2{ 
  @include big_text2(24px,bold) 
}
  1. 参数默认值
@mixin big_text3($size:20px,$weight:400){ 
  font:{ 
    size:$size; 
    weight:$weight; 
  } 
  color:#555; 
} 
.p_big_text3{ 
  @include big_text3 
}