参考文章: https://juejin.cn/post/6941206439624966152

前言

CSS选择器

基础选择器

  • 标签选择器: h1
  • 类选择器: .checked
  • ID选择器: #picker
  • 通配选择器: *

属性选择器

可以看看这篇文章: https://juejin.cn/post/6844903870171201549

  • [attr]: 选择包含某个属性的所有元素,而不关心属性值
<input type="text" placeholder="Enter your name">
<input type="password">
<input>

<style>
input[placeholder] { border: 2px solid blue; }
</style>

<!-- 选中所有带有 placeholder 属性的 input 元素(第一个 input) -->
  • [attr=val]: 选择属性值完全等于指定值的所有元素
<input type="text" placeholder="Enter your name">
<input type="password">
<input type="email">

<style>
input[type="password"] { background-color: lightgray; }
</style>

<!-- 仅选中 type="password" 的 input 元素 -->
  • [attr*=val]: 选择属性值中包含指定值的所有元素
<a href="https://google.com">Google</a>
<a href="https://github.com">GitHub</a>
<a href="mailto:support@example.com">Email Support</a>

<style>
a[href*="google"] { color: red; }
</style>

<!-- 选中 href 属性中包含 "google" 的 <a> 元素 -->
  • [attr^=val]: 选择属性值以指定字符串开头的所有元素
<a href="https://google.com">Google</a>
<a href="https://github.com">GitHub</a>
<a href="http://example.com">Example</a>

<style>
a[href^="https"] { text-decoration: underline; }
</style>

<!-- 选中 href 属性以 "https" 开头的 <a> 元素(Google 和 GitHub) -->
  • [attr$=val]: 选择属性值以指定字符串结尾的所有元素
<a href="index.html">Home</a>
<a href="about.html">About</a>
<a href="style.css">Stylesheet</a>

<style>
a[href$=".html"] { color: green; }
</style>

<!-- 选中 href 属性以 ".html" 结尾的 <a> 元素(Home 和 About) -->

组合选择器

  • 相邻兄弟选择器: A + B, 选择A元素后紧跟的第一个B元素
<div class="box">Box 1</div>
<div class="box">Box 2</div>
<p class="text">Text 1</p>
<p class="text">Text 2</p>

<style>
.box + .text { color: red; }
</style>

<!-- 仅会选中紧挨着 .box 的第一个 .text(也就是 Text 1) -->
  • 普通兄弟选择器: A ~ B, 选择A元素后所有的B元素
<div class="box">Box 1</div>
<p class="text">Text 1</p>
<p class="text">Text 2</p>
<div class="box">Box 2</div>
<p class="text">Text 3</p>

<style>
.box ~ .text { color: blue; }
</style>

<!-- 选中 .box 后所有同一父级下的 .text 元素(Text 1 和 Text 2) -->
  • 子选择器: A > B: 选择A的直接子元素B
<div class="container">
<div class="box">Box 1</div>
<div class="inner">
<div class="box">Box 2</div>
</div>
</div>

<style>
.container > .box { background-color: yellow; }
</style>

<!-- 仅会选中 .container 的直接子元素 .box(Box 1),不包括嵌套的 Box 2 -->
  • 后代选择器: A B: 选择A元素内的所有B元素, 不论层级深度
<div class="container">
<div class="box">Box 1</div>
<div class="inner">
<div class="box">Box 2</div>
</div>
</div>

<style>
.container .box { border: 1px solid black; }
</style>

<!-- 会选中 .container 内的所有 .box 元素,包括 Box 1 和 Box 2 -->

伪类

条件伪类

  • :lang(): 基于元素语言来匹配页面元素
<p lang="en">Hello, world!</p>
<p lang="fr">Bonjour, le monde!</p>
<p lang="zh">你好,世界!</p>

<style>
p:lang(en) { color: blue; }
p:lang(zh) { color: red; }
</style>

<!-- lang="en" 的段落文字变蓝, lang="zh" 的段落文字变红 -->
  • :dir(): 匹配特定文字书写方向的元素
<p dir="ltr">Left to Right text.</p>
<p dir="rtl">من اليمين إلى اليسار.</p>

<style>
p:dir(ltr) { background-color: lightblue; }
p:dir(rtl) { background-color: lightgreen; }
</style>

<!-- 从左到右(ltr)的段落背景变蓝, 从右到左(rtl)的段落背景变绿 -->
  • :has(): 选择包含某个特定子元素的父元素
<div>
<p class="child">This is a child paragraph.</p>
</div>
<div>
<span>No child paragraph here.</span>
</div>

<style>
div:has(.child) { border: 2px solid red; }
</style>

<!-- 包含类名为 child 的段落 <p> 的 <div> 会有红色边框 -->
  • :is(): 选择与列表中任意选择器匹配的元素
<h1>Heading 1</h1>
<h2>Heading 2</h2>
<h3>Heading 3</h3>

<style>
:is(h1, h2) { font-style: italic; }
</style>

<!-- h1 和 h2 元素的文字将变为斜体,而 h3 不受影响 -->
  • :not(): 选择不符合某些条件的元素
<div class="box">Box 1</div>
<div class="container">Container</div>
<div class="box">Box 2</div>

<style>
div:not(.box) { background-color: lightgray; }
</style>

<!-- 类名不是 box 的 <div>(即 Container)背景将变为浅灰色 -->

行为伪类

  • :active: 当用户点击并按住一个元素时,该伪类会生效。一般用于按钮或链接
<button>Click Me</button>
<a href="#">Active Link</a>

<style>
button:active { background-color: darkblue; color: white;}
a:active { color: red; }
</style>

<!-- 按住按钮时,背景颜色变为深蓝,文字变为白色 -->
<!-- 点击并按住链接时,文字颜色变为红色 -->
  • :hover: 当用户将鼠标指针悬停在一个元素上时,该伪类会生效
<div class="hover-box">Hover over me!</div>
<a href="#">Hover Link</a>

<style>
.hover-box:hover { background-color: lightgreen; cursor: pointer; }
a:hover { text-decoration: underline; color: orange; }
</style>

<!-- 鼠标悬停在 .hover-box 上时,背景变为浅绿色,鼠标变为手型 -->
<!-- 鼠标悬停在链接上时,文字加下划线,颜色变为橙色 -->
  • ::selection: 当用户选中文本时,该伪类会生效。可以用于自定义文本选择时的样式(如背景颜色、文字颜色)
<p>
This is a paragraph of text. Select some text to see the effect.
</p>

<style>
::selection { background-color: yellow; color: black; }
</style>

<!-- 选中段落文本时,背景变为黄色,文字变为黑色 -->

状态伪类

  • :target: 匹配当前URL锚点(#)对应的元素
<a href="#section1">Go to Section 1</a>
<a href="#section2">Go to Section 2</a>

<div id="section1">Section 1</div>
<div id="section2">Section 2</div>

<style>
#section1:target { background-color: lightblue; }
#section2:target { background-color: lightgreen; }
</style>

<!-- 点击链接 Go to Section 1,#section1 背景变为浅蓝色 -->
  • :link: 选择未访问的链接
  • :visited: 选择已访问的链接
<a href="https://example.com">Unvisited Link</a>
<a href="https://google.com">Visited Link</a>

<style>
a:link { color: blue; }
a:visited { color: purple; }
</style>

<!-- 未访问的链接文字颜色为蓝色, 已访问的链接文字颜色为紫色 -->
  • :focus: 匹配当前聚焦的表单元素
<input type="text" placeholder="Enter your name">

<style>
input:focus { border: 2px solid green; outline: none; }
</style>

<!-- 输入框聚焦时边框变为绿色 -->
  • :required: 匹配表单中被标记为必填的元素
  • :optional: 匹配表单中未标记为必填的元素
<form>
<input type="text" required placeholder="Required Field">
<input type="text" placeholder="Optional Field">
</form>

<style>
input:required { border: 2px solid red; }
input:optional { border: 2px solid gray; }
</style>

<!-- 必填字段边框为红色, 可选字段边框为灰色 -->
  • :valid: 匹配输入值合法的表单元素
  • :invalid: 匹配输入值不合法的表单元素
<form>
<input type="email" placeholder="Enter your email">
</form>

<style>
input:valid { border: 2px solid green; }
input:invalid { border: 2px solid red; }
</style>

<!-- 输入合法邮箱时,边框变绿, 输入不合法邮箱时,边框变红 -->
  • :in-range: 匹配输入值在设定范围内的元素
  • :out-of-range: 匹配输入值在设定范围外的元素
<form>
<input type="number" min="10" max="100" placeholder="Enter a number">
</form>

<style>
input:in-range { background-color: lightgreen; }
input:out-of-range { background-color: lightcoral; }
</style>

<!-- 输入 10 到 100 之间的数字,背景变绿, 输入范围外的数字,背景变红 -->
  • :checked: 匹配选中的复选框或单选按钮
<form>
<label><input type="checkbox" checked> Checked</label>
<label><input type="checkbox"> Not Checked</label>
</form>

<style>
input:checked { outline: 2px solid blue; }
</style>

<!-- 选中的复选框有蓝色边框 -->
  • :enabled: 匹配启用的表单元素
  • :disabled: 匹配禁用的表单元素
<input type="text" disabled placeholder="Disabled">
<input type="text" placeholder="Enabled">

<style>
input:enabled { background-color: white; }
input:disabled { background-color: lightgray; }
</style>

<!-- 启用的输入框背景为白色, 禁用的输入框背景为浅灰色 -->
  • :read-only: 匹配只读表单元素
  • :read-write: 匹配可编辑表单元素
<input type="text" readonly value="Read-only Field">
<input type="text" value="Editable Field">

<style>
input:read-only { color: gray; }
input:read-write { color: black; }
</style>

<!-- 只读输入框文字为灰色, 可编辑输入框文字为黑色 -->
  • :blank: 匹配没有输入值的表单元素
<form>
<input type="text" placeholder="Leave me blank">
</form>

<style>
input:blank { border: 2px dashed orange; }
</style>

<!-- 未填写的输入框边框为橙色虚线 -->

结构伪类

  • :root: 选择文档的根元素, 在HTML中一般是<html>标签
<html>
<head></head>
<body>
<p>Hello, World!</p>
</body>
</html>

<style>
:root { font-size: 16px; --main-color: blue; }
</style>

<!-- 设置根元素的字体大小和 CSS 自定义属性(变量) -->
  • :empty: 匹配没有子元素(包括文本节点)的元素
<div class="box1"></div>
<div class="box2">Content</div>

<style>
div:empty { background-color: lightgray; }
</style>

<!-- 没有内容的 <div class="box1"> 背景变为浅灰色 -->
  • :first-letter: 选择元素的首字母,用于文本样式的特殊处理
<p>This is a paragraph.</p>

<style>
p:first-letter { font-size: 2em; color: red; }
</style>

<!-- 段落首字母 “T” 字体变大且颜色变红 -->
  • :first-line: 选择元素的首行内容,常用于段落样式的特殊处理
<p>This is a long paragraph to demonstrate first-line styling in CSS.</p>

<style>
p:first-line { font-weight: bold; color: blue; }
</style>

<!-- 段落的第一行文字加粗且变蓝 -->
  • :nth-child(n): 匹配父元素中第n个子元素(从第一个开始计数)
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>

<style>
li:nth-child(2) { color: red; }
</style>

<!-- 第二个 <li> 的文字颜色变为红色 -->
  • :nth-last-child(n): 匹配父元素中倒数第n个子元素
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>

<style>
li:nth-last-child(1) { color: green; }
</style>

<!-- 最后一个 <li> 的文字颜色变为绿色 -->
  • :first-child: 匹配父元素中的第一个子元素
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>

<style>
li:first-child { font-style: italic; }
</style>

<!-- 第一个 <li> 的文字变为斜体 -->
  • :last-child: 匹配父元素中的最后一个子元素
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>

<style>
li:last-child { font-weight: bold; }
</style>

<!-- 最后一个 <li> 的文字加粗 -->
  • :only-child: 匹配父元素中仅有的子元素
<div>
<p class="single">I am the only child!</p>
</div>
<div>
<p>Child 1</p>
<p>Child 2</p>
</div>

<style>
p:only-child { color: purple; }
</style>

<!-- 仅有一个子元素的 <p>(I am the only child!)文字颜色变为紫色 -->
  • :nth-of-type(n): 匹配同类型标签中的第n
<div>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
<span>Span 1</span>
<p>Paragraph 3</p>
</div>

<style>
p:nth-of-type(2) { color: orange; }
</style>

<!-- 第二个 <p>(Paragraph 2)文字颜色变为橙色 -->
  • :nth-last-of-type(n): 匹配同类型标签中的倒数第n
<div>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
<p>Paragraph 3</p>
</div>

<style>
p:nth-last-of-type(1) { color: brown; }
</style>

<!-- 倒数第一个 <p>(Paragraph 3)文字颜色变为棕色 -->
  • :first-of-type: 匹配同类型标签中的第一个
<div>
<p>First Paragraph</p>
<p>Second Paragraph</p>
</div>

<style>
p:first-of-type { text-decoration: underline; }
</style>

<!-- 第一个 <p> 的文字加下划线 -->
  • :last-of-type: 匹配同类型标签中的最后一个
<div>
<p>First Paragraph</p>
<p>Last Paragraph</p>
</div>

<style>
p:last-of-type { color: teal; }
</style>

<!-- 最后一个 <p> 的文字颜色变为青色 -->
  • :only-of-type: 匹配父元素中仅有的某种类型的标签
<div>
<p>Unique Paragraph</p>
</div>
<div>
<span>Not Unique</span>
<p>Another Paragraph</p>
</div>

<style>
p:only-of-type { background-color: yellow; }
</style>

<!-- 父元素中仅有的 <p>(Unique Paragraph)背景变为黄色 -->

伪元素

  • ::before: 在在元素内容之前插入内容
    • ::before是一个伪元素,必须与content属性一起使用,否则不会生效
<p class="example">This is a paragraph.</p>

<style>
.example::before { content: "★ "; color: gold; font-size: 1.5em; }
</style>

<!-- 在段落内容之前插入一个金色的星星符号 -->
  • ::after: 在元素内容之后插入内容
    • ::before类似,必须与content属性一起使用
<p class="example">This is a paragraph.</p>

<style>
.example::after { content: " ✎"; color: gray; font-size: 1.2em; }
</style>

<!-- 在段落内容之后插入一个灰色的铅笔符号 -->

CSS优先级

优先级就是分配给指定的CSS声明的一个权重, 它由匹配的选择器中的每一种选择器类型的数值决定。可以把权重分成如下几个等级, 数值越大的权重越高

  • 10000: !important
  • 01000: 内联样式 (inline style)
  • 00100: ID选择器
  • 00010: 类选择器、伪类选择器、属性选择器
  • 00001: 元素选择器、伪元素选择器
  • 00000: 通配选择器、后代选择器、兄弟选择器

可以看到内联样式(通过元素中style属性定义的样式)的优先级大于任何选择器。而给属性值加上!important又可以把优先级提至最高,就是因为它的优先级最高,所以需要谨慎使用它


CSS层叠性

层叠样式表(CSS)中的“层叠”是其核心特性之一,它指的是当多个CSS声明可以作用于同一个HTML元素时,如何确定最终生效的样式。这是通过一套明确的算法来完成的,用于合并来自多个来源的属性值

  • 针对不同源的样式,将按照如下的顺序进行层叠,越往下优先级越高
    • 用户代理样式表: 浏览器自带的默认样式,如果我们不设置任何样式,浏览器会使用这些规则。例如,默认的段落<p>有一些上下边距
    • 作者样式表: 开发者定义的样式,通常是我们编写的CSS文件或内联样式。这些样式会覆盖浏览器的默认样式
    • 作者样式表中的!important声明: 如果开发者在样式中添加了!important,那么它的优先级最高,哪怕有其他规则覆盖,它也会生效

理解层叠性的时候需要结合CSS选择器的优先级以及继承性来理解。比如针对同一个选择器,定义在后面的声明会覆盖前面的, 作者定义的样式会比默认继承的样式优先级更高


@规则

@规则是一种特殊的CSS语句,用于在样式表中定义一些全局配置或条件规则,而不仅仅是常规的样式规则。以下是CSS中常用的@规则

  • @namespace: 用于定义XML命名空间(适用于特定的XML文件样式需求)
@namespace svg "http://www.w3.org/2000/svg";

/* 仅对 SVG 元素应用样式 */
svg|circle {
fill: red;
}

/* 作用:定义 svg 命名空间,并对 <circle> 元素应用样式 */
  • @media: 用于为不同设备或屏幕条件设置样式
@media (max-width: 600px) {
body {
background-color: lightblue;
}
}

@media print {
body {
font-size: 12px;
color: black;
}
}

/* 如果屏幕宽度小于或等于 600px,背景变为浅蓝色 */
/* 打印时,字体变小并使用黑色 */
  • @page: 用于设置打印页面的布局(如页边距)
@page {
margin: 1in;
}

@page :first {
margin-top: 2in;
}

/* 设置默认打印页面的页边距为 1 英寸 */
/* 第一页的上边距增加到 2 英寸 */
  • @font-face: 定义和加载自定义字体
@font-face {
font-family: "CustomFont";
src: url("customfont.woff2") format("woff2");
}

body {
font-family: "CustomFont", sans-serif;
}

/* 从外部加载名为 CustomFont 的字体并应用到页面 */
  • @keyframes: 定义动画的关键帧
@keyframes slide-in {
from {
transform: translateX(-100%);
}
to {
transform: translateX(0);
}
}

div {
animation: slide-in 1s ease-out;
}

/* 定义一个从左侧滑入的动画,并将其应用到 <div> 元素上 */
  • @import: 用于导入外部CSS文件, 与<link>的区别如下
    • <link>HTML标签,可导入CSS、图片、脚本等资源。@importCSS规则,仅能导入CSS文件
    • <link>会在页面加载时同时加载CSS@import会等页面加载完成后再加载CSS (所以@import字体会在网页加载结束后才会被应用)
@import url("styles.css");
  • @supports: 用于检测浏览器是否支持某些CSS特性,从而有条件地应用样式。可以使用notandor逻辑操作符
/* 默认样式 */
body {
background-color: white;
color: black;
transition: all 0.3s ease;
}

/* 如果支持 color-scheme,则设置支持深色模式 */
@supports (color-scheme: dark) {
body {
color-scheme: dark;
background-color: var(--background, black);
color: var(--text, white);
}
}

/* 如果用户偏好减少动画 */
@supports (prefers-reduced-motion: reduce) {
* {
transition: none;
animation: none;
}
}

/* 如果浏览器支持 color-scheme,页面会启用深色模式的默认样式或定义的变量 */
/* 如果用户设置了减少动画偏好(通过系统设置),页面会禁用所有过渡和动画效果 */
/* 如果两者都不支持,则使用默认样式(浅色背景,黑色文字,带有过渡效果) */

CSS继承性

继承性是CSS中的一个重要特性,指的是子元素可以继承父元素某些 属性计算后的值。例如,html元素的文本颜色默认是黑色,页面中的所有子元素会继承这个颜色属性,除非显式指定其他颜色。

body {
color: orange;
}

h1 {
color: inherit;
}

继承的作用

  • 继承性可以减少样式代码的冗余,提高代码的可维护性
    • 如果CSS不支持继承,那么我们需要为每个文本标签都单独设置颜色或字体,导致样式代码冗长,文件体积变大,维护成本增加

继承的默认行为

CSS属性很多,但并不是所有的属性默认都是能继承父元素对应属性的,那哪些属性存在默认继承的行为呢?一定是那些不会影响到页面布局的属性,可以分为如下几类

  • 字体相关: font-familyfont-stylefont-sizefont-weight
  • 文本相关: text-aligntext-indenttext-decorationtext-shadowletter-spacingword-spacingwhite-spaceline-heightcolor
  • 列表相关: list-stylelist-style-imagelist-style-typelist-style-position
  • 其他属性: visibilitycursor

显式控制继承行为

对于其他默认不继承的属性也可以通过以下几个属性值来控制继承行为

  • inherit: 强制继承父元素对应属性的计算值
p {
border: inherit;
}

/* p 的边框样式将继承自父元素 */
  • initial: 将属性恢复为CSS的默认值
p {
color: initial;
}

/* p 的颜色将恢复为默认值(如黑色 #000) */
  • unset
    • 如果属性默认可以继承,则效果等同于inherit
    • 如果属性默认不继承,则效果等同于initial
p {
color: unset;
}

CSS文档流

CSS的世界中,文档流是内容按照从左到右、从上到下的顺序排列和显示的一种默认布局方式。通常情况下,页面会被分割成一行一行的显示,每行可能包含多个元素。从视觉效果来看,文档流呈现为从上到下、从左到右的排列方式。这种布局也被称为流式布局,类似水流般灵活,可以自适应所在的容器

什么是文档流

  • 在没有额外样式(如positionfloat)的情况下,HTML元素会按照文档流的默认规则进行排列
  • 块级元素: 占据一整行,从上到下垂直排列,例如 <div><p>
  • 行内元素: 按从左到右的顺序水平排列,例如 <span><a><strong>
<div>块级元素 1</div>
<div>块级元素 2</div>
<span>行内元素 1</span>
<span>行内元素 2</span>
块级元素 1
块级元素 2
行内元素 1 行内元素 2

脱离文档流

脱离文档流指的是将某个元素从正常文档流中移除后,其他元素将忽略该元素的存在,并填补其原先占据的空间。脱流的元素不会影响父容器的高度计算,即脱流元素不占据空间

  • 有以下两种常见方式可以使元素脱离文档流

浮动float

浮动(float)属性最初在CSS中被引入是为了实现文字环绕图片的效果

如果没有floatimg默认是inline元素,那么文字图片的显示就会像这样

  • 使用float会让元素脱离正常文档流,移动到父容器的左/右侧
  • 后续的块级元素不会受到浮动元素的影响,但其他浮动或行内元素会受影响
<div style="float: left;">浮动元素</div>
<div>普通元素</div>

<!-- 浮动元素在左侧,普通元素从浮动元素的下方开始排列 -->

现代的CSS布局技术如FlexboxGrid已经几乎完全取代了浮动布局,但在某些特定情况下,浮动仍然有其用武之地,比如文字环绕图片和简单的左对齐或右对齐

定位position

绝对定位 (absolute)

  • 使用position: absolute;脱离文档流
  • 元素的位置由最近的非静态父容器决定,空出的位置会被后续节点填补

固定定位 (fixed)

  • 使用position: fixed;脱离文档流
  • 元素的位置固定在视口的某处,不受滚动影响
<div style="position: absolute; top: 50px; left: 100px;">绝对定位元素</div>
<p>这是一段普通文本,将填补绝对定位元素的位置。</p>

附录

文件还未上传 Github