前端知识体系之 CSS 指南

127 阅读19分钟

CSS 指南

本文档用于梳理 CSS 的重难点知识,用于复习巩固, 也用于面试谈经。

CSS 入门

官方文档:developer.mozilla.org/zh-CN/docs/…

CSS 语法

1 CSS 选择器

CSS 选择器:一个标记,用来指定 CSS 规则使用的 HTML 元素。选择器所选择的元素,叫做“选择器的对象”。

1.1 选择器分类

CSS 选择器的类型:

  • 基础选择器:标签选择器(elementname)、类选择器(.classname)、ID 选择器(#idname)、属性选择器([attr=value])、通配选择器(*)。
  • 组选择器:选择器列表(A, B)
  • 关系选择器:兄弟选择器(A ~ B)、邻近兄弟选择器(A + B)、后代选择器(A B)、直接后代选择器(A > B)
  • 伪选择器:伪类(:)、伪元素(::)

1.2 选择器重要性

CSS 是层叠样式表,同一个元素可以匹配多个 CSS 规则,如果发生规则冲突,就会按照重要性来选择。

CSS 规则的重要性由以下 3 个因素决定:

  1. 重要程度:最重要的因素。
  2. 优先级:排第二的因素。
  3. 资源排序:排最后的因素。
1.2.1 重要程度

重要程度由以下因素决定:内联样式、!important声明。

内联样式: style 属性内的样式声明。它优先于所有普通的样式,无论其优先级如何。

!important 声明:使用 !important 声明的样式优先于内联样式。示例:

.box {
  color: blue !important;
}

注意:内联样式中也可以使用 !important 声明。

1.2.2 优先级

选择器的优先级由三个不同的值(或分量)相加:

  • ID:选择器中包含 ID 选择器,则加 100。
  • :选择器中包含类选择器、属性选择器或者伪类,则加 10。
  • 元素:选择器中包含元素、伪元素选择器,则加 1。

选择器的优先级的示例:

选择器ID元素优先级
h10010-0-1
h1 + p::first-letter0030-0-3
li > a[href*="en-US"] > .inline-warning0220-2-2
#identifier1001-0-0
button:not(#mainBtn, .cta)1011-0-1

备注: 其他的选择器不会影响优先级。

1.2.3 资源顺序

资源顺序:相同权重的 CSS 规则,会应用最后面的规则。

1.3 CSS 继承

CSS 继承:父元素的某些属性会被子元素继承。比如:color 、font-family 属性。

控制继承:CSS 为属性的继承提供了五个特殊值,用于指导元素如何继承属性。

  • inherit:继承父元素的属性值。
  • initial:使用该元素的初始值
  • revert:使用浏览器的默认值。在许多情况下,此值的作用类似于 unset。
  • revert-layer:使用上一个层叠层中建立的值。
  • unset:使用自然值。也就是如果属性是自然继承那么就是 inherit,否则和 initial 一样。

2 CSS 级联层

2.1 定义

级联层:显式特异性容器。它将 CSS 规则划分为多个层,然后根据层的顺序来确定 CSS 的重要性。它可以简化 CSS 的重要性:

  • 如果不使用级联层,确定重要性需要考虑三个因素:重要程度、优先级、资源排序。其中优先级的计算是最复杂的。

  • 如果使用级联层,确定重要性只需考虑二个因素:重要程度、级联层排序。

    • 未在级联层中声明的所有 CSS 规则,会被当做最后一个级联层。
    • 对于常规(没有 !important 声明)的规则冲突,后面的层比前面的重要性高。
    • 对于有 !important 声明的规则冲突,前面的层比后面的重要性高。

级联源:浏览器默认的级联层。有以下三种:

  • 用户代理样式表:浏览器默认的样式。
  • 用户样式表:网站访问者在浏览器的配置文件中设置的样式。
  • 作者样式表:开发者声明的普通样式。

2.2 创建级联层

创建级联层:使用 @layer 声明。示例:

<style>
  /* 创建级联层,并定义其顺序。 */
  @layer theme,layout;
​
  /* 默认层:排最后一层。 */
  body {
    color: #333;
  }
​
  /* theme:排第一层 */
  @layer theme {
    body {
      display: grid;
    }
  }
​
  /* layout:排第二层 */
  @layer layout {
    body {
      display: grid;
    }
  }
​
  /* 创建的匿名层:排第三层 */
  @layer {
    body {
      margin: 0;
    }
  }
</style>

引用级联层:使用 @import layer()。示例:

@import url("lib.css") layer(theme);

2.3 级联层的排序

级联层的排序:

顺序(从低到高)起源重要性
1用户代理正常
2用户正常
3自定义级联层正常
4作者正常
5CSS 动画
6作者!important
7自定义级联层!important
8用户!important
9用户代理!important
10CSS 过渡(正在转换的样式)

为什么用户代理的 !important 样式重要性最高?

因为用户代理样式表中一般有两类样式:默认样式、规范样式。默认样式可以随便修改;规范样式就是 !important 样式,是一种严格规范,是不能修改的,所以它的重要性最高。

2.4 级联层嵌套

创建嵌套级联层:

@layer theme.layout {
  body {
    width: 50vw;
  }
}

引用嵌套级联层:

@import url("lib.css") layer(theme.layout);

3 CSS @规则

@规则是一些特殊规则,提供 CSS 如何表现的指导。

@import:导入外部样式表。示例:

@import 'styles2.css';

@import 与 link 的区别?

  • @import 是 CSS 方式;link 是 HTML 方式
  • @import 的样式在 CSS 文件解析之后同步加载;link 的样式加载页面之前异步加载
  • @import 只能导入样式表;link 可以通过 ref 指定候选样式

@media:使用媒体查询来应用 CSS。示例:

body {
  background: pink;
}
​
/* 定义视窗宽度大于等于 30em 的样式 */
@media (min-width: 30em) {
  body {
    background: blue;
  }
}

4 CSS 函数

var() 可以插入一个自定义属性(也叫 CSS 变量,是以 -- 开头的属性),比如:

:root {
  --main-bg-color: pink;
}
​
body {
  background-color: var(--main-bg-color);
}

attr() 可以获取 HTML 元素的 data-* 属性,比如:

<style>
  p:before {
    content: attr(data-foo) ' ';
  }
</style>
<p data-foo="hello">world</p>

calc() 用于对 CSS 属性值进行计算,比如:

width: calc(100% - 80px);

CSS 属性

CSS 的属性非常多,下面介绍一些重要的属性。

1 布局属性

布局属性用于控制元素的位置。

1.1 布局类型

CSS 的布局类型包含以下几种:

CSS 的布局行为由以下属性共同决定:

  • position 属性:

    • 当值为 absolute、fixed 时,优先级排第一;
    • 当值为 relative、sticky 时,优先级排第二;
    • 当值为其他时,不影响布局行为。
  • float 属性:优先级排第二

  • display 属性: 优先级排第三。

1.2 定位布局

定位布局:position 属性为非 static 的布局方式。

定位布局会根据指定的位置精确摆放元素,常用于不规则的复杂布局。

position 属性:控制元素的定位方式。可能的值:

  • static:静态定位,按照正常的方式排列元素。

  • relative:相对定位,按照相对于静态定位的位置摆放元素。

  • absolute:绝对定位,按照相对于最近的非 static 定位祖先元素的位置来摆放元素。绝对定位会脱离正常文档流。

  • fixed:固定定位,按照相对于窗口(viewport)的位置来摆放元素。

    • 它会脱离正常文档流,并且创建新的层叠上下文。
    • 窗口滚动时,它不会移动。
    • 当元素祖先的 transformperspectivefilterbackdrop-filter 属性非 none 时,容器由窗口改为该祖先。
  • sticky:粘性定位,按照相对于最先滚动祖先的位置摆放元素。最近滚动祖先滚动时,它不会移动。

在定位布局中,元素的位置由 top、right、bottom、 left 属性决定,元素的层叠优先级由 z-index 属性决定。

1.3 浮动布局

1.3.1 介绍

浮动布局:position 属性为非 absolute、fixed,并且 float 属性为非 none 的布局方式。

浮动布局常用于图片环绕效果。它有以下特点:

  • 它会脱离正常文档流;它的盒子区域会与其他盒子重叠,但是内容区域不会重叠。
  • 按照 float 属性值的方向,按照代码顺序,先排列浮动(具有 float 属性)元素,再排列非浮动元素。
  • 浮动元素默认没有滚动条。

float 属性:控制元素的左右浮动。可能的值:

  • none:不进行浮动
  • left:元素必须浮动在其所在的块容器左侧
  • right:元素必须浮动在其所在的块容器左侧
  • inline-start:元素必须浮动在其所在块容器的开始一侧。开始位置由 writing-mode 属性决定。
  • inline-end:元素必须浮动在其所在块容器的结束一侧。结束位置由 writing-mode 属性决定。
1.3.2 清除浮动

浮动元素附近的普通元素会环绕在浮动元素周围,为了清除环绕效果(使其在下方展示),需要对其使用 clear 属性。

clear 属性:用来清除受到的浮动影响。可能的值:

  • left:停止任何活动的左浮动
  • right:停止任何活动的右浮动
  • both:停止任何活动的左右浮动
1.3.3 解决溢出问题

当浮动元素高于非浮动元素时,浮动元素会溢出其父元素,因为浮动元素脱离了文档流。为了解决溢出问题,有以下三种方式:

第一种方式:clearfix 小技巧。它先向浮动元素的父元素的最下方插入空白内容,然后将生成的内容清除浮动。示例:

.wrapper::after {
  content: "";
  clear: both;
  display: block;
}

这与在浮动盒子后手动添加诸如 div 的 HTML 元素,并设置其样式为 clear:both 是等效的。

第二种方式:使用 overflow 属性。它将浮动元素的父元素的 overflow 属性设置为除 visible 外的其他值。示例:

.wrapper {
  overflow: auto;
}

第三种方式:使用 flow-root 。它将浮动元素的父元素的 dispaly 属性设置为 flow-root 。示例:

.wrapper {
  display: flow-root;
}

注意

  • 第三种方式的兼容性不太好,需要检测浏览器是否支持
  • 以上三种方式都是将元素变为 BFC 元素。

2 背景属性

background 属性:定义元素的背景。

2.1 背景简写

background 简写可以包含多个背景内容(包括背景颜色和背景图片),示例:

.bd {
  background: url(img/demo.png) center center / 100px 100px no-repeat, red;
}

当 background 属性包多个背景内容时,需要遵循以下规则:

  • 多个背景内容之间,需要是逗号隔开。
  • background-size 值只能包含在背景位置之后,并且用 '/' 字符分隔,例如:center / 80%

2.2 渐变背景

gradient 函数用于设置渐变背景,包含三种类型:

  • 线型渐变:linear-gradient(),颜色值沿着一条隐式的直线逐渐过渡。
  • 径向渐变:radial-gradient(),颜色值由一个中心点(原点)向外扩散并逐渐过渡到其他颜色值
  • 重复渐变:repeating-linear-gradient() 和 repeating-radial-gradient(),重复多次渐变图案直到足够填满指定元素。

下面是一个简单的线型渐变:

<style>
  div {
    height: 50px;
    background: linear-gradient(105deg, red 0%, white 40%, green 80%);
  }
</style>
<div />

其中,105 deg 是渐变的方向(按照顺时针方向,0 deg表示正上方),red 0% 是开始位置的颜色。

使用 repeating-linear-gradient 可以实现斑马纹效果,比如:

<style>
  div {
    width: 200px;
    height: 50px;
    /* 方向:左上;重复的区间:0 - 5px 为红色,5 - 10 px 为白色 */
    background: repeating-linear-gradient(to top left, lightpink, lightpink 5px, white 5px, white 10px);
  }
</style>
<div />

使用 repeating-linear-gradient 可以实现水波纹效果,比如:

<style>
  div {
    width: 200px;
    height: 50px;
    background: repeating-radial-gradient(powderblue, powderblue 8px, white 8px, white 16px);
  }
</style>
<div />

2.3 文字背景

文字背景:使用值为 text 的 background-clip 属性和值为 transparent 的 -webkit-text-fill-color 属性,实现背景图片嵌入文字的效果。示例:

<style>
  .clip-text {
    background: url(img/demo.png);
    background-clip: text;
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
  }
</style><h1 class="clip-text">文字背景</h1>

注意: 在谷歌浏览器中,需要使用 -webkit-background-clip 属性。

2.4 混合模式

混合模式:将元素的重叠部分混合后,以新的颜色进行展示。混合模式用于文字视频等特效。

2.4.1 定义

混合模式分为两种:

第一种是 background-blend-mode:定义元素的背景颜色、背景图片如何混合。示例:

<style>
  .background-multiply {
    background-color: red;
    background-image: url(img/demo.png);
    background-blend-mode: multiply;
  }
</style><h1 class="background-multiply">混合背景</h1>

第二种是 mix-blend-mode:定义元素的内容和背景与其重叠元素的内容和背景如何混合。示例:

<style>
  .normal {
    background: red;
  }
  .mix-multiply {
    position: relative;
    top: -50px;
    background: green;
    mix-blend-mode: multiply;
  }
</style><h1 class="normal">正常元素</h1>
<h1 class="mix-multiply">混合元素</h1>

混合模式的值由 blend-mode 决定,它包含以下几种常用的值:

  • normal:最终颜色为顶层颜色。
  • multiply:最终颜色为顶层颜色与底层颜色相乘的结果。 如果叠加黑色层,则最终层必为黑色层,叠加白色层不会造成变化。 其效果类似于在透明薄膜上重叠印刷的两个图像。
  • screen:最终的颜色是反转顶层颜色和底层颜色,将反转后的两个颜色相乘,再反转相加得到的和得到的结果。 黑色层不会造成变化,白色层导致白色最终层。 其效果类似于(被投影仪)投射到投影屏幕上的两个图像。
2.4.2 文字视频

文字视频:使用值为 screen 的 mix-blend-mode 属性,可以实现视频嵌入文字的效果。示例:

<style>
  .box {
    position: relative;
    /*  设置 font-size 为 0,是为了消除视频下方空隙 */
    font-size: 0;
  }
  .mix-screen {
    position: absolute;
    top: 0;
    height: 100%;
    color: black;
    font-size: 100px;
    font-weight: bold;
    background: white;
    mix-blend-mode: screen;
  }
</style>
<div class="box">
  <video src="img/movie.ogv" muted autoplay loop></video>
  <div class="mix-screen">文字视频</div>
</div>

3 变换属性

CSS 变换用于在不影响正常文档流的情况下改变元素的位置,支持二维平面和三维空间的旋转、倾斜、缩放、平移。注意: 只能对块级元素进行 CSS 转换。

详细文档:developer.mozilla.org/zh-CN/docs/…

4 动画属性

动画属性分为两种:animation 和 transition。

5 编辑属性

编辑属性用于改变元素的形状、模糊等

5.1 裁剪

clip-path 属性:使用裁剪方式创建元素的可显示区域。裁剪用于自定义形状。示例:

.shape {
  background: red;
  /* 圆形:半径-10px、圆心-盒子中心*/
  clip-path: circle(10px at 50% 50%);
}

5.2 滤镜

filter 属性:将模糊或颜色偏移等图形效果应用于元素。滤镜通常用于调整图像、背景和边框的渲染。示例:

.filter {
  /* 对输入图像应用阴影效果。 */
  filter: drop-shadow(5px 5px 1px rgba(0,0,0,0.7));
}

5.3 遮罩

mask:CSS 属性,根据遮罩元素的透明度来展示被遮挡元素。遮罩常用于切换图标颜色。示例:

.target {
  mask: url(#c1) luminance;
}

说明:在谷歌浏览器中,使用 mask 属性引用 svg 时,会有兼容性问题。

CSS 机制

1 盒模型

1.1 定义

CSS 盒模型是指按照盒子的结构描述元素,包含以下部分:

  • Content box(内容) : 显示内容的区域,大小由 width 和 height 决定。
  • Padding box(内边距) : 包围内容的空白区域;大小由 padding 决定。
  • Border box(边框) : 包围内边距的边界。大小由 border 相关决定。
  • Margin box(外边距) :包围边框的空白区域。大小由 margin 决定。

CSS 盒模型的类型由 box-sizing 属性决定,分为以下两种:

  • content-box:标准盒模型,是 box-sizing 的默认值。标准盒模型中,width 与 height 只包括内容的宽高,不包括边框、内边距。
  • border-box:替代盒模型。替代盒模型中,width 与 height 包括内容的宽高、边框、内边距。

1.2 显示类型

盒子的显示类型是指盒子在布局排版时的展示方式,分为两种:

  • 外部显示类型:盒子整体的展示方式。
  • 内部显示类型:盒子的子元素的展示方式。

盒子的外部显示类型由 display 属性决定,分为以下三种:

  • 块级盒子(Block Box)

    • 会产生换行
    • 会占据父容器在内联方向(行内文本的排列方向)上的所有可用空间。
    • width 和 height 属性可以发挥作用。块级盒子默认与父容器等宽。
    • 内边距、外边距、边框会推开其他盒子
  • 内联盒子(Inline Box)

    • 不会产生换行。
    • width 和 height 属性将不起作用。
    • 垂直方向的内边距、外边距、边框会被应用,但不会把其他处于 inline 状态的盒子推开。
    • 水平方向的内边距、外边距、边框会被应用,并且会把其他处于 inline 状态的盒子推开。
  • 内联块盒子(Inline-block Box):可以实现块级盒子的部分效果

    • 不会产生换行
    • width 和 height 属性可以发挥作用
    • 内边距、外边距、边框会推开其他盒子

注意: 行内元素的高度由 font-size 和 父元素的 line-height 决定:

  • 第一行的高度:font-size × 1.3125
  • 第N行的高度:父元素的 line-height

1.3 外边距重叠

外边距重叠:块级盒子的上外边距和下外边距合并为一个外边距,其大小为单个边距的最大值。

有三种情况会形成外边距重叠:

  • 同一层相邻元素之间:A 元素的下外边距和 B 元素的上外边距合并。
  • 父元素和后代元素之间没有内容:父元素的上外边距和后代元素的上外边距合并;父元素的下外边距和后代元素的下外边距合并。没有内容是指没有边框、内边距、行内内容。
  • 两个元素之间是空的块级元素:A 元素的下外边距和 B 元素的上外边距合并。空的块级元素是指没有边框、内边距、行高内容、高度。

注意: BFC 元素和其子元素不会产生外边距重叠行为。

1.4 滚动条

当元素超出窗口时,默认会在窗口(html 元素的上层)中展示滚动条。

如果希望在指定元素中展示滚动条,需要满足以下条件:

  • 元素需要指定高度,并且元素的内容高度大于父元素高度
  • overflow 的值为 scroll 或 auto

注意:

  • 滚动条出现的位置在盒子的边框内。
  • 当元素的内容溢出并且不支持滚动条时,就会在支持滚动条的最近祖先元素中展示滚动条。

2 层叠上下文

z-index 属性:指定层叠上下文中元素的优先级。

当元素满足以下任一条件时,它会形成一个独立的层叠上下文:

  • html 元素
  • 固定定位或粘性定位的元素。
  • z-index 不为 auto 的相对定位或绝对定位元素。
  • z-index 不为 auto 的网格布局子元素。
  • z-index 不为 auto 的弹性布局子元素。

注意:元素的 z-index 属性只有在层叠上下文中才会生效,如果父元素不是层叠上下文,那么它会找最近的层叠上下文。

3 块格式化上下文

块格式化上下文(Block Formatting Context,BFC)是块级盒子的、能够包含浮动元素的布局区域。

下面的元素会创建块格式化上下文:

  • html 元素
  • 浮动元素
  • 绝对定位或固定定位元素
  • 行内块元素(display 值为 inline-block)

格式化上下文会影响盒子布局,会产生以下影响:

  • 包含内部浮动:BFC 元素会包含浮动元素。
  • 排除外部浮动:BFC 元素不会与浮动元素的盒子区域重叠。
  • 阻止外边距重叠:BFC 元素和其子元素不会产生外边距重叠行为。

4 响应式设计

响应式网页设计(responsive web design,RWD):是允许 Web 页面适应不同屏幕宽度因素等,进行布局和外观的调整的一系列实践。

响应式设计由以下技术组成:

  • 媒体查询:根据不同的屏幕尺寸设计不同的样式。
  • 灵活网格:使用百分比单位指定元素的宽度。
  • 响应式图片:根据不同的屏幕选择不同的图片。
  • 响应式排版:根据不同的屏幕使用不同的字体大小。

4.1 媒体查询

媒体查询:根据不同的屏幕尺寸设计不同的样式。示例:

/* 当屏幕宽度大于等于 800px 时 */
@media screen and (min-width: 800px) {
  .container {
    margin: 1em 2em;
  }
}

4.2 灵活网格

灵活网格:使用百分比单位指定元素的宽度。比如,元素的宽度是 100px ,父元素的宽度为 1000px ,那么元素的百分比宽度就是 10/1000=10%。

多列布局、网格布局、弹性布局都属于灵活网格的范畴。

4.3 响应式图片

在早期处理图片时,通过 max-width: 100%; 样式,让图片不会溢出,并且保持图片的清晰度。

img {
  max-width: 100%;
}

这种方式有两个弊端:

  • 小屏手机加载大图时,会浪费宽带
  • 无法切换图片。因为在移动端,可能需要换另一张图片,以保证最佳的用户体验。

所以,就有了响应式图片的出现。它通过 picture元素和 img 元素的 srcset 和 sizes 属性,现实不同的屏幕加载不同的图片。详情见响应式图像指南

4.4 响应式排版

响应式排版:根据不同的屏幕使用不同的字体大小。响应式排版有两种方案:

第一种方案:使用 rem 单位,然后根据媒体查询改变 rem 的大小。示例:

html {
  font-size: 16px;
}
​
h1 {
  font-size: 2rem;
}
​
@media (min-width: 1200px) {
  html {
    font-size: 24px;
  }
}

第二种方案:使用窗口单位 vw。1vw等同于窗口宽度的百分之一。示例:

h1 {
  font-size: 6vw;
}

4.5 窗口元标签

移动端浏览器可能默认将窗口宽度设为 960 px,需要使用窗口元标签来指定窗口宽度为设备宽度。比如:

<meta name="viewport" content="width=device-width,initial-scale=1">

CSS 常见问题

1 元素居中

元素居中的通用方法:

第一种,flex,比如:

.container {
  display: flex;
  align-items: center;
  justify-content: center;
}

注意:有多个子元素时,默认水平排列,并且间距为 0。

第二种,grid,比如:

.container {
  display: grid;
  place-items: center;
}

注意:有多个子元素时,默认垂直排列,并且间距相等(大于 0)。

第三种,margin,比如:

.container {
  display: flex;
  /* 或者 display: grid; */
}
.box {
  margin: auto;
}

注意:在 flex 布局中,有多个子元素时,默认水平排列,并且间距相等(大于 0)。

第四种,transform,比如:

.container {
  position: relative;
}
.box {
  position: absolute;
  top: 50%;
  left: 50%;
  /* translateX(-50%) 表示沿着 X 轴的反方向平移自身的 50% */
  transform: translateX(-50%) translateY(-50%);
}

注意:有多个子元素时,需要单独计算位置。

元素居中的简便方法:

如果是行内元素的水平对齐,可以对父元素使用 text-align: center;;如果是块级元素的水平对齐,可以对子元素使用 margin: auto;

如果是单个元素的垂直居中,可以对父元素使用 line-height: [元素高度];