跳到主要内容

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-childnth-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 属性可以创建装饰性元素、清除浮动等。

选择器优先级

当多个选择器选中同一个元素并设置了冲突的属性时,浏览器根据优先级决定应用哪个样式。优先级从高到低:

  1. !important 声明(最高)
  2. 内联样式
  3. ID 选择器
  4. 类选择器、属性选择器、伪类
  5. 元素选择器、伪元素
  6. 通配符选择器(最低)

优先级可以用 (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):元素的实际内容区域,显示文字、图片等。widthheight 属性控制内容区的尺寸。

内边距(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 盒模型(也叫替代盒模型)。

标准盒模型(默认):widthheight 只控制内容区尺寸。元素的实际占用宽度 = 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 盒模型widthheight 控制元素的总尺寸,包括内容区、内边距和边框。

.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-topborder-top、或创建新的 BFC(如 overflow: hidden)。

块级元素与行内元素

HTML 元素默认分为块级元素和行内元素,它们的盒模型表现不同。

块级元素(如 divph1-h6ulli):

  • 独占一行,前后自动换行
  • 可以设置 width、height、margin、padding
  • 默认宽度填满父元素

行内元素(如 spanastrongemimg):

  • 不换行,与其他行内元素并排
  • 不能设置 width 和 height(img 等替换元素除外)
  • 垂直方向的 margin 和 padding 不占用空间

行内块元素display: inline-block):

  • 不换行,与其他元素并排
  • 可以设置 width、height、margin、padding
span {
display: inline-block;
width: 100px;
height: 30px;
margin: 10px;
}

通过 display 属性可以改变元素的显示类型:blockinlineinline-blocknone(隐藏元素)。

小结

这一章我们学习了:

  • CSS 的三种引入方式和基本语法
  • 各种选择器类型及其用法
  • 选择器优先级的计算规则
  • 盒模型的组成和两种模式
  • 外边距合并现象
  • 块级元素与行内元素的区别

选择器和盒模型是 CSS 最核心的概念。理解选择器优先级对于解决样式冲突问题至关重要,理解盒模型则是掌握 CSS 布局的基础。

下一章我们将学习 CSS 文本与字体样式,了解如何控制网页中的文字显示。