CSS 基础
CSS(Cascading Style Sheets,层叠样式表)是用于控制网页外观的语言。如果说 HTML 是网页的骨架,CSS 就是网页的皮肤——它决定了网页的颜色、字体、布局、动画等视觉效果。这一章将从 CSS 的基本概念讲起,深入理解选择器和盒模型这两个核心主题。
CSS 是什么
CSS 是一种样式表语言,用于描述 HTML 文档的呈现方式。它的主要作用是:
分离内容与样式:HTML 负责结构和内容,CSS 负责外观样式。这种分离让代码更清晰,也便于复用——一个 CSS 文件可以控制多个页面的样式。
灵活的样式控制:CSS 提供了丰富的属性来控制元素的外观,从简单的颜色字体,到复杂的布局动画,都可以通过 CSS 实现。
响应式设计:通过媒体查询,CSS 可以根据屏幕尺寸、设备类型等条件应用不同的样式,让网页适配各种设备。
引入 CSS 的方式
CSS 有三种引入方式,各有适用场景:
外部样式表
外部样式表是最推荐的方式,将 CSS 写在独立的 .css 文件中,通过 <link> 标签引入:
<head>
<link rel="stylesheet" href="styles.css">
</head>
/* styles.css */
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
h1 {
color: #333;
}
外部样式表的优点是:可以被多个页面共享,浏览器会缓存 CSS 文件,提高加载速度,也便于维护。
内部样式表
内部样式表将 CSS 写在 <style> 标签内,放在 HTML 文档的 <head> 中:
<head>
<style>
body {
background-color: #f5f5f5;
}
h1 {
color: navy;
}
</style>
</head>
这种方式适用于单个页面需要特殊样式的场景,或者用于开发测试阶段。
内联样式
内联样式直接写在 HTML 元素的 style 属性中:
<p style="color: red; font-size: 18px;">这是一段红色文字</p>
内联样式的优先级最高,但不利于维护,通常只在 JavaScript 动态设置样式时使用。
CSS 语法
CSS 规则由选择器和声明块组成:
h1 {
color: blue;
font-size: 24px;
}
- 选择器(
h1):指定要样式化的 HTML 元素 - 声明块(花括号内的内容):包含一个或多个声明
- 声明(
color: blue;):由属性和值组成,以分号结束
CSS 忽略空白格式,以下写法都有效:
/* 单行 */
h1 { color: blue; font-size: 24px; }
/* 多行,推荐格式 */
h1 {
color: blue;
font-size: 24px;
}
CSS 支持 /* 注释 */ 格式的注释,注释可以跨越多行,但不能嵌套。
选择器详解
选择器是 CSS 的核心概念,它决定了样式应用到哪些元素。CSS 提供了多种选择器类型,灵活组合可以精确选中任何元素。
基础选择器
元素选择器直接选中 HTML 元素:
p { color: #333; }
h1 { font-size: 32px; }
a { text-decoration: none; }
类选择器以 . 开头,选中具有指定 class 的元素:
.highlight { background-color: yellow; }
.card { border: 1px solid #ddd; }
<p class="highlight">高亮文字</p>
<div class="card">卡片内容</div>
类选择器是最常用的选择器类型,因为一个元素可以有多个类名,一个类名也可以用于多个元素。
ID 选择器以 # 开头,选中具有指定 id 的元素:
#header { height: 60px; }
#main-content { max-width: 1200px; }
<header id="header">...</header>
<main id="main-content">...</main>
ID 在页面中必须唯一,ID 选择器的优先级比类选择器高,但应避免过度使用 ID 选择器,因为它会降低 CSS 的复用性。
通配符选择器 * 选中所有元素:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
通配符选择器常用于 CSS 重置,但会影响性能,不建议在大型项目中过度使用。
组合选择器
后代选择器(空格)选中某元素内部的所有指定后代元素:
/* article 内部的所有 p 元素 */
article p {
line-height: 1.6;
}
/* nav 内部的所有 a 元素 */
nav a {
color: white;
}
后代选择器会匹配所有层级的后代,无论嵌套多深。
子选择器(>)只选中直接子元素,不匹配更深层级:
/* nav 的直接子元素 ul */
nav > ul {
list-style: none;
}
/* 只匹配直接子元素 p */
article > p {
margin-bottom: 1em;
}
相邻兄弟选择器(+)选中紧邻在某元素后面的兄弟元素:
/* h1 后面紧邻的 p 元素 */
h1 + p {
font-size: 18px;
color: #666;
}
通用兄弟选择器(~)选中某元素后面的所有指定兄弟元素:
/* h2 后面所有的 p 元素 */
h2 ~ p {
color: #555;
}
属性选择器
属性选择器根据元素的属性或属性值来选择:
/* 有 title 属性的元素 */
[title] {
cursor: help;
}
/* type="text" 的 input */
input[type="text"] {
border: 1px solid #ccc;
}
/* href 以 https 开头的 a 元素 */
a[href^="https"] {
color: green;
}
/* href 以 .pdf 结尾的 a 元素 */
a[href$=".pdf"] {
background-image: url('pdf-icon.png');
}
/* href 包含 example 的 a 元素 */
a[href*="example"] {
font-weight: bold;
}
/* class 包含完整单词 "btn" 的元素 */
[class~="btn"] {
padding: 10px 20px;
}
伪类选择器
伪类选择器用于选择元素的特定状态。最常用的是用户交互状态:
/* 鼠标悬停 */
a:hover {
color: red;
}
/* 获得焦点 */
input:focus {
border-color: blue;
outline: none;
}
/* 激活状态(点击时) */
button:active {
transform: scale(0.98);
}
/* 已访问的链接 */
a:visited {
color: purple;
}
结构伪类选择器根据元素在文档结构中的位置来选择:
/* 第一个子元素 */
li:first-child {
font-weight: bold;
}
/* 最后一个子元素 */
li:last-child {
border-bottom: none;
}
/* 第 n 个子元素 */
tr:nth-child(odd) { background: #f9f9f9; } /* 奇数行 */
tr:nth-child(even) { background: #fff; } /* 偶数行 */
tr:nth-child(3) { background: #ff0; } /* 第 3 行 */
tr:nth-child(3n) { background: #f0f; } /* 3, 6, 9... */
tr:nth-child(3n+1) { background: #0ff; } /* 1, 4, 7... */
/* 倒数第 n 个子元素 */
li:nth-last-child(2) { color: red; }
/* 唯一的子元素 */
p:only-child { font-size: 20px; }
/* 第一个该类型的子元素 */
p:first-of-type { font-size: 18px; }
/* 最后一个该类型的子元素 */
p:last-of-type { margin-bottom: 0; }
/* 第 n 个该类型的子元素 */
article p:nth-of-type(2) { color: #666; }
nth-child 和 nth-of-type 的区别:nth-child 计数时包含所有子元素,nth-of-type 只计算同类型元素。
<div>
<h1>标题</h1> <!-- h1:nth-child(1) 生效 -->
<p>第一段</p> <!-- p:nth-child(2),p:nth-of-type(1) -->
<p>第二段</p> <!-- p:nth-child(3),p:nth-of-type(2) -->
</div>
表单相关伪类:
/* 选中的复选框或单选框 */
input:checked {
accent-color: blue;
}
/* 禁用的表单元素 */
input:disabled {
background: #eee;
cursor: not-allowed;
}
/* 必填的表单元素 */
input:required {
border-left: 3px solid red;
}
/* 可选的表单元素 */
input:optional {
border-left: 3px solid #ccc;
}
/* 验证有效的输入 */
input:valid {
border-color: green;
}
/* 验证无效的输入 */
input:invalid {
border-color: red;
}
伪元素选择器
伪元素用于选择元素的特定部分,或插入内容。伪元素以双冒号 :: 开头:
/* 在元素内容前插入内容 */
p::before {
content: "» ";
color: #999;
}
/* 在元素内容后插入内容 */
p::after {
content: " ✓";
color: green;
}
/* 首字母 */
p::first-letter {
font-size: 2em;
font-weight: bold;
float: left;
margin-right: 5px;
}
/* 首行 */
p::first-line {
font-weight: bold;
}
/* 选中的文本 */
::selection {
background: #ffeb3b;
color: #000;
}
伪元素最常用的是 ::before 和 ::after,配合 content 属性可以创建装饰性元素、清除浮动等。
选择器优先级
当多个选择器选中同一个元素并设置了冲突的属性时,浏览器根据优先级决定应用哪个样式。优先级从高到低:
!important声明(最高)- 内联样式
- ID 选择器
- 类选择器、属性选择器、伪类
- 元素选择器、伪元素
- 通配符选择器(最低)
优先级可以用 (ID, 类, 元素) 三位数表示:
#nav .item a { } /* (1, 1, 1) - 1个ID, 1个类, 1个元素 */
.nav .menu .link { } /* (0, 3, 0) - 3个类 */
#header { } /* (1, 0, 0) - 1个ID */
.btn.primary { } /* (0, 2, 0) - 2个类 */
div p span { } /* (0, 0, 3) - 3个元素 */
比较时从左到右依次比较,数值大的优先级高。(1, 0, 0) 大于 (0, 9, 9)。
当优先级相同时,后出现的样式覆盖先出现的样式。
!important 会覆盖任何正常优先级,但应该尽量避免使用,它会让样式难以维护。
盒模型
盒模型是 CSS 布局的基础概念。每个 HTML 元素都被视为一个矩形盒子,由内容区、内边距、边框、外边距四部分组成。
盒模型组成
+------------------------------------------+
| margin |
| +----------------------------------+ |
| | border | |
| | +--------------------------+ | |
| | | padding | | |
| | | +------------------+ | | |
| | | | content | | | |
| | | | | | | |
| | | +------------------+ | | |
| | | | | |
| | +--------------------------+ | |
| | | |
| +----------------------------------+ |
| |
+------------------------------------------+
内容区(content):元素的实际内容区域,显示文字、图片等。width 和 height 属性控制内容区的尺寸。
内边距(padding):内容区与边框之间的空白区域。背景色和背景图会延伸到内边距区域。
边框(border):包围内边距和内容区的边界线。
外边距(margin):元素边框外侧的空白区域,控制元素与其他元素之间的距离。
.box {
/* 内容区尺寸 */
width: 200px;
height: 100px;
/* 内边距 */
padding: 20px; /* 四周相同 */
padding: 10px 20px; /* 上下 左右 */
padding: 10px 20px 15px; /* 上 左右 下 */
padding: 10px 20px 15px 5px; /* 上 右 下 左 */
/* 边框 */
border: 1px solid #333;
border-width: 1px;
border-style: solid; /* solid, dashed, dotted, double, none */
border-color: #333;
/* 外边距 */
margin: 20px;
margin: 10px auto; /* 水平居中 */
}
两种盒模型
CSS 有两种盒模型:标准盒模型和 IE 盒模型(也叫替代盒模型)。
标准盒模型(默认):width 和 height 只控制内容区尺寸。元素的实际占用宽度 = width + padding-left + padding-right + border-left + border-right。
.box {
box-sizing: content-box; /* 默认值 */
width: 200px;
padding: 20px;
border: 5px solid black;
/* 总宽度 = 200 + 20*2 + 5*2 = 250px */
}
IE 盒模型:width 和 height 控制元素的总尺寸,包括内容区、内边距和边框。
.box {
box-sizing: border-box;
width: 200px;
padding: 20px;
border: 5px solid black;
/* 总宽度 = 200px,内容区宽度 = 200 - 20*2 - 5*2 = 150px */
}
IE 盒模型更直观,更容易控制元素尺寸。推荐在全局样式中设置:
* {
box-sizing: border-box;
}
外边距合并
当两个垂直方向相邻的外边距相遇时,它们会合并成一个外边距,取两者中的较大值。这就是外边距合并(margin collapsing)。
<div class="box1">Box 1</div>
<div class="box2">Box 2</div>
.box1 { margin-bottom: 30px; }
.box2 { margin-top: 20px; }
/* 两元素之间的实际间距是 30px,不是 50px */
外边距合并只发生在垂直方向,水平方向不会合并。
父子元素之间也会发生外边距合并:
<div class="parent">
<div class="child">子元素</div>
</div>
.parent { background: #eee; }
.child { margin-top: 20px; }
/* 子元素的 margin-top 会"穿透"到父元素外部 */
解决方法:给父元素添加 padding-top、border-top、或创建新的 BFC(如 overflow: hidden)。
块级元素与行内元素
HTML 元素默认分为块级元素和行内元素,它们的盒模型表现不同。
块级元素(如 div、p、h1-h6、ul、li):
- 独占一行,前后自动换行
- 可以设置 width、height、margin、padding
- 默认宽度填满父元素
行内元素(如 span、a、strong、em、img):
- 不换行,与其他行内元素并排
- 不能设置 width 和 height(img 等替换元素除外)
- 垂直方向的 margin 和 padding 不占用空间
行内块元素(display: inline-block):
- 不换行,与其他元素并排
- 可以设置 width、height、margin、padding
span {
display: inline-block;
width: 100px;
height: 30px;
margin: 10px;
}
通过 display 属性可以改变元素的显示类型:block、inline、inline-block、none(隐藏元素)。
小结
这一章我们学习了:
- CSS 的三种引入方式和基本语法
- 各种选择器类型及其用法
- 选择器优先级的计算规则
- 盒模型的组成和两种模式
- 外边距合并现象
- 块级元素与行内元素的区别
选择器和盒模型是 CSS 最核心的概念。理解选择器优先级对于解决样式冲突问题至关重要,理解盒模型则是掌握 CSS 布局的基础。
下一章我们将学习 CSS 文本与字体样式,了解如何控制网页中的文字显示。