CSS详解
前言
在之前的CSS 基础知识入门文章中,我们介绍了CSS的基本概念和常用选择器和三种引入方式。本文将更深入地探讨CSS的详细内容,包括CSS的语法解析、值的单位、层叠与继承、盒模型、文档流、布局方式、伪类和伪元素。
CSS语法解析
CSS的基本语法
CSS的基本语法由选择器(selector)和声明块(declaration block)组成。选择器用于指定要应用样式的HTML元素,声明块包含一个或多个声明,每个声明由属性(property)和属性值(value)组成。CSS语法的基本结构如下:
|
|
例如:
|
|
在这个例子中,p是选择器,表示所有的段落元素;color是属性,表示文本颜色;red是属性值,表示将文本颜色设置为红色。声明块就是用大括号{}包裹起来的部分,可以包含多个声明,每个声明之间用分号;分隔。
CSS的注释
在CSS中,可以使用/*和*/来添加注释。注释不会被浏览器解析和渲染,只用于提高代码的可读性和维护性。注释的语法如下:
|
|
CSS的@规则
@规则用于定义CSS中的特殊指令,如导入外部样式表、定义媒体查询等。常见的@规则包括:
@import:用于导入其他CSS文件。@media:用于定义响应式样式,根据不同的设备特性应用不同的样式。@font-face:用于定义自定义字体。@keyframes:用于定义动画关键帧。@charset:用于指定CSS文件的字符编码。@supports:用于检测浏览器是否支持某个CSS特性。
CSS的值的单位
CSS中常用的值的单位包括绝对单位和相对单位两大类。
绝对单位
绝对单位是指固定的长度单位,不会随着环境的变化而变化。常见的绝对单位包括:
px(像素):最常用的单位,表示屏幕上的一个点。cm(厘米):表示厘米。mm(毫米):表示毫米。in(英寸):表示英寸,1英寸=2.54厘米。pt(磅):表示印刷字体的大小,1pt=1/72英寸。pc(派卡):表示印刷字体的大小,1pc=12pt。
相对单位
相对单位是相对于其他单位或环境的变化而变化的单位。常见的相对单位包括:
%(百分比):相对于父元素的大小。em:相对于当前元素或者父元素的字体大小。rem:相对于根元素的字体大小。vw(视口宽度):相对于视口的宽度,1vw=1%视口宽度。vh(视口高度):相对于视口的高度,1vh=1%视口高度。
CSS的层叠
CSS的全称是层叠样式表(Cascading Style Sheets),其中“层叠”指的是当多个样式规则应用于同一个元素时,浏览器如何决定最终应用哪一个规则,也即优先级的概念。CSS的层叠规则主要包括以下几个方面:
重要性(Importance)
使用!important声明的样式规则优先级最高,会覆盖其他规则。
示例:
|
|
在这个例子中,段落文本的颜色将是蓝色,因为!important使得第一个定义p样式的优先级最高。
后者居上
当多个规则具有相同的重要性时,后定义的规则会覆盖先定义的规则。
示例:
|
|
在这个例子中,段落文本的颜色将是蓝色,因为后定义的规则覆盖了先定义的规则。
来源(Source)
CSS样式可以来自不同的来源,优先级从高到低依次为:内联样式、嵌入式样式(<style>标签内)、外部样式表(通过<link>标签引入)。
示例:
|
|
在这个例子中,段落文本的颜色将是橙色,因为内联样式的优先级最高。
特异性(Specificity)
特异性是根据选择器的类型和数量来计算的,特异性高的规则优先级更高。特异性的计算规则如下:
- 内联样式(如
style属性)具有最高的特异性。 - ID选择器(如
#id)的特异性高于类选择器(如.class)。 - 类选择器、属性选择器和伪类选择器的特异性高于元素选择器(如
div、p)。 - 通用选择器(
*)和组合选择器的特异性最低。 示例:
|
|
在这个例子中,段落文本的颜色将是绿色,因为ID选择器的特异性最高。特异性也可以理解成具体程度,越具体的选择器优先级越高。
积分规则
CSS的优先级可以通过积分规则来计算:
- !important:10000分
- 内联样式:01000分
- ID选择器:00100分
- 类选择器、属性选择器和伪类选择器:00010分
- 元素选择器和伪元素选择器:00001分
例如:
|
|
在这个例子中,#header p的总积分为00101,.header p的总积分为00011,p的总积分为00001。因此,段落文本的颜色将是绿色,因为它具有最高的积分。在使用多个选择器时,可以通过计算积分来确定最终应用的样式规则。
CSS的继承
CSS的继承是指某些CSS属性会从父元素传递给子元素。并不是所有的CSS属性都具有继承性,只有一些特定的属性会被继承,我们可以根据常识来判断,不会影响到页面布局的属性通常都能被继承。常见的可继承属性包括:
- 文字属性:
color、font-family、font-size、font-style、font-weight、line-height、text-align等。 - 列表属性:
list-style、list-style-type、list-style-position等。 - 表格属性:
border-collapse、border-spacing等。 而像margin、padding、border、width、height等属性则不会被继承。
继承的控制
可以使用inherit、initial、unset和关键字来控制继承行为:
inherit:强制子元素继承父元素的属性值。
示例:
|
|
inherit:强制子元素继承父元素的属性值。
示例:
|
|
initial:将属性值重置为其初始值。
示例:
|
|
unset:如果属性是可继承的,则继承父元素的值;如果不可继承,则设置为初始值。
CSS 盒模型
盒模型概述
CSS 盒模型是理解网页布局的基础概念。每个HTML元素都可以看作一个矩形盒子,盒模型由四个部分组成:
- 内容(content):盒子的实际内容区域,如文本或图像,可以用
inline-size和block-size或者width和height来设置内容的宽度和高度。 - 内边距(padding):内容与边框之间的空间,用于增加内容周围的空白区域,用
padding属性来设置大小。 - 边框(border):包围内容和内边距的线条,可以设置宽度、样式和颜色,用
border属性来定义。 - 外边距(margin):盒子与其他元素之间的空间,用于控制元素之间的距离,用
margin属性来设置大小。
标准盒模型
CSS标准盒模型中,元素的宽度和高度仅包括内容区域的宽度和高度,不包括内边距和边框。即width和height属性设置的值仅仅是内容区域的大小。
示例:
|
|
在这个例子中,.box类定义了一个盒子模型,内容区域宽度为200px,高度为100px,内边距为20px,边框宽度为5px,外边距为30px。这里的元素总宽 = 内容宽度 + 左右内边距 + 左右边框 = 200 + 202 + 52 = 250px;总高 = 内容高度 + 上下内边距 + 上下边框 = 100 + 202 + 52 = 150px。
其中的199.992×99.984和4.500属于浏览器渲染时的精度偏差。浏览器在渲染元素时,会涉及像素的亚像素(sub-pixel)计算(即像素的细分精度,比如把一个物理像素拆分为多个逻辑像素计算)。这种偏差是浏览器底层渲染引擎的 “精度妥协”,属于正常现象——它不会影响视觉呈现,最终元素的实际显示仍会对齐到物理像素,保证视觉上的清晰。
替代盒模型
除了标准盒模型外,CSS还提供了替代盒模型,可以通过box-sizing属性来设置。box-sizing属性有两个主要值:
-
content-box(默认值,也即标准盒模型):宽度和高度只包括内容区域,不包括内边距和边框,即width和height属性设置的值仅仅是内容区域的大小。 -
border-box:宽度和高度包括内容区域、内边距和边框,即width和height属性设置的值是整个盒子的大小。
示例:
|
|
在这个例子中,.box类使用了border-box盒模型,因此盒子的总宽度和高度仍然是200px和100px,而不是内容区域的宽度和高度。因此元素的总宽 = 200px,总高 = 100px,内容区域的宽度和高度会根据内边距和边框的大小自动调整。即内容的宽度 = 总宽 - 左右内边距 - 左右边框 = 200 - 202 - 52 = 150px;内容的高度 = 总高 - 上下内边距 - 上下边框 = 100 - 202 - 52 = 50px。
大多数开发者更倾向于使用border-box盒模型,因为它更直观,尤其是在进行复杂布局时,可以更容易地控制元素的总大小。
盒模型的边距和溢出问题
外边距合并(Margin Collapsing)
在CSS盒模型中,外边距(margin)有一个特殊的行为,称为“边距合并”(margin collapsing)。当两个垂直相邻的块级元素的外边距相遇时,浏览器会将它们合并为一个外边距,而不是简单地相加。这意味着最终的外边距大小将是两个外边距中较大的那个。但是如果两个外边距是负值,则取较小的那个值。如果一个是正值一个是负值,则相当于做加法运算。
|
|
在这个例子中,.box1的下外边距是30px,.box2的上外边距是50px。由于边距合并,两个盒子之间的实际间距将是50px,而不是80px(30px + 50px)。这是因为浏览器选择了较大的外边距值作为最终的间距。
观感上就像外边距小的那个被大边距“吃掉”了一样。理解边距合并对于布局设计非常重要,尤其是在处理多个块级元素时,可以帮助避免意外的间距问题。解决方法可以使用内边距(padding)或边框(border)来替代外边距,或者添加边框或内边距来阻止边距合并。也可以使用flex布局或grid布局来避免这种情况,这在后面的布局章节中会详细介绍。
盒子溢出(Overflow)
盒子溢出是指当内容的大小超过其容器的尺寸时,内容会溢出容器的边界。CSS提供了overflow属性来控制溢出内容的显示方式。overflow属性有以下几个常用值:
visible:默认值,溢出内容会显示在容器之外。hidden:溢出内容会被裁剪,不会显示在容器之外。scroll:无论是否溢出,容器都会显示滚动条。auto:当内容溢出时,自动显示滚动条。
盒子溢出示例
|
|
在这个例子中,.container类定义了一个固定大小的容器,而.content类定义了一个比容器大的内容区域。根据overflow属性的不同设置,溢出内容的显示方式会有所不同。
CSS的布局方式
CSS提供了多种布局方式,常见的布局方式包括:
文档流(Document Flow)
在讲解CSS的布局方式之前,我们要先介绍一下文档流的概念。文档流是指HTML元素在页面中的默认排列方式。大多数HTML元素都是按照文档流的顺序从上到下、从左到右排列的。块级元素(如<div>、<p>)默认占据整行,而行内元素(如<span>、<a>)则在一行内排列,直到行满为止。文档流就像水一样,能够自适应所在的容器。当一个节点被移除时,其他节点会自动填补它的位置。如果一个节点脱离了文档流,其他节点就不会再考虑它的位置,会自动填补它的位置。有几种常见的脱离文档流的方式,包括定位布局(positioning)、浮动布局(floating)和弹性盒布局(flexbox)等。
流式布局(Flow Layout)
流式布局是最基本的布局方式,元素按照文档流的顺序排列。块级元素(如<div>、<p>)默认占据整行,而行内元素(如<span>、<a>)则在一行内排列,直到行满为止。
定位布局(Positioning Layout)
定位布局允许开发者通过position属性来控制元素的位置。常见的定位方式有:
static:默认值,元素按照文档流排列。relative:相对于其正常位置进行偏移。absolute:相对于最近的已定位祖先元素进行定位,如果没有已定位祖先,则相对于初始包含块(通常是<html>元素)定位。fixed:相对于浏览器窗口进行定位,滚动页面时位置不变。sticky:在特定的滚动位置下表现为relative,否则表现为fixed。
relative(相对定位)解析:
|
|
在上面的例子中,.box元素将相对于其正常位置向下移动20px,向右移动30px。这个相对是相对于它在文档流中的原始位置。
absolute(绝对定位) 解析:
|
|
在这个例子中,.box元素将相对于其最近的已定位祖先元素.container定位,距离顶部50px,距离左侧100px。注意,如果没有已定位的祖先元素,.box将相对于初始包含块(通常是<html>元素)进行定位。所以,使用absolute定位时,通常会为其祖先元素设置position: relative以确保定位的参考点正确。
fixed(固定定位) 解析:
|
|
在这个例子中,.box元素将固定在浏览器窗口的右上角,距离顶部10px,距离右侧10px。无论页面如何滚动,.box的位置都不会改变。
sticky(粘性定位) 解析:
|
|
在这个例子中,.box元素在滚动到达其父容器的顶部时会固定在视口的顶部(距离顶部0px)。在滚动之前,它会按照正常的文档流进行排列。
注意,sticky定位需要父容器有足够的高度,否则可能无法达到预期效果。且sticky的父级元素不能有overflow: hidden、overflow: scroll或overflow: auto属性,否则会影响其粘性行为。以及flex的布局主轴方向和sticky定位的方向要一致,否则可能无法达到预期效果。要触发粘性效果,需要设置top、bottom、left或right中的至少一个属性。
浮动布局(Floating Layout)
浮动布局使用float属性将元素从正常文档流中取出,并使其向左或向右浮动。常用于实现文本环绕效果或创建多栏布局。需要注意的是,浮动元素不会影响后续元素的布局,可能需要使用清除浮动(clear)来避免布局问题。
弹性盒布局(Flexbox Layout)
弹性盒布局使用display: flex属性创建一个灵活的容器,允许子元素在主轴和交叉轴上进行对齐和分配空间。Flexbox非常适合用于一维布局,如水平或垂直排列元素。常用的Flexbox属性包括flex-direction、justify-content、align-items等。
flex布局的主轴
在Flexbox中,主轴是指元素在容器中排列的方向。主轴的方向可以通过flex-direction属性来设置,常见的取值有:
row:默认值,主轴为水平方向,从左到右排列。row-reverse:主轴为水平方向,从右到左排列。column:主轴为垂直方向,从上到下排列。column-reverse:主轴为垂直方向,从下到上排列。
flex布局的交叉轴
交叉轴是指与主轴垂直的方向。交叉轴的方向取决于主轴的方向:
- 当主轴为水平方向(
row或row-reverse)时,交叉轴为垂直方向。 - 当主轴为垂直方向(
column或column-reverse)时,交叉轴为水平方向。
⬇️ 下载
flex的内容对齐
在Flexbox中,可以使用justify-content属性来控制主轴上的内容对齐方式,常见的取值有:
flex-start:默认值,内容向主轴的起始位置对齐。flex-end:内容向主轴的结束位置对齐。center:内容在主轴上居中对齐。space-between:内容在主轴上均匀分布,首尾元素紧贴容器边缘。space-around:内容在主轴上均匀分布,首尾元素与容器边缘之间留有空隙。
flex的尺寸
在Flexbox中,可以使用flex属性来控制子元素在主轴上的尺寸分配。flex属性是一个简写属性,包含三个子属性:flex-grow、flex-shrink和flex-basis。
flex-grow:定义子元素在主轴上如何增长以填充剩余空间。默认值为0,表示不增长。flex-shrink:定义子元素在主轴上如何缩小以适应容器。默认值为1,表示可以缩小。flex-basis:定义子元素在主轴上的初始尺寸。可以设置为具体的长度值(如100px)或百分比(如50%),也可以设置为auto,表示根据内容自动计算尺寸。
示例:
|
|
在这个例子中,.item类的子元素将具有初始尺寸为100px,并且可以增长以填充剩余空间,但不会缩小。设置flex: 1也表示每个子元素将平分剩余空间。即每个元素在主轴上占据相等的空间,这是个无单位的比例值,表示每个元素按比例分配空间。
flex的换行
默认情况下,Flexbox容器内的子元素会在一行内排列,超出容器宽度时不会换行。可以使用flex-wrap属性来控制子元素的换行行为,常见的取值有:
nowrap:默认值,子元素不换行,超出容器宽度时会溢出。wrap:子元素换行,超出容器宽度时会自动换到下一行。wrap-reverse:子元素换行,超出容器宽度时会自动换到上一行。
网格布局(Grid Layout)
网格布局使用display: grid属性创建一个二维的网格容器,允许开发者定义行和列,并将子元素放置在指定的网格单元格中。Grid布局非常适合用于复杂的网页布局,如报纸式布局。常用的Grid属性包括grid-template-rows、grid-template-columns、grid-gap等。
grid布局的行和列
在Grid布局中,可以使用grid-template-rows和grid-template-columns属性来定义网格的行和列。可以使用具体的长度值(如100px)、百分比(如50%)或灵活单位(如fr)来设置行和列的大小。
示例:
|
|
在这个例子中,.container类定义了一个Grid容器,包含两行和两列。第一行高度为100px,第二行高度为200px;第一列宽度为1fr,第二列宽度为2fr,表示第二列的宽度是第一列的两倍。grid-gap属性用于设置网格单元格之间的间距。
grid布局的子元素定位
在Grid布局中,可以使用grid-row和grid-column属性来控制子元素在网格中的位置。可以指定子元素跨越的行和列。
示例:
|
|
在这个例子中,.item1类的子元素将跨越第一行和第一列、第二列,而.item2类的子元素将跨越第二行和第一列。在观感上,.item1会占据网格的第一行的全部宽度,而.item2会占据第二行的第一列。
grid布局的自动放置
Grid布局还支持自动放置子元素,可以使用grid-auto-rows和grid-auto-columns属性来定义自动生成的行和列的大小。
示例:
|
|
在这个例子中,.container类定义了一个Grid容器,自动生成的行高度为100px,自动生成的列宽度为1fr,表示每列宽度相等。grid-gap属性用于设置网格单元格之间的间距。
grid布局的对齐
在Grid布局中,可以使用justify-items和align-items属性来控制子元素在网格单元格内的对齐方式。常见的取值有:
start:子元素向单元格的起始位置对齐。end:子元素向单元格的结束位置对齐。center:子元素在单元格内居中对齐。stretch:默认值,子元素拉伸以填充整个单元格。
CSS的伪类和伪元素
伪类(Pseudo-classes)
伪类用于定义元素的特殊状态或条件,可以分为四种,分别是条件伪类、行为伪类、状态伪类和结构伪类。
条件伪类
条件伪类用于根据元素的特定条件来应用样式,常见的条件伪类有:
:lang():根据元素的语言属性应用样式。:not():选择不符合特定条件的元素。:has():选择包含特定子元素的元素。:is():选择符合多个选择器条件的元素。:dir():根据元素的文本方向应用样式。
行为伪类
行为伪类用于根据用户与元素的交互行为来应用样式,常见的行为伪类有:
:hover:当用户将鼠标悬停在元素上时应用样式。:active:当用户点击并按下元素时应用样式。:focus:当元素获得焦点时应用样式。
状态伪类
状态伪类用于根据元素的状态来应用样式,常见的状态伪类有:
:checked:选择被选中的复选框或单选按钮。:disabled:选择被禁用的表单元素。:enabled:选择可用的表单元素。:required:选择必填的表单元素。:valid:选择有效的表单元素。:invalid:选择无效的表单元素。
结构伪类
结构伪类用于根据元素在文档结构中的位置来应用样式,常见的结构伪类有:
:first-child:选择作为其父元素的第一个子元素的元素。:last-child:选择作为其父元素的最后一个子元素的元素。:nth-child(n):选择作为其父元素的第n个子元素的元素。:nth-last-child(n):选择作为其父元素的倒数第n个子元素的元素。:only-child:选择作为其父元素唯一子元素的元素。:root:选择文档的根元素。:empty:选择没有子元素的元素。
伪元素(Pseudo-elements)
伪元素用于创建元素的虚拟子元素,常见的伪元素有:
::before:在元素内容之前插入内容。::after:在元素内容之后插入内容。::first-letter:选择元素的第一个字母。::first-line:选择元素的第一行文本。
示例:
|
|
在这个例子中,::before伪元素在每个段落内容之前插入了“Note: ”,并将其设置为粗体;::after伪元素在段落内容之后插入了“ (end of paragraph)”,并将其设置为斜体。
结语
本文详细介绍了CSS的层叠与继承、盒模型、布局方式以及伪类和伪元素等内容。CSS是前端开发中不可或缺的技术,它的上手相对简单,但是想要精通却很困难。在之后的开发中除了原生CSS外,我们还会接触到各种CSS预处理器(如Sass、Less)和CSS框架(如Bootstrap、Tailwind CSS),这些工具可以帮助我们更高效地编写和管理CSS代码。本文仅对CSS做了一些详细的介绍,后面还需要自己不断学习和实践。