大厂前端面试CSS高频考点剖析:选择器体系

57 阅读8分钟

前言

CSS (Cascading Style Sheets) 是网页设计的核心语言之一,用于描述HTML文档的呈现方式。本文将全面介绍CSS的基础概念、各种选择器类型及其使用方法、注意事项,以及选择器权重的重要性。

一、CSS基础概念

1. CSS基本结构

CSS由三个主要部分组成:

  • 选择器(Selector) :用于选择要样式化的HTML元素
  • 声明(Declaration) :一个属性与值的键值对
  • 声明块(Declaration Block) :由大括号{}包围的一组声明
p {
    color: blue;
    font-size: 16px;
}

在这个例子中:

  • p 是选择器
  • color: blue; 和 font-size: 16px; 都是声明
  • 整个{color: blue; font-size: 16px;}是声明块
  • 选择器加上声明块构成一个规则集(ruleset)

image.png

2. CSS层叠特性

CSS中的"C"代表"层叠"(Cascading),这意味着:

  1. 样式可以来自多个来源(作者样式、用户样式、浏览器默认样式)
  2. 当规则冲突时,会根据特定规则确定哪个样式生效
  3. 层叠顺序决定了最终应用的样式(权重相同的话)

二、CSS选择器详解

CSS选择器是用于选择HTML元素的模式。了解各种选择器及其用法是掌握CSS的关键。

1. 基本选择器

元素选择器(类型选择器/标签选择器)

选择特定类型的HTML元素。

p {
    color: blue;
}

类选择器(Class选择器)

选择具有特定class属性的元素,以.开头,一个元素可以有多个类名,一个类名也可以用于多个元素。

.container {
    width: 80%;
}

ID选择器

选择具有特定id属性的元素,以#开头,ID在文档中应该是唯一的。

#main {
    background-color: #f0f0f0;
}

通用选择器(通配符选择器)

通用选择器匹配文档中的所有元素,以*开头,通常用于重置默认样式或设置全局样式。下面这个样式常用来去除所有元素默认内外边距。

* {
    margin: 0; /* 外边距*/ 
    padding: 0;/* 内边距*/ 
}

2. 组合选择器

后代选择器 (空格)

选择.container元素内部的所有<p>后代元素,无论嵌套多深。

.container p {
    color: red;
}

子元素选择器 (>)

仅选择.container直接子元素的<p>不包含更深层级的。

.container > p {
    color: blue;
}

相邻兄弟选择器 (+)

选择紧接<h2>后面的第一个<p>兄弟元素。

h2 + p {
    font-weight: bold;
}

通用兄弟选择器 (~)

选择<h2>之后所有同级<p>元素。

h2 ~ p {
    background: yellow;
}

并集选择器 (,)

同时选择所有<h1><h2><h3>元素。

h1, h2, h3 {
    font-family: sans-serif;
}

经典面试错误点:

  1. 混淆后代和子选择器:很多人误以为div pdiv > p效果相同,实际上前者选择所有后代,后者只选直接子元素。(相当于前者可以选择儿子和孙子无穷无尽,而后者只能选择儿子)
  2. 相邻兄弟选择器误解A + B只选择紧邻的下一个兄弟,而不是所有后续兄弟。
  3. 选择器优先级混淆:组合选择器的优先级计算常被误解,如.class p比单纯的p选择器优先级高。
  4. 性能问题:过度嵌套的后代选择器如div ul li a会影响页面渲染性能。
  5. 空格敏感div > pdiv>p效果相同,但div >p在某些旧浏览器中可能有问题。

3. 伪类选择器

伪类用于定义元素的特殊状态。

行为伪类

  • :hover - 鼠标悬停时
  • :active - 元素被激活时(如点击按钮)
  • :focus - 元素获得焦点时
button:hover {
    background-color: red;
}

input:focus {
    border: 2px solid blue;
}

状态伪类

  • :checked - 选中的表单元素
  • :disabled - 禁用的表单元素
input:checked + label {
    font-weight: bold;
}

结构伪类

  • :first-child - 第一个子元素
  • :last-child - 最后一个子元素
  • :nth-child(n) - 第n个子元素
  • :nth-of-type(n) - 第n个特定类型的子元素
li:nth-child(odd) {
    background-color: lightgray;
}

.container :nth-child(3) {
    background-color: yellow;
}

.container p:nth-of-type(3) {
    background-color: red;
} 

注意:nth-child:nth-of-type的区别:

  • :nth-child选择父元素的第n个子元素,不考虑类型
  • :nth-of-type选择父元素的第n个特定类型的子元素

这个是面试中常考的点,下面我们通过一个案例来解释一下:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>:nth-child vs :nth-of-type</title>
    <style>
        /* 基础样式 */
        .container {
            font-family: Arial, sans-serif;
            max-width: 600px;
            margin: 20px auto;
            padding: 20px;
            border: 1px solid #ddd;
            border-radius: 5px;
        }
        
        /* 使用:nth-child选择器 */
        .container p:nth-child(2) {
            color: red;
            font-weight: bold;
        }
        
        /* 使用:nth-of-type选择器 */
        .container p:nth-of-type(2) {
            background-color: yellow;
        }
        
        /* 辅助样式,使效果更明显 */
        p, div, span {
            padding: 5px;
            margin: 5px 0;
        }
    </style>
</head>
<body>
    <div class="container">
        <div>我是第一个子元素(div)</div>
        <p>我是第二个子元素(第一个p元素)</p>
        <span>我是第三个子元素(span)</span>
        <p>我是第四个子元素(第二个p元素)</p>
        <p>我是第五个子元素(第三个p元素)</p>
        <div>我是第六个子元素(div)</div>
    </div>
</body>
</html>

在这个例子中:

  1. :nth-child(2)  选择器:

    • 这个是从1开始计算,不是从0开始
    • .container p:nth-child(2)他会选择container类的第2个子元素,并且他必须是p 标签,如果不是,那么这个元素不会被渲染
    • .container:nth-child(2)这个就不用考虑第2个子元素是不是p标签了
  2. :nth-of-type(2)  选择器:

    • 选择父元素中第2个特定类型(p)的子元素
    • 它会跳过非p元素,只计算p元素的顺序
    • 在我们的例子中,第2个p元素是 <p>我是第四个子元素(第二个p元素)</p>

总结:

选择器计算方式上例中选中的元素
:nth-child(2)所有子元素中的第2个(还要注意前面有没有加上限定)第二个子元素(第一个p元素)
:nth-of-type(2)同类型子元素中的第2个第二个p元素(第四个总体子元素)

否定伪类 (:not)

选择不匹配给定选择器的元素。

li:not(:last-child) {
    margin-bottom: 10px;
}

4. 伪元素选择器

伪元素用于样式化元素的特定部分。

  • ::before - 在元素内容前插入内容
  • ::after - 在元素内容后插入内容
  • ::selection - 用户选中的文本部分
::selection {
    background-color: blue;
    color: white;
}

面试考题:伪类和伪元素的区别:

核心区别

特性伪类(Pseudo-classes)伪元素(Pseudo-elements)
作用对象元素的状态元素的某部分或生成内容
语法单冒号 :(如 :hover双冒号 ::(如 ::before
典型用例:active:nth-child()::before::first-line

记忆技巧

  • 伪类(Pseudo-class)→  “类”似状态(如悬停、选中)。
  • 伪元素(Pseudo-element)→  “元素的一部分” (如首字母、插入内容)。

通过区分它们的作用(状态 vs. 部分/内容)和语法(: vs. ::),可以更清晰地运用它们。

三、选择器权重与优先级(面试常考)

CSS选择器的权重(也称为特异性)决定了当多个规则应用于同一个元素时,哪个规则会被应用。理解选择器权重是解决样式冲突的关键。

选择器权重等级

CSS选择器的权重由四个组成部分构成,可以表示为:(a, b, c, d)从左到右权重依次减弱:

  1. 内联样式 (a): 直接在HTML元素的style属性中编写的样式
  2. ID选择器 (b): 使用#id选择的元素
  3. 类/属性/伪类选择器 (c): 包括.class、[type="text"]、:hover等
  4. 元素/伪元素选择器 (d): 包括div、p、::before等

各类选择器的具体权重值

权重规则:a > b > c > d

选择器类型权重值 (a,b,c,d)示例
内联样式(1,0,0,0)<div style="color:red">
ID选择器(0,1,0,0)#header
类选择器(0,0,1,0).active
属性选择器(0,0,1,0)[type="text"]
伪类选择器(0,0,1,0):hover
元素选择器(0,0,0,1)div
伪元素选择器(0,0,0,1)::before
通配符(*)(0,0,0,0)*
继承的样式无权重从父元素继承的样式

优先级规则

  1. !important > 内联样式 > ID选择器 > 类/属性/伪类选择器 > 元素/伪元素选择器
  2. 相同权重下,后定义的样式会覆盖前面的样式
  3. 继承的样式权重最低,低于任何直接应用的样式

特殊情况

  1. !important: 会覆盖所有其他规则(尽量避免使用)

  2. 通用选择器(*)组合器(+, >, ~):not()伪类:

    • 没有权重
    • 组合器不影响权重
    • :not()本身的权重为0,但括号内选择器的权重会计算
  3. 相同权重时,后定义的样式优先

结语

CSS选择器是前端开发的基础工具,掌握各种选择器及其权重对于编写可维护、高效的CSS代码至关重要。通过合理组合不同类型的选择器,可以精确地定位和样式化页面元素,同时保持代码的灵活性和可扩展性。记住,选择器的使用不仅仅是让样式生效,还要考虑性能、可维护性和团队协作的便利性。