前端基础CSS系列之选择器与样式隔离

主要介绍了css的常见选择器和如何解决css样式隔离的问题。

Posted by jiangvv on April 16, 2025

CSS选择器和样式隔离

CSS选择器

一、基本选择器

1.通用选择器:*

选择所有元素。(可选)可以将其限制为特定的名称空间或所有名称空间。

例子:* 将匹配文档的所有元素。

2.标签选择器:标签名称

按照给定的节点名称,选择所有匹配的元素。

例子:<input> 匹配任何<input>元素。

3.类选择器:.类名

按照给定的 class 属性的值,选择所有匹配的元素。

例子:.index 匹配任何 class 属性中含有 “index” 类的元素。

4.ID选择器:#id名

按照 id 属性选择一个与之匹配的元素。需要注意的是,一个文档中,每个 ID 属性都应当是唯一的。

例子:#toc 匹配 ID 为 “toc” 的元素。

5.属性选择器:

按照给定的属性,选择所有匹配的元素。 例子:p[class="test"] 选择类名为test的p元素

二、分组选择器

1.并集选择器:,

将不同的选择器组合在一起的方法,它选择所有能被列表中的任意一个选择器选中的节点。

示例:div, span 会同时匹配span元素和div元素。

2.后代选择器:空格

选择前一个元素的所有后代节点。

例子:div span 匹配所有位于任意div元素之内的span元素。

3.直接后代选择器:>

选择前一个元素的所有直接子代的节点。

例子:ul > li 匹配直接嵌套在ul元素内的所有li元素。

4.兄弟选择器:~

同一父节点的前一个元素后的所有后一个元素

例子:p ~ span 匹配同一父元素下,p元素后的所有span元素。

5.紧邻兄弟选择器:+

后一个元素紧跟在前一个之后,并且共享同一个父节点。

例子:h2 + p 会匹配紧邻在h2元素后的第一个p元素。

三、伪选择器

1.伪类选择器::

支持按照未被包含在文档树中的状态信息来选择元素。

动态伪类:

  1. a:link 超链接未被访问的状态。

  2. a:visited 超链接访问过的状态。
  3. a:hover 鼠标悬停在元素上的状态。
  4. a:active 元素激活的状态。

  5. input:focus 获取焦点的元素。

结构伪类

  1. :first-child 所有兄弟元素中的第一个。
  2. :last-child 所有兄弟元素中的最后一个。
  3. :nth-child(n) 所有兄弟元素中的第 n 个。
  4. :first-of-type 所有同类型兄弟元素中的第一个。
  5. :last-of-type 所有同类型兄弟元素中的最后一个。
  6. :nth-of-type(n) 所有同类型兄弟元素中的 第n个 。

2.伪元素选择器:::

用于表示无法用 HTML 语义表达的实体。

例子:p::first-line 匹配所有p元素的第一行。

样式隔离方案

一、BEM

.block__element--modifier或者说block-name__element-name--modifier-name形式命名,命名有含义,也就是模块名 + 元素名 + 修饰器名 如.dropdown-menu__item--active

优点:

  • 人为严格遵守BEM规范,可以解决无作用域样式污染问题
  • 可读性好,一目了然是那个dom节点,对于无用css删除,删除了相应dom节点后,对应的css也能比较放心的删除,不会影响到其他元素样式

缺点:

  • 命名太长(个人开发习惯、部分人会觉得,我认为命名长提高了可读性,能解决一些问题,也不叫缺点),至于体积增大,gzip可忽略

二、CSS module (目前使用)

依赖webpack css-loader,配置如下,现在webpack已经默认开启CSS modules功能了

{
  test: /.css$/,
  loader: "style-loader!css-loader?modules" //简写方式
}
//todo:详细配置讲解

我们先看一个示例: 将CSS文件style.css引入为style对象后,通过style.title的方式使用title 类:

import style from './style.css';

export default () => {
  return (
    <p className={style.title}>
      I am KaSong.
    </p>
  );
};

对应style.css

.title {
  color: red;
}

打包工具会将style.title编译为带哈希的字符串

<h1 class="_3zyde4l1yATCOkgn-DBWEL">
  Hello World
</h1>

同时style.css也会编译:

._3zyde4l1yATCOkgn-DBWEL {
  color: red;
}

这样,就产生了独一无二的class,解决了CSS模块化的问题 使用了 CSS Modules 后,就相当于给每个 class 名外加加了一个:local,以此来实现样式的局部化,如果你想切换到全局模式,使用对应的 :global:local:global 的区别是 CSS Modules 只会对 :local 块的 class 样式做 localIdentName 规则处理,:global 的样式编译后不变

.title {
  color: red;
}

:global(.title) {
  color: green;
}

可以看到,依旧使用CSS,但使用JS来管理样式依赖,最大化地结合现有CSS 生态和 JS 模块化能力,发布时依旧编译出单独的 JSCSS

三、CSS in JS (以前使用)

核心思想是把CSS直接写到各自组件中,也就是说用JS去写CSS,直接使用行内样式,而不是单独的样式文件里,例如:

<h1 style="color:red;font-size:46px;"  onclick="alert('Hi')">
  Hello World
</h1>

上面的例子使用 React 改写如下

const style = {
  'color': 'red',
  'fontSize': '46px'
};

const clickHandler = () => alert('hi'); 

ReactDOM.render(
  <h1 style={style} onclick={clickHandler}>
     Hello, world!
  </h1>,
  document.getElementById('example')
);