器→工具, 编程语言

系统化CSS学习指南

钱魏Way · · 3 次浏览
目录

CSS的基本概念

CSS 是什么?

CSS 的全称是 Cascading Style Sheets,中文翻译为 层叠样式表

  • 样式表 (Style Sheets):意味着它是一套规则集,用于指定网页上元素(如文本、图片、布局)应该如何被呈现(即“化妆”)。
  • 层叠 (Cascading):这是CSS一个非常核心且强大的特性。它意味着多个样式规则可以应用于同一个HTML元素,浏览器会根据一套复杂的规则(层叠规则)来决定最终应用哪个样式。这套规则考虑了样式的来源优先级(特异性)顺序

简单来说,CSS就是Web的设计师和化妆师。如果HTML是搭建了房子的骨架和结构(哪里是客厅,哪里是卧室),那么CSS就是负责房子的装修(墙壁颜色、地板材质、家具摆放),让它变得美观宜居。

CSS 的核心作用

CSS的主要作用可以概括为以下几点:

实现内容与表现分离

这是CSS最重要、最哲学的作用。

  • HTML 只负责定义网页的内容结构和语义(例如:这是一个标题<h1>,这是一个段落<p>,这是一个列表<ul>)。
  • CSS 则独立负责定义这些内容的视觉表现(例如:标题是红色居中,段落字体是16px,列表项之间有间隔)。

带来的巨大优势:

  • 易于维护:要修改网站风格(比如把所有标题颜色从蓝色改成绿色),只需修改一个CSS文件,所有HTML页面都会自动更新,无需逐个修改成千上万个HTML标签。
  • 代码简洁清晰:HTML文件变得干净,只关注内容,而CSS文件专注于样式,便于团队协作和代码阅读。
  • 提高页面加载速度:CSS文件可以被浏览器缓存,首次加载后,用户访问同一网站的其他页面时无需重新下载样式,只需加载HTML内容即可。

精确控制页面布局与外观

CSS提供了极其丰富的属性,让你能控制几乎所有视觉细节:

  • 布局:控制元素的位置、排列方式(流式、浮动、flex弹性、grid网格布局)。
  • 颜色和背景:设置文字颜色、背景颜色或背景图片。
  • 文字排版:控制字体、大小、粗细、行高、对齐方式等,实现精美的文字排版。
  • 盒模型:控制每个元素周围的内边距 (padding)边框 (border)外边距 (margin),这是布局的基础。
  • 动态效果:通过过渡 (transition)动画 (animation) 让页面元素动起来,提升用户体验。

实现响应式网页设计

CSS可以让你编写自适应的样式规则,使同一个网页能够自动在不同设备(从手机小屏幕到桌面大显示器)上都能呈现出最合适的布局和外观。这主要通过媒体查询 技术来实现。

核心基本概念详解

要理解CSS,必须掌握以下几个基本概念:

CSS 规则集

CSS代码的基本组成单位,它告诉浏览器如何样式化特定的元素。

p {
  color: red;
  font-size: 16px;
}
  • 选择器 (Selector):p,用于“选中”你想要样式化的一个或多个HTML元素。
  • 声明块 (Declaration Block):{ color: red; font-size: 16px; },由一对大括号 {}包裹。
  • 声明 (Declaration):color: red;,一个具体的样式指令。
  • 属性 (Property):color,是你想要改变的样式名称(如 color, width, border)。
  • 值 (Value):red,是你想给这个属性设置的特定值(如 red, 20px, #FFFFFF)。
  • 分号 (;):每个声明都必须以分号结束。

盒模型 (Box Model)

每一个HTML元素都可以被看作一个矩形的盒子,CSS布局都围绕着这个“盒子”展开。这个盒子由内到外包括四个部分:

  • 内容 (Content):盒子的核心,显示文本和图像的实际区域。其大小通过 width和 height设置。
  • 内边距 (Padding):内容区与边框之间的透明区域。使用 padding相关属性控制。
  • 边框 (Border):包裹在内边距和外边距之间的线。使用 border相关属性控制。
  • 外边距 (Margin):盒子与其他盒子之间的透明区域,用于控制元素间的间隔。使用 margin相关属性控制。

层叠与继承 (Cascading & Inheritance)

  • 层叠:解决冲突的规则。当多个CSS规则指向同一个元素时,浏览器会根据:
    • 重要性 (!important):最高优先级。
    • 来源:浏览器默认样式 < 用户样式表 < 作者(开发者)样式表。
    • 特异性 (Specificity):计算选择器的权重(例如:#id选择器比 .class选择器权重高)。
    • 顺序:在来源和特异性相同的情况下,后出现的样式会覆盖先出现的样式。
  • 继承:一些CSS属性(主要是文本相关属性,如 color, font-family, line-height)会从父元素自动传递给子元素。这避免了在每个元素上重复设置相同的样式。但并非所有属性都继承(如 border, margin, padding就不继承)。

CSS三种引入方式

三种引入方式概览

方式 说明 使用方法 优点 缺点 使用场景
行内样式 直接在HTML标签的style属性中编写 <div style=”color: red;”> 优先级最高,快速测试 难以维护,样式与结构混杂 极少使用,用于测试或覆盖样式
内部样式表 在HTML文件的<head>中使用<style>标签包裹 <style> p { color: blue; } </style> 方便在单页面中统一管理 不能跨页面复用 用于单个页面特有的少量样式
外部样式表 将CSS写在单独的文件中,通过<link>引入 <link rel=”stylesheet” href=”style.css”> 最佳实践,易于维护和复用 需要HTTP请求 绝大多数场景,项目开发的标准方式

CSS选择器详解

选择器基本概念

是什么?

CSS选择器是CSS规则的第一部分,用于指定你想要样式化的一个或一组HTML元素。

语法结构:

选择器 {
  属性: 值;
}
/* 例如 */
h1 {
  color: navy;
}

在这个例子中,h1就是选择器,它选中了页面上的所有 <h1>元素。

选择器分类详解

为了更直观地理解,我们可以将选择器分为以下几大类:

基础选择器

这是最常用、最简单的选择器类型。

选择器 示例 描述 使用频率
元素选择器 p 选中所有指定类型的HTML标签元素。 ⭐⭐⭐⭐⭐
类选择器 .my-class 选中所有 class属性包含 my-class的元素。可复用 ⭐⭐⭐⭐⭐
ID选择器 #my-id 选中 id属性为 my-id的唯一元素。 ⭐⭐⭐
通配选择器 * 选中页面上的每一个元素。(常用于重置样式)

示例代码:

<p>这是一个段落</p>
<p class="highlight">这是一个需要高亮的段落</p>
<div id="header">这是页头</div>

/* 元素选择器 */
p {
  font-size: 16px;
}

/* 类选择器 (最常用、最灵活) */
.highlight {
  background-color: yellow;
}

/* ID选择器 */
#header {
  height: 60px;
  background-color: #333;
}

/* 通配选择器 */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box; /* 非常实用的重置 */
}

组合器(关系选择器)

用于根据元素之间的特定关系来精确选择元素。

选择器 示例 描述
后代选择器 div p 选中 <div>元素内部所有(无论嵌套多深)的 <p>元素。
子选择器 div > p 选中 <div>元素直接子元素中的所有 <p>元素。(只限一级)
相邻兄弟选择器 h1 + p 选中紧接在 <h1>元素之后第一个 <p>兄弟元素。
通用兄弟选择器 h1 ~ p 选中 <h1>元素之后所有 <p>兄弟元素。

示例代码:

<article>
  <h1>主标题</h1>
  <p>第一段(紧邻h1,会被 h1 + p 和 h1 ~ p 选中)</p>
  <div>
    <p>嵌套的段落(是div的后代,是article的后代)</p>
  </div>
  <p>另一段(是h1的兄弟,会被 h1 ~ p 选中)</p>
</article>

/* 选中article里的所有p */
article p {
  color: darkgray;
}

/* 只选中article的直接子元素p (上面的嵌套段落不会被选中) */
article > p {
  font-weight: bold;
}

/* 选中紧接在h1后面的第一个p */
h1 + p {
  text-indent: 2em;
}

/* 选中h1后面所有的p */
h1 ~ p {
  border-left: 3px solid orange;
  padding-left: 10px;
}

属性选择器

根据元素的属性及属性值来选择元素。

选择器 示例 描述
[attr] [target] 选中所有带有 target属性的元素。
[attr=value] [target=”_blank”] 选中所有 target属性值等于 _blank的元素。
[attr~=value] [class~=”logo”] 选中 class属性值中包含完整单词 logo的元素。
[attr\|=value] [lang\|=”en”] 选中 lang属性值en开头或以 en-开头的所有元素。
[attr^=value] a[href^=”https”] 选中 href属性值https开头的所有 <a>元素。
[attr$=value] a[href$=”.pdf”] 选中 href属性值.pdf结尾的所有 <a>元素。
[attr*=value] a[href*=”example”] 选中 href属性值包含 example 的所有 <a>元素。

示例代码:

/* 为所有外部链接添加一个小图标 */
a[href^="http"]::after {
  content: "↗";
}

/* 为所有下载PDF的链接添加特殊样式 */
a[href$=".pdf"] {
  background-color: lightcoral;
}

/* 选中所有包含‘btn’类名的元素,如‘btn-primary’, ‘btn-small’ */
[class*="btn"] {
  border-radius: 4px;
  padding: 8px 16px;
}

伪类

用于定义元素的特定状态

伪类 示例 描述
动态伪类 a:hover 当鼠标悬停在链接上时的状态。
input:focus 当输入框获得焦点时的状态。
UI状态伪类 input:checked 选中所有被选中的单选/复选框。
input:disabled 选中所有被禁用的表单元素。
结构伪类 li:first-child 选中作为其父元素下第一个子元素的 <li>。
li:last-child 选中作为其父元素下最后一个子元素的 <li>。
li:nth-child(n) 选中父元素下第n个子元素 <li>。(极其强大)
li:nth-of-type(n) 选中父元素下同类型中的第n个 <li>元素。
其他 :not(selector) 否定伪类,选中不匹配给定选择器的元素。

:nth-child()公式示例:

  • :nth-child(2):第2个
  • :nth-child(odd)/ :nth-child(2n+1):所有奇数行
  • :nth-child(even)/ :nth-child(2n):所有偶数行
  • :nth-child(3n):每第3个(3, 6, 9…)

示例代码:

/* 链接悬停效果 */
a:hover {
  color: red;
  text-decoration: underline;
}

/* 表格斑马纹效果 */
tr:nth-child(odd) {
  background-color: #f2f2f2;
}

/* 除了最后一个li,都给右边距 */
li:not(:last-child) {
  margin-right: 20px;
}

伪元素

用于样式化元素的特定部分,而不是元素本身。

伪元素 示例 描述
::before p::before 在 <p>内容之前插入生成的内容。
::after p::after 在 <p>内容之后插入生成的内容。
::first-line p::first-line 选中 <p>的第一行文本。
::first-letter p::first-letter 选中 <p>的第一个字母(实现首字下沉)。
::selection ::selection 选中用户高亮的文本部分。

示例代码:

/* 给链接添加一个外部链接图标 */
a[href^="http"]::after {
  content: " ↗";
}

/* 首字下沉效果 */
p::first-letter {
  font-size: 2em;
  font-weight: bold;
  float: left;
  margin-right: 5px;
}

/* 改变用户选中文本的样式 */
::selection {
  background-color: lightblue;
  color: black;
}

选择器组

你可以将多个选择器用逗号分隔,分组在一起,以便为它们应用相同的样式。

/* 同时为h1, h2, h3应用相同的字体和颜色 */
h1, h2, h3 {
  font-family: 'Microsoft YaHei', sans-serif;
  color: #333;
}

/* 选中所有按钮和链接的悬停状态 */
button:hover, a:hover {
  opacity: 0.8;
}

优先级与特异性

当多个选择器同时指向同一个元素时,浏览器根据一套规则决定应用哪个样式。这套规则的核心是特异性

特异性权重计算规则(从高到低):

  • 行内样式:style=”…”— 1000分
  • ID选择器:#my-id— 100分/个
  • 类/属性/伪类选择器:.class, [type=”text”], :hover— 10分/个
  • 元素/伪元素选择器:div, p, ::before— 1分/个
  • 通配/关系选择器:*, >, +, ~— 0分
  • 比较规则:不是简单相加,而是逐级比较。一个ID选择器胜过无数个类和元素选择器。

示例:

#header .nav li a {...} /* 特异性: 100 + 10 + 1 + 1 = 112 */
.body .menu > a {...}   /* 特异性: 10 + 10 + 0 + 1 = 21 */
div a {...}             /* 特异性: 1 + 1 = 2 */
a {...}                 /* 特异性: 1 */

重要提示

  • !important规则会覆盖所有其他声明,但应尽量避免使用,因为它破坏了自然的级联规则,难以维护。
  • 选择器越具体,优先级越高。
  • 来源也会影响优先级:作者样式表(你写的) > 用户样式表 > 浏览器默认样式。

CSS盒模型详解

盒模型是CSS中最核心、最基础的概念,每一个HTML元素都被表示为一个矩形的盒子,CSS围绕这些盒子进行布局和样式设计。下面我将从内到外、从理论到实践,详细解析盒模型。

什么是盒模型?

CSS盒模型是一个描述HTML元素在页面中所占空间的模型。它规定了每个元素由一个内容区域及其周围的内边距边框外边距区域组成。

想象一下快递盒:

  • 内容 = 你买的商品
  • 内边距 = 包装盒内的缓冲泡沫
  • 边框 = 包装盒本身的纸板
  • 外边距 = 两个快递盒之间的间隔距离

盒模型的组成部分

内容区 (Content Area)

  • 包含元素的真实内容(文本、图片等)
  • 尺寸由 width和 height属性控制
  • 背景颜色/图片默认显示在此区域
div {
  width: 300px;    /* 内容区域宽度 */
  height: 200px;   /* 内容区域高度 */
  background-color: #f0f0f0; /* 背景色填充内容区 */
}

内边距 (Padding)

  • 内容区与边框之间的透明空间
  • 使用 padding相关属性控制
  • 背景颜色/图片会延伸到内边距区域
div {
  padding: 20px;                 /* 四个方向相同 */
  padding: 10px 20px;            /* 上下10px,左右20px */
  padding: 5px 10px 15px 20px;   /* 上、右、下、左(顺时针) */
  
  /* 或分别指定 */
  padding-top: 10px;
  padding-right: 15px;
  padding-bottom: 10px;
  padding-left: 15px;
}

边框 (Border)

  • 内边距和外边距之间的可见界线
  • 使用 border相关属性控制
  • 背景颜色/图片在边框处停止(除非使用 border-radius)
div {
  border: 2px solid #333;        /* 简写:宽度 样式 颜色 */
  border-width: 2px;             /* 边框宽度 */
  border-style: solid;           /* 样式:solid, dotted, dashed, double... */
  border-color: #333;            /* 颜色 */
  
  /* 或分别指定各边 */
  border-top: 1px dotted red;
  border-right: 2px solid blue;
  /* ... */
}

外边距 (Margin)

  • 盒子与其他盒子之间的透明空间
  • 使用 margin相关属性控制
  • 背景颜色/图片不会延伸到外边距区域
div {
  margin: 20px;                 /* 四个方向相同 */
  margin: 0 auto;               /* 上下0,左右自动(常用居中技巧) */
  margin: 10px 20px 30px 40px;  /* 上、右、下、左 */
  
  /* 分别指定 */
  margin-top: 10px;
  margin-right: 15px;
  /* ... */
}

两种重要的盒模型类型

这是盒模型中最关键的概念区别!

标准盒模型 (content-box) – 默认

  • width和 height只定义内容区域的尺寸
  • 元素总宽度 = width+ padding-left+ padding-right+ border-left+ border-right+ margin-left+ margin-right
  • 元素总高度 = height+ padding-top+ padding-bottom+ border-top+ border-bottom+ margin-top+ margin-bottom

怪异盒模型 (border-box)

  • width和 height定义内容+内边距+边框的总尺寸
  • 元素总宽度 = width+ margin-left+ margin-right
  • 元素总高度 = height+ margin-top+ margin-bottom

如何切换盒模型?

/* 设置为怪异盒模型 - 强烈推荐! */
* {
  box-sizing: border-box;
}

/* 或针对特定元素 */
div {
  box-sizing: border-box;
}

/* 显式设置为标准盒模型(默认) */
div {
  box-sizing: content-box;
}

盒模型计算示例

标准盒模型 (content-box)

div {
  width: 300px;
  height: 200px;
  padding: 20px;
  border: 5px solid #333;
  margin: 10px;
  box-sizing: content-box; /* 默认 */
}
  • 实际宽度 = 300(width) + 20×2(padding) + 5×2(border) + 10×2(margin) = 370px
  • 实际高度 = 200(height) + 20×2(padding) + 5×2(border) + 10×2(margin) = 270px

怪异盒模型 (border-box)

div {
  width: 300px;
  height: 200px;
  padding: 20px;
  border: 5px solid #333;
  margin: 10px;
  box-sizing: border-box;
}
  • 内容区宽度 = 300 – 20×2 – 5×2 = 250px
  • 实际宽度 = 300(width) + 10×2(margin) = 320px
  • 实际高度 = 200(height) + 10×2(margin) = 220px

外边距的特殊行为

外边距合并 (Margin Collapsing)

当两个垂直相邻元素的上下外边距相遇时,它们会合并成一个外边距,其大小取两者中的较大者。

<div style="margin-bottom: 30px;">第一个div</div>
<div style="margin-top: 20px;">第二个div</div>

这两个div之间的实际间距是 30px(取最大值),而不是50px。

何时会发生合并?

  • 相邻的兄弟元素之间
  • 父元素与第一个/最后一个子元素之间(如果没有边框、内边距或内容隔开)
  • 空元素自身的上下外边距

如何防止外边距合并?

  • 添加边框或内边距
  • 创建新的块格式化上下文(BFC),如设置 overflow: auto/hidden
  • 使用 flexbox 或 grid 布局

负外边距

外边距可以设置为负值,这会让元素向相反方向移动。

div {
  margin-top: -10px;   /* 向上移动10px */
  margin-left: -20px;  /* 向左移动20px */
}

实际开发建议

全局设置为 border-box

*,
*::before,
*::after {
  box-sizing: border-box;
}

这样做可以让尺寸计算更直观,是现代CSS开发的最佳实践。

使用开发者工具调试

浏览器开发者工具(F12)中的”Elements”面板可以直观地查看每个元素的盒模型,是调试布局的必备工具。

理解布局上下文

不同的布局方式(正常流、flexbox、grid)对盒模型的解释略有不同,但基本原理不变。

注意默认样式

不同浏览器对某些元素(如<body>、<p>)有默认的margin和padding,通常需要在CSS开头进行重置:

body, h1, h2, h3, h4, h5, h6, p, ul, ol {
  margin: 0;
  padding: 0;
}

或使用更全面的CSS Reset或Normalize.css。

CSS 常用属性详解

文本与字体属性

字体相关

p {
  font-family: "Microsoft YaHei", Arial, sans-serif; /* 字体栈,浏览器会按顺序使用第一个可用的 */
  font-size: 16px;          /* 字体大小:px, em, rem, % */
  font-weight: 400;         /* 字重:100-900 或 normal(400)/bold(700) */
  font-style: italic;       /* 样式:normal/italic/oblique */
  line-height: 1.6;        /* 行高:无单位数字表示字体大小的倍数 */
}

/* 简写 */
p {
  font: italic 700 16px/1.6 "Microsoft YaHeui", sans-serif;
  /* 顺序:style weight size/line-height family */
}

文本相关

h1 {
  color: #333;              /* 文字颜色:关键字、十六进制、rgb()、rgba() */
  text-align: center;       /* 水平对齐:left/center/right/justify */
  text-decoration: none;    /* 装饰线:none/underline/overline/line-through */
  text-transform: uppercase;/* 文本转换:none/uppercase/lowercase/capitalize */
  letter-spacing: 1px;      /* 字符间距 */
  word-spacing: 2px;        /* 单词间距 */
  text-shadow: 2px 2px 4px rgba(0,0,0,0.3); /* 文字阴影:x偏移 y偏移 模糊半径 颜色 */
}

p {
  text-indent: 2em;         /* 首行缩进 */
  white-space: nowrap;      /* 空白处理:normal/nowrap/pre/pre-wrap/pre-line */
  word-wrap: break-word;    /* 长单词换行 */
  overflow-wrap: break-word;/* 更现代的替代方案 */
}

颜色与背景属性

颜色表示方式

div {
  color: red;               /* 颜色关键字 */
  color: #ff0000;           /* 十六进制 */
  color: #f00;              /* 简写十六进制 */
  color: rgb(255, 0, 0);    /* RGB */
  color: rgba(255, 0, 0, 0.5); /* RGB + 透明度 (0-1) */
  color: hsl(0, 100%, 50%); /* HSL:色相(0-360) 饱和度(0-100%) 明度(0-100%) */
  color: hsla(0, 100%, 50%, 0.5); /* HSL + 透明度 */
}

背景属性

.hero {
  background-color: #f8f8f8;          /* 背景颜色 */
  background-image: url("image.jpg"); /* 背景图片 */
  background-repeat: no-repeat;       /* 重复方式:repeat/no-repeat/repeat-x/repeat-y */
  background-position: center center; /* 位置:left/center/right top/center/bottom 或 具体值 */
  background-size: cover;             /* 尺寸:cover/contain/具体值 */
  background-attachment: fixed;       /* 附着方式:scroll/fixed/local */
}

/* 简写 */
.hero {
  background: #f8f8f8 url("image.jpg") no-repeat center center / cover fixed;
}

盒模型属性(核心)

尺寸控制

.container {
  width: 100%;              /* 宽度 */
  height: 100vh;            /* 高度:100vh = 视口高度 */
  min-width: 300px;         /* 最小宽度 */
  max-width: 1200px;        /* 最大宽度 */
  min-height: 200px;        /* 最小高度 */
  max-height: 800px;        /* 最大高度 */
  
  /* 现代替代方案 */
  inline-size: 100%;        /* 逻辑宽度(根据书写模式) */
  block-size: 100vh;        /* 逻辑高度 */
}

内边距与外边距

.box {
  /* 内边距 */
  padding: 20px;                    /* 四边相同 */
  padding: 10px 20px;               /* 上下 左右 */
  padding: 5px 10px 15px 20px;      /* 上 右 下 左 */
  
  /* 外边距 */
  margin: 0 auto;                   /* 水平居中常用技巧 */
  margin: 10px 20px 30px 40px;      /* 上 右 下 左 */
  
  /* 逻辑属性(支持书写模式) */
  padding-inline: 20px;             /* 左右内边距 */
  padding-block: 10px;              /* 上下内边距 */
  margin-inline: auto;              /* 左右外边距自动(水平居中) */
}

边框

.btn {
  border: 2px solid #333;          /* 简写:宽度 样式 颜色 */
  border-width: 1px 2px 3px 4px;   /* 各边宽度 */
  border-style: solid dotted dashed double; /* 各边样式 */
  border-color: red green blue yellow; /* 各边颜色 */
  border-radius: 8px;              /* 圆角:可分别设置四个角 */
  border-top-left-radius: 10px;     /* 单独设置左上角 */
  
  /* 高级圆角 */
  border-radius: 10px 20px 30px 40px / 5px 10px 15px 20px; /* 水平半径 / 垂直半径 */
}

布局属性(现代CSS核心)

Flexbox 弹性布局

.container {
  display: flex;                   /* 启用flex布局 */
  flex-direction: row;             /* 主轴方向:row/row-reverse/column/column-reverse */
  flex-wrap: wrap;                 /* 换行:nowrap/wrap/wrap-reverse */
  justify-content: center;         /* 主轴对齐:flex-start/flex-end/center/space-between/space-around/space-evenly */
  align-items: center;             /* 交叉轴对齐:stretch/flex-start/flex-end/center/baseline */
  align-content: space-between;    /* 多轴线对齐 */
  gap: 20px;                       /* 项目间距 */
}

.item {
  flex: 1;                         /* 简写:grow shrink basis */
  flex-grow: 1;                    /* 放大比例 */
  flex-shrink: 0;                  /* 缩小比例 */
  flex-basis: 200px;               /* 初始大小 */
  align-self: flex-start;          /* 单个项目对齐方式 */
  order: 2;                        /* 排列顺序 */
}

Grid 网格布局

.container {
  display: grid;
  grid-template-columns: 1fr 2fr 1fr; /* 列轨道:fr单位、px、%、auto等 */
  grid-template-rows: 100px auto 100px; /* 行轨道 */
  grid-template-areas: 
    "header header header"
    "sidebar main aside"
    "footer footer footer";        /* 区域命名 */
  gap: 20px;                        /* 网格间隙 */
  justify-items: center;            /* 单元格水平对齐 */
  align-items: center;              /* 单元格垂直对齐 */
  justify-content: center;          /* 整个网格水平对齐 */
  align-content: center;            /* 整个网格垂直对齐 */
}

.item {
  grid-column: 1 / 3;               /* 列线范围:开始线 / 结束线 */
  grid-row: 1 / 2;                  /* 行线范围 */
  grid-area: header;                /* 指定区域 */
  justify-self: start;              /* 单个项目水平对齐 */
  align-self: end;                  /* 单个项目垂直对齐 */
}

定位

.element {
  position: static;        /* 默认:正常文档流 */
  position: relative;      /* 相对定位:相对于自身原位置 */
  position: absolute;      /* 绝对定位:相对于最近的非static定位祖先 */
  position: fixed;         /* 固定定位:相对于视口 */
  position: sticky;       /* 粘性定位:在滚动时固定 */
  
  top: 10px;              /* 定位偏移 */
  right: 20px;
  bottom: 30px;
  left: 40px;
  
  z-index: 10;            /* 堆叠顺序 */
}

变换、过渡与动画

变换 (Transform)

.card {
  transform: translate(50px, 100px); /* 移动:translateX() translateY() */
  transform: rotate(45deg);          /* 旋转 */
  transform: scale(1.2);             /* 缩放:scaleX() scaleY() */
  transform: skew(30deg, 20deg);     /* 倾斜:skewX() skewY() */
  
  /* 多重变换 */
  transform: translateX(50px) rotate(45deg) scale(1.2);
  
  transform-origin: left top;        /* 变换原点 */
}

过渡 (Transition)

.btn {
  transition: all 0.3s ease-in-out; /* 简写:property duration timing-function delay */
  transition-property: background-color, transform; /* 应用过渡的属性 */
  transition-duration: 0.3s;        /* 过渡时间 */
  transition-timing-function: ease-in-out; /* 时间函数:ease/linear/ease-in/ease-out/ease-in-out/cubic-bezier() */
  transition-delay: 0.1s;           /* 延迟时间 */
}

动画 (Animation)

@keyframes slideIn {
  from {
    transform: translateX(-100%);
    opacity: 0;
  }
  to {
    transform: translateX(0);
    opacity: 1;
  }
}

.element {
  animation: slideIn 0.5s ease-in-out forwards; /* 简写:name duration timing-function delay iteration-count direction fill-mode */
  animation-name: slideIn;        /* 动画名称 */
  animation-duration: 0.5s;       /* 动画时长 */
  animation-timing-function: ease-in-out; /* 时间函数 */
  animation-delay: 0.2s;          /* 延迟 */
  animation-iteration-count: infinite; /* 重复次数:数字/infinite */
  animation-direction: alternate; /* 方向:normal/reverse/alternate/alternate-reverse */
  animation-fill-mode: forwards;  /* 填充模式:none/forwards/backwards/both */
  animation-play-state: running;  /* 播放状态:running/paused */
}

其他重要属性

显示与可见性

.element {
  display: block;           /* 块级元素 */
  display: inline;         /* 行内元素 */
  display: inline-block;   /* 行内块元素 */
  display: flex;            /* 弹性盒子 */
  display: grid;            /* 网格布局 */
  display: none;           /* 完全不显示,不占空间 */
  
  visibility: visible;      /* 可见 */
  visibility: hidden;       /* 隐藏,但仍占空间 */
  
  opacity: 0.5;            /* 透明度:0-1 */
}

溢出处理

.container {
  overflow: visible;        /* 默认:内容溢出时显示 */
  overflow: hidden;        /* 隐藏溢出内容 */
  overflow: scroll;        /* 总是显示滚动条 */
  overflow: auto;          /* 需要时显示滚动条 */
  
  overflow-x: hidden;      /* 水平溢出处理 */
  overflow-y: auto;        /* 垂直溢出处理 */
  
  text-overflow: ellipsis; /* 文本溢出显示省略号,需配合: */
  white-space: nowrap;
  overflow: hidden;
}

光标与用户交互

button {
  cursor: pointer;         /* 光标样式:pointer/help/wait/crosshair/not-allowed等 */
  user-select: none;       /* 用户选择:none/text/all/auto */
  pointer-events: none;    /* 鼠标事件:none/auto */
}

现代CSS特性

变量(自定义属性)

:root {
  --primary-color: #007bff;
  --spacing: 20px;
  --font-size: 16px;
}

.element {
  color: var(--primary-color);
  padding: var(--spacing);
  font-size: var(--font-size, 16px); /* 备用值 */
}

滤镜效果

.image {
  filter: blur(5px);               /* 模糊 */
  filter: brightness(1.5);         /* 亮度 */
  filter: contrast(200%);          /* 对比度 */
  filter: grayscale(100%);         /* 灰度 */
  filter: hue-rotate(90deg);       /* 色相旋转 */
  filter: invert(100%);            /* 反色 */
  filter: opacity(50%);            /* 透明度 */
  filter: saturate(200%);          /* 饱和度 */
  filter: sepia(100%);             /* 褐色滤镜 */
  
  /* 多重滤镜 */
  filter: contrast(175%) brightness(103%);
}

混合模式

.overlay {
  background-blend-mode: multiply; /* 背景混合模式 */
  mix-blend-mode: screen;          /* 元素混合模式:normal/multiply/screen/overlay等 */
}

实用建议

  • 性能优化:避免过度使用耗性能的属性如box-shadow、filter、transform等
  • 浏览器兼容性:使用现代属性时考虑兼容性,可通过Autoprefixer等工具自动添加前缀
  • 命名规范:采用BEM、SMACSS等命名方法论提高代码可维护性
  • 响应式设计:多用相对单位(rem、em、%、vw、vh)而非固定像素

CSS布局技术

CSS布局技术是前端开发的核心,它决定了网页元素如何排列和呈现。下面我为你系统介绍各种CSS布局技术,从传统方法到现代方案,以及如何选择使用它们。

布局基础:盒模型与文档流

理解CSS布局,首先需要掌握两个基础概念:盒模型和文档流。

盒模型 (Box Model):每个HTML元素都被视为一个矩形盒子,由内到外包括:

  • 内容 (Content):显示文本、图像等实际内容,尺寸由 width和 height控制。
  • 内边距 (Padding):内容区与边框之间的透明区域,使用 padding相关属性控制。
  • 边框 (Border):围绕内边距和内容的线,使用 border相关属性控制。
  • 外边距 (Margin):盒子与其他盒子之间的透明区域,使用 margin相关属性控制,用于创建元素间距。

盒模型的计算方式可通过 box-sizing属性设置:

  • content-box(默认):元素的 width和 height只包括内容区域。总宽度 = width+ padding-left/right+ border-left/right+ margin-left/right。
  • border-box(推荐):元素的 width和 height包括内容、内边距和边框。总宽度 = width+ margin-left/right。这更直观,便于布局。建议全局设置:
*, *::before, *::after {
  box-sizing: border-box;
}

文档流 (Normal Flow):默认情况下,块级元素(如 div, p)独占一行,行内元素(如 span, a)则按顺序水平排列。许多布局技术旨在脱离控制文档流。

传统布局方案

在Flexbox和Grid出现之前,主要依赖这些方法实现复杂布局。

浮动布局 (Float Layout)

设计初衷

float属性最初的设计目的并不是为了复杂的页面布局,而是为了实现简单的文字环绕图片的效果,类似于报纸和杂志的排版方式。

基本属性值

  • float: left;:元素向左浮动
  • float: right;:元素向右浮动
  • float: none;:默认值,不浮动
  • float: inherit;:继承父元素的浮动属性

浮动的工作原理与行为

当一个元素被浮动时,它会发生以下变化:

  • 脱离文档流:元素从正常的文档流中被“取出”,不再占据原本的空间。
  • 向左或向右移动:直到碰到其容器元素的边缘或者另一个浮动元素的边缘为止。
  • 内容环绕:内联内容(如文本) 会识别浮动元素的边界并环绕它。这也是其最初的设计目的。

代码示例:文字环绕

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图文混排示例</title>
<style>
  .image-float {
    float: left;      /* 图片向左浮动 */
    margin: 0 15px 15px 0; /* 添加一些外边距让文字不紧贴图片 */
    width: 200px;
  }
</style>
</head>
<body>
<div>
    <img src="https://picsum.photos/200/200" alt="示例图片" class="image-float">
    <p>这是一个典型的图文混排示例,图片向左浮动,文本围绕在图片周围。这种布局在文章、博客和新闻网站中非常常见。</p>
    <p>浮动布局使得我们可以轻松实现文本环绕图片的效果,而不需要复杂的定位或表格布局。</p>
    <p>继续添加更多文本,看看文本如何流畅地环绕在图片周围。当文本足够多时,它会完全包围图片,然后在下方继续正常流动。</p>
</div>
</body>
</html>

效果图示:

从文字环绕到页面布局

开发者发现,通过将多个块级元素(如<div>)设置为浮动,可以让它们并排排列,从而创造出多栏布局。这是浮动属性被“创造性滥用”来作为主要布局技术的开始。

代码示例:经典的三栏布局

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>经典的三栏布局</title>
<style>
  /* 基础样式 */
  .container {
    width: 80%;
    margin: 0 auto; /* 容器居中 */
    background-color: #f5f5f5;
    padding: 20px;
  }
  
  .column {
    height: 300px; /* 给一个高度以便观察 */
    padding: 20px;
    box-sizing: border-box; /* 非常重要!让padding包含在width内 */
  }
  
  /* 浮动布局核心 */
  .left {
    float: left;
    width: 25%;
    background-color: #ffcccc;
  }
  
  .main {
    float: left;
    width: 50%;
    background-color: #ccffcc;
  }
  
  .right {
    float: right;
    width: 25%;
    background-color: #ccccff;
  }
</style>
</head>
<body>

<div class="container">
  <div class="column left">左侧边栏 (25%)</div>
  <div class="column main">主内容区 (50%)</div>
  <div class="column right">右侧边栏 (25%)</div>
</div>

</body>
</html>

浮动的核心问题:高度塌陷与清除浮动

这是浮动布局最令人头疼的地方,也是必须理解的概念。

什么是高度塌陷?当一个父容器内部的所有元素都浮动后,由于浮动元素脱离文档流,父容器在计算高度时,会认为其中没有任何内容,因此高度会变为0(或仅由padding/border决定),导致布局混乱。

解决方案:清除浮动 (Clearfix)。清除浮动的目的是告诉父容器:“请你在计算高度时,考虑一下你里面那些浮动的孩子。”

方法一:空div清除法(古老且不语义化)

<div class="container">
  <div class="column left">左侧边栏 (25%)</div>
  <div class="column main">主内容区 (50%)</div>
  <div class="column right">右侧边栏 (25%)</div>
  <div style="clear: both;"></div>
</div>

clear: both;意味着该元素左侧和右侧不允许出现浮动元素,因此它会被推到所有浮动元素的下方。父容器为了包裹这个空div,自然也就包裹了所有浮动元素。

方法二:overflow 法

.container {
  overflow: hidden; /* 或者 auto */
  width: 80%;
  margin: 0 auto;
}

为父容器设置 overflow: hidden或 overflow: auto可以触发一个叫 BFC (Block Formatting Context) 的机制。BFC区域内的浮动元素也会参与高度计算。

缺点:可能会意外地裁剪掉定位在容器外的元素或显示不必要的滚动条。

方法三:现代最佳实践 —— 伪元素Clearfix

这是目前最推荐、最通用的方法。

/* 定义一个clearfix类 */
.clearfix::after {
  content: "";    /* 无需实际内容 */
  display: table; /* 也可以是 block */
  clear: both;    /* 核心:清除左右两侧的浮动 */
}

/* 为了兼容旧版本浏览器,有时会使用双伪元素版本 */
.clearfix::before,
.clearfix::after {
  content: "";
  display: table;
}
.clearfix::after {
  clear: both;
}

使用方法:

<!-- 直接将clearfix类添加到父容器 -->
<div class="container clearfix">
  <div class="column left">左侧边栏 (25%)</div>
  <div class="column main">主内容区 (50%)</div>
  <div class="column right">右侧边栏 (25%)</div>
</div>

浮动布局的其他挑战与技巧

  • 等高的列:浮动元素的默认高度由内容决定。要实现多栏等高效果,需要借助巨大的负外边距和正内边距等“Hack”技巧,非常繁琐。而Flexbox和Grid原生支持等高布局。
  • 外边距折叠:在清除浮动时,需要注意垂直方向上的外边距折叠问题。
  • 响应式布局困难:让浮动布局适应不同屏幕尺寸需要大量媒体查询和百分比宽度计算,远不如Flexbox和Grid灵活。

浮动布局的现状与总结

方面 说明
历史地位 在Flexbox和Grid出现之前,它是实现PC端多栏布局的唯一可行方案,统治了Web布局近十年。
现代开发 不推荐用于主要页面布局。对于新项目,应优先使用 Flexbox(一维布局)和 Grid(二维布局)。
适用场景 文字环绕图片(其本职工作)、少量传统项目维护、或者需要兼容非常古老浏览器的情况。
核心教训 一定要清除浮动,否则必然导致高度塌陷,布局崩溃。

定位布局 (Positioning Layout)

定位布局是CSS中控制元素位置的强大工具,它允许你精确地将元素放置在页面的特定位置,甚至脱离正常的文档流。

核心概念:position 属性

position属性是定位布局的核心,它定义了元素的定位方法,有五个可能的值:

定位方式 属性值 参考点 是否脱离文档流 典型应用场景
静态定位 static 正常文档流位置 默认值,恢复普通流
相对定位 relative 自身原有位置 否(保留原占位) 微调元素位置,作为绝对定位的参考容器
绝对定位 absolute 相对于最近非static定位的祖先元素 模态框、下拉菜单、精准定位的UI组件
固定定位 fixed 相对于浏览器视口 固定导航栏、悬浮按钮、弹窗
粘性定位 sticky 在父容器和视口之间切换 否(滚动时表现特殊) 吸顶效果、滚动标题

偏移属性

一旦设置了 position值为 relative, absolute, fixed或 sticky,就可以使用以下四个属性进行精确定位:

.element {
  position: absolute;
  top: 20px;      /* 距离参考点上边缘20px */
  right: 50px;    /* 距离参考点右边缘50px */
  bottom: 10px;   /* 距离参考点下边缘10px */
  left: 30px;     /* 距离参考点左边缘30px */
}

重要规则:

  • 如果同时设置 left和 right,left优先于 right
  • 如果同时设置 top和 bottom,top优先于 bottom
  • 如果只设置一侧属性,另一侧会保持自动计算

各种定位方式详解

静态定位 (Static) – 默认值

.element {
  position: static; /* 默认值,可以用于覆盖其他定位 */
}
  • 元素遵循正常的文档流
  • 忽略 top, right, bottom, left和 z-index属性
  • 主要用于重置元素的定位方式

相对定位 (Relative) – “便利贴式”定位

.box {
  position: relative;
  top: 30px;   /* 从原位置向下移动30px */
  left: 20px;  /* 从原位置向右移动20px */
}

特点:

  • 元素保留其原有空间,不影响其他元素布局
  • 移动时相对于自身原本的位置
  • 常作为绝对定位子元素的定位上下文

实用示例:微调图标位置

.icon-wrapper {
  position: relative;
}

.icon-badge {
  position: absolute;
  top: -8px;    /* 向上移动 */
  right: -8px;  /* 向右移动 */
}

绝对定位 (Absolute) – “精确制导”定位

.element {
  position: absolute;
  top: 0;
  left: 0;
}

核心特性:

  • 元素完全脱离文档流,不保留原有空间
  • 定位参考点是最近的非static定位祖先元素
  • 如果没有这样的祖先,则相对于初始包含块(通常是<html>)

重要技巧:创建定位上下文

<div class="relative-parent"> <!-- 这个div成为定位上下文 -->
  <div class="absolute-child"></div>
</div>
.relative-parent {
  position: relative; /* 创建定位上下文 */
  width: 300px;
  height: 200px;
}

.absolute-child {
  position: absolute;
  top: 20px;
  left: 30px;
}

实用示例:创建下拉菜单

/* HTML结构:<nav><ul><li>菜单项<ul class="submenu">...</ul></li></ul></nav> */

nav li {
  position: relative; /* 为子菜单创建定位上下文 */
}

.submenu {
  position: absolute;
  top: 100%;      /* 紧贴父菜单底部 */
  left: 0;
  display: none;
  min-width: 150px;
}

nav li:hover .submenu {
  display: block;
}

固定定位 (Fixed) – “如影随形”定位

.fixed-element {
  position: fixed;
  bottom: 20px;     /* 距离视口底部20px */
  right: 20px;      /* 距离视口右侧20px */
  z-index: 1000;    /* 确保在最上层 */
}

核心特性:

  • 相对于浏览器视口定位
  • 不随页面滚动而移动
  • 完全脱离文档流

实用示例:固定导航栏和返回顶部按钮

/* 固定顶部导航 */
.header {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  z-index: 1000;
  background: white;
  box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}

/* 为主内容添加补偿间距,防止被固定导航遮挡 */
.main-content {
  padding-top: 80px; /* 等于固定导航的高度 */
}

/* 返回顶部按钮 */
.back-to-top {
  position: fixed;
  bottom: 30px;
  right: 30px;
  width: 50px;
  height: 50px;
  border-radius: 50%;
  background: #007bff;
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.3s;
}

.back-to-top.visible {
  opacity: 1;
}

粘性定位 (Sticky) – “智能吸附”定位

.sticky-element {
  position: sticky;
  top: 0; /* 当元素到达视口顶部0px位置时固定 */
}

核心特性

  • 混合定位:在父容器内表现为相对定位,滚动出视口时表现为固定定位
  • 需要指定至少一个”粘性约束”(top, right, bottom, left)
  • 父容器的溢出设置会影响粘性效果

实用示例:表格标题行和章节标题吸顶

/* 表格粘性表头 */
.table-container {
  height: 400px;
  overflow: auto;
}

table th {
  position: sticky;
  top: 0;
  background: white;
  z-index: 10;
  box-shadow: 0 2px 3px rgba(0,0,0,0.1);
}

/* 章节标题吸顶 */
.section-header {
  position: sticky;
  top: 60px; /* 考虑已有固定导航栏的高度 */
  background: #f8f9fa;
  padding: 10px;
  z-index: 5;
}

层叠上下文与 z-index

当多个定位元素重叠时,z-index控制它们的堆叠顺序。

.modal {
  position: fixed;
  z-index: 1050; /* 确保在最上层 */
}

.overlay {
  position: fixed;
  z-index: 1040; /* 在模态框下层 */
}

重要规则:

  • z-index只对定位元素(非static)有效
  • 值可以是正数、负数或0(默认auto)
  • 数值越大,元素越靠前
  • 层叠上下文的形成会影响z-index的作用范围

实际开发技巧与注意事项

居中定位技巧

/* 绝对定位居中 */
.centered-box {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%); /* 使用变换实现真正居中 */
}

/* 现代替代方案 */
.centered-box-modern {
  position: absolute;
  inset: 0; /* 设置所有边为0 */
  margin: auto; /* 浏览器自动计算外边距实现居中 */
  width: fit-content; /* 宽度适应内容 */
  height: fit-content;
}

定位与Flexbox/Grid结合

.card {
  display: flex;
  position: relative; /* 为内部绝对定位元素创建上下文 */
}

.card-badge {
  position: absolute;
  top: -10px;
  right: -10px;
}

常见问题与解决方案

问题:父元素高度塌陷(绝对定位子元素不参与父元素高度计算)

解决方案:为父元素显式设置高度,或使用JavaScript计算

问题:固定定位在移动端浏览器中的异常行为

解决方案:使用JavaScript辅助或考虑使用绝对定位替代

问题:粘性定位在特定浏览器中不生效

解决方案:检查父容器是否有 overflow设置,并确保指定了约束值

现代布局神器

现代布局方案更强大、灵活,能高效解决复杂布局问题。

弹性盒子布局 (Flexbox)

Flexbox是CSS3中一种强大的一维布局模型,它让我们能够更高效地处理空间分配、对齐和排序等问题,特别适合组件级和小规模布局。

为什么需要Flexbox?

在Flexbox出现之前,开发者主要依赖以下方式实现布局:

  • 表格布局(display: table)
  • 浮动布局(float)
  • 定位布局(position)

这些方法都存在各种局限,比如垂直居中困难、等高列实现复杂等。Flexbox的出现完美解决了这些问题。

Flexbox的核心概念

Flex容器和Flex项目

  • Flex容器:设置了 display: flex或 display: inline-flex的元素
  • Flex项目:Flex容器的直接子元素
<div class="flex-container"> <!-- Flex容器 -->
  <div class="flex-item">项目1</div> <!-- Flex项目 -->
  <div class="flex-item">项目2</div> <!-- Flex项目 -->
  <div class="flex-item">项目3</div> <!-- Flex项目 -->
</div>

主轴和交叉轴

Flexbox基于主轴交叉轴的概念:

  • 主轴:由 flex-direction定义的主要方向
  • 交叉轴:与主轴垂直的方向

Flex容器属性详解

定义Flex容器

.flex-container {
  display: flex; /* 块级Flex容器 */
  /* 或者 */
  display: inline-flex; /* 行内Flex容器 */
}

主轴方向:flex-direction

决定项目的排列方向

.container {
  flex-direction: row;            /* 默认值:从左到右 */
  flex-direction: row-reverse;    /* 从右到左 */
  flex-direction: column;         /* 从上到下 */
  flex-direction: column-reverse; /* 从下到上 */
}

可视化效果:

row:          [1] [2] [3] [4]
row-reverse:  [4] [3] [2] [1]  
column:       [1]    column-reverse: [4]
              [2]                   [3]
              [3]                   [2]
              [4]                   [1]

换行控制:flex-wrap

控制项目是否换行

.container {
  flex-wrap: nowrap;    /* 默认:不换行,项目会压缩 */
  flex-wrap: wrap;      /* 换行:从上到下 */
  flex-wrap: wrap-reverse; /* 换行:从下到上 */
}

主轴对齐:justify-content

控制项目在主轴上的对齐方式

.container {
  justify-content: flex-start;    /* 默认:起始位置对齐 */
  justify-content: flex-end;      /* 末端对齐 */
  justify-content: center;       /* 居中对齐 */
  justify-content: space-between; /* 两端对齐,项目间间隔相等 */
  justify-content: space-around;   /* 每个项目两侧间隔相等 */
  justify-content: space-evenly;   /* 所有间隔完全相等 */
}

交叉轴对齐:align-items

控制项目在交叉轴上的对齐方式

.container {
  align-items: stretch;     /* 默认:拉伸填满容器高度 */
  align-items: flex-start;  /* 交叉轴起始处对齐 */
  align-items: flex-end;    /* 交叉轴末端对齐 */
  align-items: center;     /* 交叉轴居中对齐 */
  align-items: baseline;   /* 项目的第一行文字基线对齐 */
}

多行对齐:align-content

当有多行/多列时,控制行/列在交叉轴上的对齐方式

.container {
  align-content: stretch;     /* 默认:拉伸行填满空间 */
  align-content: flex-start;  /* 交叉轴起始处对齐 */
  align-content: flex-end;    /* 交叉轴末端对齐 */
  align-content: center;      /* 交叉轴居中对齐 */
  align-content: space-between; /* 两端对齐 */
  align-content: space-around;  /* 每行周围间隔相等 */
}

间距控制:gap

控制项目之间的间距(较新的属性)

.container {
  gap: 10px;           /* 项目行列间距都是10px */
  gap: 10px 20px;      /* 行间距10px,列间距20px */
  row-gap: 10px;       /* 只设置行间距 */
  column-gap: 20px;    /* 只设置列间距 */
}

Flex项目属性详解

排序控制:order

控制项目的显示顺序

.item {
  order: 0; /* 默认值:0 */
}

数值越小,排列越靠前。可以为负值。

放大比例:flex-grow

定义项目的放大能力

.item {
  flex-grow: 0; /* 默认值:不放大 */
  flex-grow: 1; /* 有剩余空间时放大 */
}

示例:三个项目分别设置 flex-grow: 1, flex-grow: 2, flex-grow: 1,则它们将按1:2:1的比例分配剩余空间。

缩小比例:flex-shrink

定义项目的缩小能力

.item {
  flex-shrink: 1; /* 默认值:空间不足时缩小 */
  flex-srink: 0;  /* 禁止缩小 */
}

基准大小:flex-basis

定义项目在分配多余空间之前的默认大小

.item {
  flex-basis: auto; /* 默认值:项目本来大小 */
  flex-basis: 200px; /* 固定宽度 */
  flex-basis: 20%;   /* 百分比宽度 */
}

简写属性:flex

flex-grow, flex-shrink, flex-basis的简写

.item {
  flex: none;        /* 0 0 auto */
  flex: auto;        /* 1 1 auto */
  flex: 1;           /* 1 1 0% */
  flex: 0 0 200px;   /* 不放大、不缩小、固定200px */
  flex: 2 1 300px;   /* 放大比例2、缩小比例1、基准300px */
}

单独对齐:align-self

允许单个项目有与其他项目不同的对齐方式

.item {
  align-self: auto;     /* 默认:继承align-items */
  align-self: flex-start;
  align-self: flex-end;
  align-self: center;
  align-self: baseline;
  align-self: stretch;
}

实用布局模式

水平居中

.container {
  display: flex;
  justify-content: center; /* 主轴居中 */
}

垂直居中

.container {
  display: flex;
  align-items: center; /* 交叉轴居中 */
}

完全居中

.container {
  display: flex;
  justify-content: center; /* 主轴居中 */
  align-items: center;     /* 交叉轴居中 */
}

等高分栏

.container {
  display: flex;
}

.column {
  flex: 1; /* 所有栏目等分宽度 */
}

导航菜单

.nav {
  display: flex;
  gap: 20px;
}

.nav-item {
  /* 自动适应内容 */
}

.nav-item.push-right {
  margin-left: auto; /* 向右推 */
}

响应式卡片布局

.card-container {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
}

.card {
  flex: 1 1 300px; /* 可放大、可缩小、基准300px */
}

实际开发示例

现代导航栏

<nav class="navbar">
  <div class="logo">网站LOGO</div>
  <ul class="nav-links">
    <li><a href="#">首页</a></li>
    <li><a href="#">产品</a></li>
    <li><a href="#">关于</a></li>
    <li><a href="#">联系</a></li>
  </ul>
  <div class="user-actions">
    <button>登录</button>
    <button>注册</button>
  </div>
</nav>
.navbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 20px;
  height: 60px;
  background: #333;
  color: white;
}

.nav-links {
  display: flex;
  gap: 30px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.user-actions {
  display: flex;
  gap: 10px;
}

卡片组件布局

.card {
  display: flex;
  flex-direction: column;
  max-width: 350px;
  border: 1px solid #ddd;
  border-radius: 8px;
  overflow: hidden;
}

.card-img {
  width: 100%;
  height: 200px;
  object-fit: cover;
}

.card-content {
  display: flex;
  flex-direction: column;
  flex-grow: 1; /* 让内容区域填充剩余空间 */
  padding: 20px;
}

.card-title {
  margin: 0 0 10px 0;
}

.card-description {
  flex-grow: 1; /* 描述填充剩余空间 */
  margin-bottom: 20px;
}

.card-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

浏览器兼容性与最佳实践

兼容性提示:

  • 现代浏览器全面支持Flexbox
  • 需要兼容旧浏览器时考虑使用autoprefixer
  • IE10/11有部分支持,需要特别注意

最佳实践:

  • 移动优先:Flexbox非常适合移动端布局
  • 渐进增强:为不支持Flexbox的浏览器提供降级方案
  • 合理使用:Flexbox适合组件布局,复杂页面布局建议使用Grid
  • 性能考虑:避免过度嵌套Flex容器

常见问题解决

项目宽度异常:

.item {
  min-width: 0; /* 解决文本溢出问题 */
}

滚动条问题:

.container {
  min-height: 0; /* 解决滚动条显示问题 */
}

网格布局 (CSS Grid)

网格布局是CSS中最强大的二维布局系统,专门为解决复杂网页布局而设计。它允许我们同时控制行和列,创建精确的网格结构。

为什么需要网格布局?

在网格布局之前,我们主要依赖:

  • 表格布局(语义化差)
  • 浮动布局(清除浮动麻烦)
  • Flexbox(主要处理一维布局)

网格布局解决了这些痛点,提供了真正的二维布局能力。

核心概念

  • 网格容器和网格项目
    • 网格容器:设置 display: grid的元素
    • 网格项目:网格容器的直接子元素
<div class="grid-container"> <!-- 网格容器 -->
  <div class="grid-item">项目1</div> <!-- 网格项目 -->
  <div class="grid-item">项目2</div> <!-- 网格项目 -->
  <div class="grid-item">项目3</div> <!-- 网格项目 -->
</div>
  • 网格线 (Grid Lines),网格的分隔线,有行网格线和列网格线
  • 网格轨道 (Grid Tracks),行和列的通道,即行高和列宽
  • 网格单元格 (Grid Cell),最小的网格单位,由相邻的行线和列线组成
  • 网格区域 (Grid Area),由一个或多个网格单元格组成的矩形区域

网格容器属性详解

定义网格容器

.grid-container {
  display: grid; /* 块级网格容器 */
  /* 或者 */
  display: inline-grid; /* 行内网格容器 */
}

定义列和行:grid-template-columns / grid-template-rows

.grid-container {
  /* 定义3列:200px | 1fr | 300px */
  grid-template-columns: 200px 1fr 300px;
  
  /* 定义2行:100px 和 自动高度 */
  grid-template-rows: 100px auto;
  
  /* 使用repeat()函数 */
  grid-template-columns: repeat(4, 1fr); /* 4等分列 */
  grid-template-columns: repeat(3, 100px 200px); /* 100px 200px 重复3次 */
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); /* 自动适应 */
}

单位说明:

  • fr:剩余空间分配单位
  • min-content:最小内容宽度
  • max-content:最大内容宽度
  • minmax(min, max):定义大小范围
  • auto:自动计算

网格区域模板:grid-template-areas

.grid-container {
  grid-template-areas:
    "header header header"
    "sidebar main aside"
    "footer footer footer";
}

.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }

间隙控制:gap

.grid-container {
  gap: 20px;           /* 行列间隙都是20px */
  gap: 10px 20px;      /* 行间隙10px,列间隙20px */
  row-gap: 10px;       /* 只设置行间隙 */
  column-gap: 20px;    /* 只设置列间隙 */
}

自动放置:grid-auto-flow

控制自动布局算法如何工作

.grid-container {
  grid-auto-flow: row;        /* 默认:按行填充 */
  grid-auto-flow: column;     /* 按列填充 */
  grid-auto-flow: dense;      /* 密集填充,尝试填充空白 */
}

隐式轨道大小:grid-auto-columns / grid-auto-rows

定义超出明确网格范围的轨道大小

.grid-container {
  grid-auto-rows: 100px;     /* 隐式行高度为100px */
  grid-auto-columns: minmax(100px, auto);
}

对齐方式

.grid-container {
  /* 项目在网格单元格内的对齐 */
  justify-items: stretch;    /* 水平对齐:start | center | end | stretch */
  align-items: stretch;      /* 垂直对齐:start | center | end | stretch */
  place-items: center;       /* 简写:align-items justify-items */

  /* 整个网格内容在容器内的对齐 */
  justify-content: space-between; /* 水平对齐 */
  align-content: space-around;    /* 垂直对齐 */
  place-content: center;          /* 简写:align-content justify-content */
}

网格项目属性详解

项目位置控制

.grid-item {
  /* 通过线号定位 */
  grid-column-start: 1;     /* 开始于第1条列线 */
  grid-column-end: 3;       /* 结束于第3条列线 */
  grid-row-start: 2;        /* 开始于第2条行线 */
  grid-row-end: 4;          /* 结束于第4条行线 */
  
  /* 简写 */
  grid-column: 1 / 3;       /* 等价于 grid-column-start: 1; grid-column-end: 3; */
  grid-row: 2 / 4;          /* 等价于 grid-row-start: 2; grid-row-end: 4; */
  
  /* 跨越多行/列 */
  grid-column: span 2;      /* 跨越2列 */
  grid-row: span 3;         /* 跨越3行 */
}

网格区域定位:grid-area

.grid-item {
  grid-area: 2 / 1 / 4 / 3; /* row-start / column-start / row-end / column-end */
}

项目自对齐

.grid-item {
  justify-self: center;    /* 单元格内水平对齐:start | center | end | stretch */
  align-self: center;      /* 单元格内垂直对齐:start | center | end | stretch */
  place-self: center;      /* 简写:align-self justify-self */
}

实用布局模式

经典12列网格系统

.grid-container {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 20px;
}

.col-1 { grid-column: span 1; }
.col-2 { grid-column: span 2; }
.col-3 { grid-column: span 3; }
/* ... 一直到 col-12 */
.col-12 { grid-column: span 12; }

/* 响应式调整 */
@media (max-width: 768px) {
  .col-1, .col-2, .col-3, .col-4, .col-6 {
    grid-column: span 12;
  }
}

圣杯布局 (Holy Grail Layout)

.layout {
  display: grid;
  grid-template-areas:
    "header header header"
    "sidebar main aside"
    "footer footer footer";
  grid-template-columns: 200px 1fr 300px;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
}

header { grid-area: header; }
aside { grid-area: aside; }
main { grid-area: main; }
nav { grid-area: sidebar; }
footer { grid-area: footer; }

/* 移动端适配 */
@media (max-width: 768px) {
  .layout {
    grid-template-areas:
      "header"
      "sidebar"
      "main"
      "aside"
      "footer";
    grid-template-columns: 1fr;
  }
}

瀑布流布局 (Masonry)

.masonry {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  grid-auto-rows: 50px; /* 基础行高 */
  gap: 15px;
}

.masonry-item {
  /* 通过调整行跨度创建错落效果 */
  grid-row: span 3; /* 默认跨度 */
}

.masonry-item:nth-child(2n) {
  grid-row: span 4;
}

.masonry-item:nth-child(3n) {
  grid-row: span 2;
}

仪表盘布局

.dashboard {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  grid-auto-rows: 200px;
  gap: 20px;
  padding: 20px;
}

.widget {
  background: white;
  border-radius: 8px;
  padding: 20px;
  box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}

.widget-large {
  grid-column: span 2;
  grid-row: span 2;
}

.widget-wide {
  grid-column: span 2;
}

图片画廊

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 10px;
}

.gallery-item {
  aspect-ratio: 4/3; /* 保持宽高比 */
  overflow: hidden;
}

.gallery-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.3s ease;
}

.gallery-item:hover img {
  transform: scale(1.05);
}

高级技巧

命名网格线

.grid-container {
  grid-template-columns: 
    [sidebar-start] 200px 
    [sidebar-end main-start] 1fr 
    [main-end aside-start] 300px [aside-end];
}

.sidebar {
  grid-column: sidebar-start / sidebar-end;
}

使用minmax()实现响应式

.grid-container {
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}

使用fit-content()

.grid-container {
  grid-template-columns: fit-content(200px) 1fr fit-content(300px);
}

子网格 (Subgrid) – 实验性功能

.grid-item {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: span 2;
}

浏览器兼容性

支持情况

  • 现代浏览器:完全支持
  • IE 10/11:部分支持(老语法)
  • 移动端:良好支持

前缀处理

对于需要兼容旧浏览器的情况:

.grid-container {
  display: -ms-grid; /* IE 10/11 */
  -ms-grid-columns: 200px 1fr 300px;
  display: grid;
  grid-template-columns: 200px 1fr 300px;
}

特性检测

@supports (display: grid) {
  .grid-container {
    display: grid;
  }
}

@supports not (display: grid) {
  /* 降级方案 */
  .grid-container {
    display: flex;
    flex-wrap: wrap;
  }
}

最佳实践

移动优先

/* 移动端:单列 */
.layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
}

/* 平板:2列 */
@media (min-width: 768px) {
  .layout {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* 桌面端:3列 */
@media (min-width: 1024px) {
  .layout {
    grid-template-columns: repeat(3, 1fr);
  }
}

使用CSS变量

:root {
  --grid-gap: 20px;
  --sidebar-width: 250px;
  --main-width: 1fr;
}

.layout {
  grid-template-columns: var(--sidebar-width) var(--main-width);
  gap: var(--grid-gap);
}

性能考虑

  • 避免过度嵌套网格
  • 使用明确的轨道大小而不是完全依赖自动布局
  • 对于大量网格项目,考虑虚拟滚动

Grid vs Flexbox

特性 Grid Flexbox
维度 二维(行和列) 一维(行或列)
布局方式 同时定义行和列 一次只处理一个方向
适用场景 整体页面布局 组件内部布局
内容影响 更适合显式布局 更依赖内容大小

选择建议:

  • 使用Grid进行宏观布局(页面结构)
  • 使用Flexbox进行微观布局(组件内部)
  • 两者可以嵌套使用

实用代码片段

居中元素

.centered {
  display: grid;
  place-items: center; /* 水平和垂直居中 */
  height: 100vh;
}

表单布局

.form {
  display: grid;
  grid-template-columns: [labels] auto [controls] 1fr;
  gap: 10px;
}

.form label {
  grid-column: labels;
  align-self: center;
}

.form input,
.form select {
  grid-column: controls;
}

响应式布局策略

响应式网页设计是现代前端开发的核心技能,它让网站能够自动适应不同设备的屏幕尺寸,提供最佳的用户体验。

媒体查询 (Media Queries)

媒体查询是响应式设计的核心技术,允许根据设备特性应用不同的CSS样式。

基本语法结构

@media 媒体类型 and (媒体特性) {
  /* 满足条件时应用的CSS规则 */
}

媒体类型

  • all- 所有设备(默认)
  • screen- 屏幕设备
  • print- 打印设备
  • speech- 屏幕阅读器

常用媒体特性

特性 描述 示例
width, min-width, max-width 视口宽度 (min-width: 768px)
height, min-height, max-height 视口高度 (max-height: 600px)
orientation 设备方向 (orientation: portrait)
resolution 屏幕分辨率 (min-resolution: 2dppx)
aspect-ratio 宽高比 (aspect-ratio: 16/9)

移动优先策略 (Mobile First)

核心思想:先为移动设备设计基础样式,然后逐步为更大屏幕增强体验。

/* === 移动端基础样式(默认)=== */
.container {
  width: 100%;
  padding: 15px;
}

.menu {
  display: none; /* 移动端隐藏菜单 */
}

.hamburger {
  display: block; /* 显示汉堡菜单 */
}

/* === 平板设备(768px及以上)=== */
@media (min-width: 768px) {
  .container {
    width: 750px;
    margin: 0 auto;
    padding: 20px;
  }
  
  .hamburger {
    display: none; /* 隐藏汉堡菜单 */
  }
  
  .menu {
    display: flex; /* 显示水平菜单 */
  }
}

/* === 桌面设备(1024px及以上)=== */
@media (min-width: 1024px) {
  .container {
    width: 980px;
    padding: 30px;
  }
  
  .main-content {
    display: grid;
    grid-template-columns: 250px 1fr;
    gap: 30px;
  }
}

/* === 大桌面设备(1200px及以上)=== */
@media (min-width: 1200px) {
  .container {
    width: 1140px;
  }
}

常用断点设置

/* 超小设备 (手机, 小于576px) - 默认样式 */

/* 小设备 (平板, 576px及以上) */
@media (min-width: 576px) { ... }

/* 中等设备 (小桌面, 768px及以上) */
@media (min-width: 768px) { ... }

/* 大设备 (桌面, 992px及以上) */
@media (min-width: 992px) { ... }

/* 超大设备 (大桌面, 1200px及以上) */
@media (min-width: 1200px) { ... }

复杂媒体查询

/* 多个条件组合 */
@media screen and (min-width: 768px) and (max-width: 1023px) and (orientation: landscape) {
  /* 平板横屏样式 */
}

/* 多个查询条件 */
@media (min-width: 768px), (orientation: portrait) {
  /* 满足任一条件时应用 */
}

弹性单位 (Fluid Units)

使用相对单位代替固定像素值,实现元素的流体缩放。

百分比 (%) – 相对于父元素

.container {
  width: 90%; /* 父元素宽度的90% */
  max-width: 1200px;
}

.column {
  width: 50%; /* 父元素宽度的一半 */
}

.image {
  max-width: 100%; /* 不超过父元素宽度 */
  height: auto; /* 保持宽高比 */
}

视口单位 (vw, vh, vmin, vmax) – 相对于视口尺寸

.hero-section {
  height: 100vh; /* 整个视口高度 */
  width: 100vw;  /* 整个视口宽度 */
}

.title {
  font-size: 5vw; /* 字体大小为视口宽度的5% */
}

.sidebar {
  width: 300px;
  max-width: 80vw; /* 最大为视口宽度的80% */
}

/* 保持元素宽高比 */
.aspect-ratio-box {
  width: 100%;
  height: 0;
  padding-bottom: 56.25%; /* 16:9 比例 (9/16 = 0.5625) */
  position: relative;
}

.aspect-ratio-box > * {
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
}

字体相对单位 (rem, em) – 响应式排版

/* 根元素字体设置 */
:root {
  font-size: 16px; /* 基准大小 */
}

@media (min-width: 768px) {
  :root {
    font-size: 18px; /* 大屏幕增加字体大小 */
  }
}

@media (min-width: 1200px) {
  :root {
    font-size: 20px;
  }
}

/* 使用rem - 相对于根元素 */
h1 {
  font-size: 2.5rem; /* 40px (基于16px基准) */
  margin-bottom: 1.5rem; /* 24px */
}

p {
  font-size: 1rem;
  line-height: 1.6;
}

/* 使用em - 相对于父元素 */
.card {
  padding: 1.5em; /* 相对于父元素的字体大小 */
  margin-bottom: 1em;
}

.button {
  font-size: 1.2em;
  padding: 0.8em 1.5em;
}

现代CSS函数

.container {
  /* clamp(最小值, 理想值, 最大值) */
  width: clamp(300px, 80%, 1200px);
  font-size: clamp(16px, 2.5vw, 24px);
  padding: clamp(15px, 5%, 50px);
}

/* min() 和 max() 函数 */
.sidebar {
  width: min(300px, 100%); /* 取较小值 */
  height: max(100vh, 600px); /* 取较大值 */
}

现代布局技术的响应式应用

Flexbox 响应式布局

/* 基础移动样式 */
.card-container {
  display: flex;
  flex-direction: column; /* 移动端垂直排列 */
  gap: 20px;
}

.card {
  flex: 1;
  min-width: 0; /* 防止内容溢出 */
}

/* 平板及以上水平排列 */
@media (min-width: 768px) {
  .card-container {
    flex-direction: row;
    flex-wrap: wrap; /* 允许换行 */
  }
  
  .card {
    flex: 0 0 calc(50% - 20px); /* 两列布局 */
  }
}

/* 桌面端三列布局 */
@media (min-width: 1024px) {
  .card {
    flex: 0 0 calc(33.333% - 20px); /* 三列布局 */
  }
}

/* 导航栏响应式示例 */
.nav {
  display: flex;
  flex-direction: column; /* 移动端垂直 */
  gap: 10px;
}

@media (min-width: 768px) {
  .nav {
    flex-direction: row; /* 大屏水平 */
    justify-content: space-between;
  }
  
  .nav-item:last-child {
    margin-left: auto; /* 最后一个项目向右推 */
  }
}

Grid 响应式布局

/* 自动适应网格 */
.grid-container {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 20px;
  padding: 20px;
}

/* 明确网格布局 */
.layout {
  display: grid;
  grid-template-columns: 1fr; /* 移动端单列 */
  gap: 20px;
}

/* 平板:两列布局 */
@media (min-width: 768px) {
  .layout {
    grid-template-columns: 200px 1fr;
    grid-template-areas:
      "header header"
      "sidebar main"
      "footer footer";
  }
}

/* 桌面:三列布局 */
@media (min-width: 1024px) {
  .layout {
    grid-template-columns: 250px 1fr 200px;
    grid-template-areas:
      "header header header"
      "sidebar main aside"
      "footer footer footer";
  }
}

/* 网格区域分配 */
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }

/* 图片画廊响应式 */
.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 10px;
}

@media (min-width: 768px) {
  .gallery {
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  }
}

实用响应式模式

/* 响应式网格系统 */
:root {
  --grid-columns: 4;
  --grid-gap: 20px;
}

.grid {
  display: grid;
  grid-template-columns: repeat(var(--grid-columns), 1fr);
  gap: var(--grid-gap);
}

@media (min-width: 768px) {
  :root {
    --grid-columns: 8;
  }
}

@media (min-width: 1024px) {
  :root {
    --grid-columns: 12;
  }
}

/* 列跨度工具类 */
.col-1 { grid-column: span 1; }
.col-2 { grid-column: span 2; }
/* ... 更多列类 */

@media (max-width: 767px) {
  [class*="col-"] {
    grid-column: span var(--grid-columns);
  }
}

响应式设计最佳实践

移动优先工作流

  • 先设计移动端体验
  • 逐步增强到大屏幕
  • 测试各种设备尺寸

性能优化

/* 响应式图片 */
img {
  max-width: 100%;
  height: auto;
}

/* 艺术指导 - 不同尺寸使用不同图片 */
.hero {
  background-image: url('small.jpg');
}

@media (min-width: 768px) {
  .hero {
    background-image: url('medium.jpg');
  }
}

@media (min-width: 1200px) {
  .hero {
    background-image: url('large.jpg');
  }
}

/* 使用picture元素 */
<picture>
  <source media="(min-width: 1024px)" srcset="large.jpg">
  <source media="(min-width: 768px)" srcset="medium.jpg">
  <img src="small.jpg" alt="描述文本">
</picture>

响应式排版

:root {
  --text-base-size: 1rem;
  --text-scale-ratio: 1.2;
}

h1 {
  font-size: calc(var(--text-base-size) * var(--text-scale-ratio) * 3);
}

@media (min-width: 768px) {
  :root {
    --text-base-size: 1.1rem;
  }
}

@media (min-width: 1200px) {
  :root {
    --text-base-size: 1.2rem;
  }
}

实用工具类

/* 显示/隐藏工具类 */
.hide-mobile { display: none; }
.show-desktop { display: none; }

@media (max-width: 767px) {
  .hide-mobile { display: none !important; }
  .show-mobile { display: block !important; }
}

@media (min-width: 768px) {
  .hide-desktop { display: none !important; }
  .show-desktop { display: block !important; }
}

/* 间距工具类 */
:root {
  --spacing-unit: 0.5rem;
}

@media (min-width: 768px) {
  :root {
    --spacing-unit: 1rem;
  }
}

.p-1 { padding: var(--spacing-unit); }
.p-2 { padding: calc(var(--spacing-unit) * 2); }

CSS 视觉效果与动画

现代CSS提供了强大的视觉效果和动画能力,可以让网页变得生动而富有吸引力。下面我将详细讲解过渡、变换、动画以及各种视觉效果。

变换 (Transform) – 元素的变形艺术

变换允许你对元素进行旋转、缩放、移动和倾斜等几何变换。

移动变换 (Translate)

.element {
  transform: translateX(50px);    /* 水平移动 */
  transform: translateY(-20px);   /* 垂直移动 */
  transform: translate(50px, -20px); /* 同时设置X和Y */
  
  /* 百分比相对于元素自身尺寸 */
  transform: translate(50%, 50%); /* 向右移动自身宽度50%,向下移动自身高度50% */
}

缩放变换 (Scale)

.element {
  transform: scale(1.5);         /* 等比例放大1.5倍 */
  transform: scaleX(2);          /* 水平方向放大2倍 */
  transform: scaleY(0.5);        /* 垂直方向缩小到0.5倍 */
  transform: scale(1.2, 0.8);    /* 水平1.2倍,垂直0.8倍 */
}

旋转变换 (Rotate)

.element {
  transform: rotate(45deg);      /* 顺时针旋转45度 */
  transform: rotate(-90deg);     /* 逆时针旋转90度 */
  transform: rotate(1turn);      /* 旋转一圈(360度) */
  transform: rotate(0.25turn);    /* 旋转90度 */
}

倾斜变换 (Skew)

.element {
  transform: skewX(30deg);       /* 水平方向倾斜30度 */
  transform: skewY(15deg);        /* 垂直方向倾斜15度 */
  transform: skew(30deg, 15deg); /* 同时设置X和Y */
}

变换原点 (Transform Origin)

控制变换的基准点

.element {
  transform-origin: center;      /* 默认:中心点 */
  transform-origin: top left;    /* 左上角 */
  transform-origin: 50px 50px;   /* 具体坐标 */
  transform-origin: 0 0;         /* 左上角 */
}

多重变换

.element {
  transform: translateX(50px) rotate(45deg) scale(1.2);
  /* 注意:变换顺序很重要! */
}

3D变换

.container {
  perspective: 1000px; /* 启用3D透视 */
}

.element {
  transform: rotateX(45deg);     /* 绕X轴旋转 */
  transform: rotateY(30deg);     /* 绕Y轴旋转 */
  transform: rotateZ(15deg);     /* 绕Z轴旋转 */
  transform: rotate3d(1, 1, 0, 45deg); /* 自定义轴旋转 */
  
  transform: translateZ(100px); /* Z轴移动 */
  transform: translate3d(50px, 30px, 20px);
  
  transform-style: preserve-3d;  /* 保持3D空间 */
  backface-visibility: hidden;   /* 背面不可见 */
}

过渡 (Transition) – 平滑的状态变化

过渡为元素的状态变化添加平滑的动画效果。

基本语法

.element {
  transition-property: transform;      /* 要过渡的属性 */
  transition-duration: 0.3s;          /* 过渡持续时间 */
  transition-timing-function: ease;    /* 时间函数(速度曲线) */
  transition-delay: 0.1s;              /* 延迟时间 */
  
  /* 简写形式 */
  transition: transform 0.3s ease 0.1s;
}

过渡属性

.element {
  /* 多个属性分别设置 */
  transition: opacity 0.3s, transform 0.5s;
  
  /* 所有可动画属性 */
  transition: all 0.3s ease;
  
  /* 具体属性 */
  transition: background-color 0.3s, color 0.2s;
}

时间函数 (Timing Functions)

控制动画的速度曲线

.element {
  /* 关键字 */
  transition-timing-function: ease;        /* 默认:慢-快-慢 */
  transition-timing-function: ease-in;     /* 慢开始 */
  transition-timing-function: ease-out;    /* 慢结束 */
  transition-timing-function: ease-in-out; /* 慢开始和结束 */
  transition-timing-function: linear;       /* 匀速 */
  
  /* 贝塞尔曲线 */
  transition-timing-function: cubic-bezier(0.1, 0.7, 1.0, 0.1);
  
  /* 步进函数 */
  transition-timing-function: steps(4, jump-end);
}

实用过渡示例

/* 按钮悬停效果 */
.btn {
  background-color: #007bff;
  color: white;
  padding: 10px 20px;
  border: none;
  transition: all 0.3s ease;
}

.btn:hover {
  background-color: #0056b3;
  transform: translateY(-2px);
  box-shadow: 0 5px 15px rgba(0,0,0,0.2);
}

/* 淡入淡出 */
.fade-element {
  opacity: 0;
  transition: opacity 0.5s ease;
}

.fade-element.show {
  opacity: 1;
}

/* 折叠面板 */
.accordion-content {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s ease;
}

.accordion-content.open {
  max-height: 500px;
}

动画 (Animation) – 复杂的自定义动画

使用 @keyframes创建复杂的自定义动画序列。

关键帧定义

@keyframes slideIn {
  from {
    transform: translateX(-100%);
    opacity: 0;
  }
  
  to {
    transform: translateX(0);
    opacity: 1;
  }
}

/* 使用百分比定义多阶段动画 */
@keyframes bounce {
  0% {
    transform: translateY(0);
  }
  
  50% {
    transform: translateY(-30px);
  }
  
  100% {
    transform: translateY(0);
  }
}

动画属性

.element {
  animation-name: slideIn;           /* 动画名称 */
  animation-duration: 0.5s;          /* 动画时长 */
  animation-timing-function: ease;   /* 时间函数 */
  animation-delay: 0.2s;             /* 延迟时间 */
  animation-iteration-count: 3;      /* 播放次数:数字或infinite */
  animation-direction: normal;       /* 方向:normal, reverse, alternate, alternate-reverse */
  animation-fill-mode: none;         /* 填充模式:none, forwards, backwards, both */
  animation-play-state: running;     /* 播放状态:running, paused */
  
  /* 简写形式 */
  animation: slideIn 0.5s ease 0.2s 3 alternate both;
}

动画填充模式 (Fill Mode)

.element {
  animation-fill-mode: none;       /* 默认:动画前后不应用样式 */
  animation-fill-mode: forwards;    /* 动画结束后保持最后一帧样式 */
  animation-fill-mode: backwards;  /* 动画延迟期间应用第一帧样式 */
  animation-fill-mode: both;        /* 同时应用forwards和backwards */
}

实用动画示例

/* 加载动画 */
@keyframes spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

.loader {
  animation: spin 1s linear infinite;
}

/* 脉动效果 */
@keyframes pulse {
  0% { transform: scale(1); }
  50% { transform: scale(1.05); }
  100% { transform: scale(1); }
}

.pulse {
  animation: pulse 2s ease-in-out infinite;
}

/* 打字机效果 */
@keyframes typing {
  from { width: 0; }
  to { width: 100%; }
}

.typewriter {
  overflow: hidden;
  white-space: nowrap;
  animation: typing 3s steps(40, end);
}

/* 复杂组合动画 */
@keyframes complexAnimation {
  0% {
    transform: translateY(50px) rotate(0deg);
    opacity: 0;
  }
  50% {
    transform: translateY(-20px) rotate(180deg);
    opacity: 0.8;
  }
  100% {
    transform: translateY(0) rotate(360deg);
    opacity: 1;
  }
}

视觉效果 – 提升页面质感

渐变 (Gradients)

.element {
  /* 线性渐变 */
  background: linear-gradient(to right, #ff7e5f, #feb47b);
  background: linear-gradient(45deg, #ff7e5f, #feb47b, #86a8e7);
  
  /* 径向渐变 */
  background: radial-gradient(circle, #ff7e5f, #feb47b);
  
  /* 重复渐变 */
  background: repeating-linear-gradient(
    45deg,
    #ff7e5f,
    #ff7e5f 10px,
    #feb47b 10px,
    #feb47b 20px
  );
  
  /* 渐变文字 */
  background: linear-gradient(45deg, #ff7e5f, #feb47b);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

阴影 (Shadows)

.element {
  /* 盒子阴影:offset-x offset-y blur-radius spread-radius color */
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1), 0 6px 6px rgba(0, 0, 0, 0.1); /* 多重阴影 */
  
  /* 内阴影 */
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
  
  /* 文字阴影 */
  text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5), 
               0 4px 8px rgba(0, 0, 0, 0.3); /* 多重文字阴影 */
}

滤镜 (Filters)

.element {
  /* 模糊 */
  filter: blur(5px);
  
  /* 亮度 */
  filter: brightness(1.5);  /* 变亮 */
  filter: brightness(0.5);  /* 变暗 */
  
  /* 对比度 */
  filter: contrast(200%);
  
  /* 灰度 */
  filter: grayscale(100%); /* 完全灰度 */
  filter: grayscale(50%);  /* 部分灰度 */
  
  /* 色相旋转 */
  filter: hue-rotate(90deg);
  
  /* 反转颜色 */
  filter: invert(100%);
  
  /* 不透明度 */
  filter: opacity(50%);
  
  /* 饱和度 */
  filter: saturate(200%);
  filter: saturate(50%);
  
  /* 棕褐色调 */
  filter: sepia(100%);
  
  /* 多重滤镜 */
  filter: brightness(1.2) contrast(0.8) saturate(1.1);
  
  /* 背景模糊(需要backdrop-filter支持) */
  backdrop-filter: blur(10px);
}

混合模式 (Blend Modes)

.element {
  /* 背景混合模式 */
  background-blend-mode: multiply;
  
  /* 元素混合模式 */
  mix-blend-mode: screen;
  
  /* 常用混合模式 */
  mix-blend-mode: normal;      /* 正常 */
  mix-blend-mode: multiply;    /* 正片叠底 */
  mix-blend-mode: screen;      /* 屏幕 */
  mix-blend-mode: overlay;     /* 叠加 */
  mix-blend-mode: darken;      /* 变暗 */
  mix-blend-mode: lighten;     /* 变亮 */
  mix-blend-mode: color-dodge; /* 颜色减淡 */
  mix-blend-mode: color-burn;  /* 颜色加深 */
}

综合应用示例

高级卡片效果

.card {
  background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
  border-radius: 12px;
  padding: 24px;
  box-shadow: 
    0 10px 30px rgba(0, 0, 0, 0.1),
    0 1px 8px rgba(0, 0, 0, 0.05);
  transition: all 0.3s ease;
  transform: translateY(0);
}

.card:hover {
  transform: translateY(-8px) scale(1.02);
  box-shadow: 
    0 20px 40px rgba(0, 0, 0, 0.15),
    0 3px 12px rgba(0, 0, 0, 0.08);
}

.card:active {
  transform: translateY(-4px) scale(1.01);
}

毛玻璃效果

.glass-effect {
  background: rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.2);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}

/* 兼容性回退 */
@supports not (backdrop-filter: blur(10px)) {
  .glass-effect {
    background: rgba(255, 255, 255, 0.9);
  }
}

加载动画集合

/* 旋转加载 */
.spinner {
  width: 40px;
  height: 40px;
  border: 4px solid #f3f3f3;
  border-top: 4px solid #007bff;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

/* 脉冲加载 */
.pulse-loader {
  width: 20px;
  height: 20px;
  background: #007bff;
  border-radius: 50%;
  animation: pulse 1.5s ease-in-out infinite;
}

/* 波浪加载 */
.wave-loader {
  display: flex;
  gap: 4px;
}

.wave-loader div {
  width: 6px;
  height: 20px;
  background: #007bff;
  animation: wave 1.2s ease-in-out infinite;
}

.wave-loader div:nth-child(2) { animation-delay: -0.2s; }
.wave-loader div:nth-child(3) { animation-delay: -0.4s; }

@keyframes wave {
  0%, 100% { transform: scaleY(1); }
  50% { transform: scaleY(1.8); }
}

性能优化与最佳实践

性能考虑

/* 优先使用transform和opacity进行动画 */
.good-performance {
  transform: translateX(100px);
  opacity: 0.5;
}

/* 避免动画这些属性(性能开销大) */
.bad-performance {
  margin-left: 100px;    /* 触发重排 */
  width: 500px;         /* 触发重排 */
  height: 300px;        /* 触发重排 */
}

硬件加速

.accelerated {
  transform: translateZ(0); /* 触发GPU加速 */
  will-change: transform;    /* 预先告知浏览器 */
}

响应式动画

@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

浏览器兼容性

.element {
  /* 提供回退方案 */
  opacity: 0.8;
  
  /* 现代浏览器支持 */
  @supports (backdrop-filter: blur(10px)) {
    backdrop-filter: blur(10px);
    background: rgba(255, 255, 255, 0.1);
  }
}

实用工具类

/* 动画工具类 */
.fade-in {
  animation: fadeIn 0.5s ease;
}

.slide-in-left {
  animation: slideInLeft 0.5s ease;
}

.slide-in-right {
  animation: slideInRight 0.5s ease;
}

.bounce-in {
  animation: bounceIn 0.6s ease;
}

/* 悬停效果工具类 */
.hover-lift {
  transition: transform 0.3s ease;
}

.hover-lift:hover {
  transform: translateY(-4px);
}

.hover-glow {
  transition: box-shadow 0.3s ease;
}

.hover-glow:hover {
  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
}

/* 滤镜工具类 */
.grayscale {
  filter: grayscale(100%);
  transition: filter 0.3s ease;
}

.grayscale:hover {
  filter: grayscale(0%);
}

CSS工程化与维护

CSS BEM 方法论

BEM(Block, Element, Modifier)是一种非常流行的CSS命名方法论,它通过严格的命名约定来解决CSS中的可维护性和可扩展性问题。

为什么需要CSS方法论?

在大型项目中,CSS很容易变得难以维护,常见问题包括:

  • 命名冲突:不同组件的相同类名相互影响
  • 特异性战争:不断使用更具体的选择器来覆盖样式
  • 难以理解:无法从类名看出元素的作用和关系
  • 难以复用:样式紧密耦合,无法轻松提取组件

BEM通过严格的命名规则解决了这些问题。

BEM的核心概念

Block(块)

  • 独立的、可复用的组件或模块
  • 代表页面上的功能独立的部分
  • 名称应该描述其用途而不是外观
/* 块 */
.header { /* 样式 */ }
.menu { /* 样式 */ }
.search-form { /* 样式 */ }

Element(元素)

  • 块的组成部分,不能独立于块存在
  • 名称描述其在块中的用途
  • 使用双下划线 __连接块和元素
/* 元素 */
.menu__item { /* 样式 */ }
.menu__link { /* 样式 */ }
.search-form__input { /* 样式 */ }
.search-form__button { /* 样式 */ }

Modifier(修饰符)

  • 定义块或元素的外观、状态或行为的变化
  • 使用双连字符 –连接
  • 可以应用于块或元素
/* 修饰符 */
.menu--dark { /* 深色变体 */ }
.menu__item--active { /* 激活状态 */ }
.button--large { /* 大尺寸 */ }
.button--disabled { /* 禁用状态 */ }

BEM命名语法规则

基本命名模式

block__element–modifier

命名规范

  • 只使用小写字母
  • 单词用连字符分隔:search-form而不是 searchForm或 search_form
  • 元素用双下划线:block__element
  • 修饰符用双连字符:block–modifier或 block__element–modifier

HTML结构示例

<!-- 块 -->
<header class="header">
  
  <!-- 元素 -->
  <nav class="header__nav">
    <ul class="header__menu">
      <!-- 元素 + 修饰符 -->
      <li class="header__item header__item--active">
        <a class="header__link" href="#">首页</a>
      </li>
      <li class="header__item">
        <a class="header__link" href="#">关于</a>
      </li>
    </ul>
  </nav>
  
  <!-- 搜索表单块 -->
  <form class="search-form search-form--compact">
    <input class="search-form__input" type="text">
    <!-- 元素 + 修饰符 -->
    <button class="search-form__button search-form__button--primary">
      搜索
    </button>
  </form>

</header>

实际项目示例

按钮组件

/* 块 - 基础按钮 */
.button {
  display: inline-block;
  padding: 12px 24px;
  border: none;
  border-radius: 4px;
  font-size: 16px;
  cursor: pointer;
  transition: all 0.3s ease;
}

/* 元素 - 按钮内的图标 */
.button__icon {
  margin-right: 8px;
  vertical-align: middle;
}

/* 修饰符 - 按钮变体 */
.button--primary {
  background-color: #007bff;
  color: white;
}

.button--primary:hover {
  background-color: #0056b3;
}

.button--secondary {
  background-color: #6c757d;
  color: white;
}

.button--large {
  padding: 16px 32px;
  font-size: 18px;
}

.button--disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

/* 修饰符 - 图标位置 */
.button__icon--right {
  margin-right: 0;
  margin-left: 8px;
}

<button class="button button--primary button--large">
  <span class="button__icon">✓</span>
  主要按钮
</button>

<button class="button button--secondary" disabled>
  次要按钮
</button>

<button class="button button--primary">
  图标在右
  <span class="button__icon button__icon--right">→</span>
</button>

卡片组件

/* 块 - 基础卡片 */
.card {
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  overflow: hidden;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

/* 元素 - 卡片各部分 */
.card__image {
  width: 100%;
  height: 200px;
  object-fit: cover;
}

.card__content {
  padding: 20px;
}

.card__title {
  margin: 0 0 12px 0;
  font-size: 20px;
  color: #333;
}

.card__description {
  margin: 0 0 20px 0;
  color: #666;
  line-height: 1.6;
}

.card__footer {
  padding: 16px 20px;
  background: #f8f9fa;
  border-top: 1px solid #e9ecef;
}

/* 修饰符 - 卡片变体 */
.card--hoverable:hover {
  transform: translateY(-4px);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
}

.card--bordered {
  border: 1px solid #e9ecef;
  box-shadow: none;
}

.card--small .card__content {
  padding: 16px;
}

.card--small .card__title {
  font-size: 16px;
}

<div class="card card--hoverable">
  <img class="card__image" src="image.jpg" alt="示例图片">
  <div class="card__content">
    <h3 class="card__title">卡片标题</h3>
    <p class="card__description">这是一个卡片的描述内容,可以包含多行文本。</p>
  </div>
  <div class="card__footer">
    <button class="button button--primary">操作按钮</button>
  </div>
</div>

<div class="card card--bordered card--small">
  <div class="card__content">
    <h3 class="card__title">小卡片</h3>
    <p class="card__description">这是一个小型卡片的示例。</p>
  </div>
</div>

BEM的优势

清晰的代码结构

/* 传统CSS - 难以理解关系 */
.header nav ul li a { /* 样式 */ }
.header .nav-item.active { /* 样式 */ }

/* BEM - 结构清晰 */
.header__link { /* 样式 */ }
.header__item--active { /* 样式 */ }

避免特异性冲突

/* 传统CSS - 特异性战争 */
.header .nav .item .link { /* 特异性: 0,0,4,0 */ }
.header .nav .item .link.active { /* 特异性: 0,0,5,0 */ }

/* BEM - 统一特异性 */
.header__link { /* 特异性: 0,0,1,0 */ }
.header__link--active { /* 特异性: 0,0,1,0 */ }

可复用性和模块化

/* 可以在任何地方使用,不会冲突 */
.button { /* 基础按钮样式 */ }
.menu__button { /* 菜单内的按钮 */ }

/* 而不是 */
.menu .button { /* 依赖上下文 */ }

易于维护和扩展

/* 添加新变体很容易 */
.button--new-variant {
  /* 新样式 */
}

/* 而不是创建新的选择器链 */
.special-section .special-button {
  /* 导致特异性增加 */
}

BEM的最佳实践

避免嵌套过深

/* 不推荐 - 嵌套过深 */
.block__element1__element2__element3 { }

/* 推荐 - 扁平结构 */
.block__element1 { }
.block__element2 { }
.block__element3 { }

不要使用元素选择器

/* 不推荐 - 过于泛化 */
.block div { }
.block > span { }

/* 推荐 - 明确指定 */
.block__container { }
.block__label { }

修饰符独立使用

/* 不推荐 - 修饰符依赖基础类 */
.block--modifier .block__element { }

/* 推荐 - 修饰符独立 */
.block--modifier { }
.block__element--modifier { }

使用预处理器的好处

/* SCSS中的BEM */
.block {
  &__element {
    /* 元素样式 */
    
    &--modifier {
      /* 修饰符样式 */
    }
  }
  
  &--modifier {
    /* 块修饰符 */
  }
}

BEM与其他方法的结合

BEM + SMACSS(可扩展和模块化CSS)

/* SMACSS类别 + BEM命名 */

/* Layout规则 */
.l-header { /* 布局样式 */ }

/* Module规则 */
.menu { /* 模块基础 */ }
.menu__item { /* 模块元素 */ }

/* State规则 */
.is-active { /* 状态样式 */ }
.is-hidden { /* 状态样式 */ }

/* 在HTML中结合使用 */
<div class="menu menu--dark is-active">

BEM + Utility Classes(工具类)

/* BEM组件 */
.button { /* 基础样式 */ }
.button--primary { /* 变体样式 */ }

/* 工具类 */
.text-center { text-align: center; }
.mb-20 { margin-bottom: 20px; }

<!-- 结合使用 -->
<button class="button button--primary text-center mb-20">
  按钮
</button>

常见问题解答

BEM类名太长怎么办?

/* 保持简洁但描述性 */
/* 而不是缩写到难以理解 */
.nav__itm--act /* 不推荐 - 难以理解 */
.nav__item--active /* 推荐 - 清晰明确 */

如何处理多个修饰符?

<!-- 多个修饰符 -->
<button class="button button--primary button--large button--disabled">
  按钮
</button>

BEM是否适合所有项目?

  • 适合:中大型项目、团队合作、需要长期维护的项目
  • 可能过度:小型项目、个人项目、原型开发

如何迁移现有项目到BEM?

  • 逐步迁移:从新组件开始使用BEM
  • 创建规范:制定团队的BEM指南
  • 重构旧代码:有计划地重构重要组件
  • 使用工具:利用CSS预处理器和lint工具

工具和资源

CSS预处理器支持

// SCSS中的BEM混合宏
@mixin element($element) {
  &__#{$element} {
    @content;
  }
}

@mixin modifier($modifier) {
  &--#{$modifier} {
    @content;
  }
}

// 使用
.block {
  @include element('element') {
    // 元素样式
  }
  
  @include modifier('modifier') {
    // 修饰符样式
  }
}

代码检查工具

  • stylelint:检查BEM命名规范
  • PostCSS:自动生成BEM类名
  • CSS Modules:结合BEM使用

命名约定生成器

在线工具如BEM命名生成器可以帮助创建正确的类名。

CSS 预处理器

CSS预处理器是前端开发中必不可少的工具,它们通过扩展CSS语法提供了变量、嵌套、混合等强大特性,极大提升了CSS的可维护性和开发效率。

为什么需要CSS预处理器?

原生CSS的局限性

/* 原生CSS的问题示例 */
.container {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
}

/* 重复的颜色值 */
.header { background-color: #007bff; }
.button { background-color: #007bff; }
.link { color: #007bff; }

/* 复杂的媒体查询 */
@media (min-width: 768px) {
  .container { padding: 20px; }
}
@media (min-width: 1024px) {
  .container { padding: 30px; }
}

/* 重复的浏览器前缀 */
.element {
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
  border-radius: 5px;
  -webkit-box-shadow: 0 2px 5px rgba(0,0,0,0.1);
  -moz-box-shadow: 0 2px 5px rgba(0,0,0,0.1);
  box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}

预处理器的解决方案

  • 变量:避免重复值,统一管理
  • 嵌套:清晰的结构关系
  • 混合:代码复用和抽象
  • 函数:动态计算和逻辑处理
  • 模块化:更好的代码组织

Sass/SCSS 详细介绍

两种语法格式

// SCSS语法(更流行,兼容CSS)
$primary-color: #007bff;

.container {
  width: 100%;
  max-width: 1200px;
  
  .header {
    background-color: $primary-color;
  }
}

// Sass语法(缩进格式,更简洁)
$primary-color: #007bff

.container
  width: 100%
  max-width: 1200px
  
  .header
    background-color: $primary-color

变量系统

// 基础变量
$primary-color: #007bff;
$secondary-color: #6c757d;
$font-family: 'Helvetica', 'Arial', sans-serif;
$base-spacing: 1rem;
$border-radius: 4px;

// 映射(Map)变量
$colors: (
  primary: #007bff,
  secondary: #6c757d,
  success: #28a745,
  danger: #dc3545,
  warning: #ffc107
);

$breakpoints: (
  sm: 576px,
  md: 768px,
  lg: 992px,
  xl: 1200px
);

// 使用变量
.button {
  background-color: $primary-color;
  font-family: $font-family;
  border-radius: $border-radius;
  
  // 使用map-get获取映射值
  &.button-success {
    background-color: map-get($colors, success);
  }
}

嵌套规则

// 选择器嵌套
.nav {
  background: #333;
  padding: 1rem;
  
  // 子元素嵌套
  > .nav-list {
    display: flex;
    list-style: none;
    
    // 伪类嵌套
    &:hover {
      background: #444;
    }
    
    // 媒体查询嵌套
    @media (max-width: 768px) {
      flex-direction: column;
    }
    
    // 兄弟选择器嵌套
    + .nav-toggle {
      display: none;
    }
  }
  
  .nav-item {
    margin-right: 1rem;
    
    .nav-link {
      color: white;
      text-decoration: none;
      
      &:hover {
        text-decoration: underline;
      }
    }
  }
}

// 编译后
.nav { background: #333; padding: 1rem; }
.nav > .nav-list { display: flex; list-style: none; }
.nav > .nav-list:hover { background: #444; }
@media (max-width: 768px) {
  .nav > .nav-list { flex-direction: column; }
}
.nav > .nav-list + .nav-toggle { display: none; }
.nav .nav-item { margin-right: 1rem; }
.nav .nav-item .nav-link { color: white; text-decoration: none; }
.nav .nav-item .nav-link:hover { text-decoration: underline; }

混合宏(Mixins)

// 基础混合宏
@mixin center-element {
  display: flex;
  justify-content: center;
  align-items: center;
}

// 带参数的混合宏
@mixin button-style($bg-color, $text-color: white) {
  background-color: $bg-color;
  color: $text-color;
  padding: 0.5rem 1rem;
  border: none;
  border-radius: $border-radius;
  cursor: pointer;
  transition: background-color 0.3s ease;
  
  &:hover {
    background-color: darken($bg-color, 10%);
  }
}

// 带内容块的混合宏
@mixin media-query($breakpoint) {
  @media (min-width: $breakpoint) {
    @content;
  }
}

// 使用混合宏
.container {
  @include center-element;
}

.primary-button {
  @include button-style($primary-color);
}

.secondary-button {
  @include button-style($secondary-color, #333);
}

// 使用带内容块的混合宏
.sidebar {
  width: 100%;
  
  @include media-query(map-get($breakpoints, md)) {
    width: 250px;
    position: fixed;
    left: 0;
    top: 0;
    height: 100vh;
  }
}

函数(Functions)

// 自定义函数
@function calculate-rem($px-value) {
  @return ($px-value / 16) * 1rem;
}

@function color-shade($color, $percentage) {
  @return mix(black, $color, $percentage);
}

@function get-breakpoint($key) {
  @return map-get($breakpoints, $key);
}

// 使用函数
body {
  font-size: calculate-rem(16px);
}

.dark-button {
  @include button-style(color-shade($primary-color, 20%));
}

@include media-query(get-breakpoint(lg)) {
  .container {
    max-width: 1140px;
  }
}

继承(Extend)

// 基础样式
%base-button {
  display: inline-block;
  padding: 0.5rem 1rem;
  border: none;
  border-radius: $border-radius;
  cursor: pointer;
  transition: all 0.3s ease;
}

// 使用继承
.primary-button {
  @extend %base-button;
  background-color: $primary-color;
  color: white;
}

.secondary-button {
  @extend %base-button;
  background-color: $secondary-color;
  color: #333;
}

// 编译后(合并相同样式)
.primary-button, .secondary-button {
  display: inline-block;
  padding: 0.5rem 1rem;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: all 0.3s ease;
}

.primary-button { background-color: #007bff; color: white; }
.secondary-button { background-color: #6c757d; color: #333; }

控制指令

// 条件语句
@mixin theme-colors($theme: light) {
  @if $theme == light {
    background-color: white;
    color: #333;
  } @else if $theme == dark {
    background-color: #333;
    color: white;
  } @else {
    @error "Unknown theme #{$theme}";
  }
}

// 循环语句
$sizes: (small: 0.5rem, medium: 1rem, large: 2rem);

@each $name, $size in $sizes {
  .padding-#{$name} {
    padding: $size;
  }
}

// For循环
@for $i from 1 through 12 {
  .col-#{$i} {
    width: percentage($i / 12);
  }
}

// While循环
$i: 1;
@while $i <= 5 {
  .mt-#{$i} { margin-top: #{$i * 0.25}rem; }
  $i: $i + 1;
}

模块化与导入

// _variables.scss(局部文件,不会被编译为单独CSS)
$primary-color: #007bff;
$breakpoints: (sm: 576px, md: 768px, lg: 992px, xl: 1200px);

// _mixins.scss
@mixin responsive($breakpoint) {
  @media (min-width: map-get($breakpoints, $breakpoint)) {
    @content;
  }
}

// main.scss(主文件)
@import 'variables';
@import 'mixins';
@import 'components/buttons';
@import 'components/forms';

.container {
  @include responsive(md) {
    max-width: 720px;
  }
}

Less 详细介绍

基本语法

// 变量
@primary-color: #007bff;
@font-family: 'Helvetica', 'Arial', sans-serif;

// 混合
.border-radius(@radius: 4px) {
  -webkit-border-radius: @radius;
  -moz-border-radius: @radius;
  border-radius: @radius;
}

// 使用
.button {
  background-color: @primary-color;
  .border-radius(5px);
}

Less 特有特性

// 嵌套和父选择器
.nav {
  background: #333;
  
  &-item {
    color: white;
    
    &:hover {
      color: #ccc;
    }
    
    &--active {
      font-weight: bold;
    }
  }
}

// 编译后
.nav { background: #333; }
.nav-item { color: white; }
.nav-item:hover { color: #ccc; }
.nav-item--active { font-weight: bold; }

Sass vs Less 对比

特性 Sass/SCSS Less
流行度 ⭐⭐⭐⭐⭐(行业标准) ⭐⭐⭐(逐渐减少)
功能丰富度 ⭐⭐⭐⭐⭐ ⭐⭐⭐
性能 ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
学习曲线 ⭐⭐⭐ ⭐⭐
社区支持 ⭐⭐⭐⭐⭐ ⭐⭐⭐
Bootstrap支持 ✅(v5+) ✅(v3-v4)

现代工作流集成

安装与使用

# 安装Sass
npm install -g sass

# 编译SCSS文件
sass input.scss output.css

# 监听文件变化
sass --watch input.scss:output.css

# 编译整个目录
sass --watch scss:css

# 压缩输出
sass --style=compressed input.scss output.css

构建工具集成

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: [
          'style-loader',
          'css-loader',
          'sass-loader'
        ]
      }
    ]
  }
};

// package.json
{
  "scripts": {
    "build:css": "sass scss/main.scss dist/css/main.css",
    "watch:css": "sass --watch scss:dist/css"
  }
}

与现代框架结合

// React + Sass组件
// Button.module.scss
.button {
  padding: 0.5rem 1rem;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  
  &Primary {
    background-color: #007bff;
    color: white;
  }
  
  &Secondary {
    background-color: #6c757d;
    color: white;
  }
}

// Button.jsx
import styles from './Button.module.scss';

const Button = ({ primary, children }) => (
  <button className={`${styles.button} ${primary ? styles.primary : styles.secondary}`}>
    {children}
  </button>
);

项目结构

src/
├── scss/
│   ├── utils/
│   │   ├── _variables.scss
│   │   ├── _mixins.scss
│   │   ├── _functions.scss
│   │   └── _placeholders.scss
│   ├── components/
│   │   ├── _buttons.scss
│   │   ├── _forms.scss
│   │   └── _cards.scss
│   ├── layout/
│   │   ├── _header.scss
│   │   ├── _footer.scss
│   │   └── _grid.scss
│   ├── pages/
│   │   ├── _home.scss
│   │   └── _contact.scss
│   └── main.scss
└── css/
    └── main.css

代码组织规范

// _variables.scss
// ============= COLORS =============
$primary-color: #007bff;
$secondary-color: #6c757d;

// ============= TYPOGRAPHY =============
$base-font-size: 16px;
$font-family: 'Helvetica', 'Arial', sans-serif;

// ============= BREAKPOINTS =============
$breakpoints: (
  sm: 576px,
  md: 768px,
  lg: 992px,
  xl: 1200px
);

// _mixins.scss
@mixin respond-to($breakpoint) {
  @if map-has-key($breakpoints, $breakpoint) {
    @media (min-width: map-get($breakpoints, $breakpoint)) {
      @content;
    }
  } @else {
    @error "Unknown breakpoint #{$breakpoint}";
  }
}

@mixin text-truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

性能优化

// 避免过度嵌套
// 不好
.nav {
  .nav-list {
    .nav-item {
      .nav-link {
        // 太深了!
      }
    }
  }
}

// 好
.nav-list {
  .nav-item {
    .nav-link {
      // 合理的深度
    }
  }
}

// 使用继承而不是混合宏生成重复代码
%base-styles {
  padding: 1rem;
  margin: 0.5rem;
}

// 而不是
@mixin base-styles {
  padding: 1rem;
  margin: 0.5rem;
}

学习路径建议

初学者路径

  • 先掌握原生CSS – 理解CSS基础
  • 学习SCSS语法 – 变量、嵌套、混合宏
  • 实践小项目 – 重构现有CSS代码
  • 学习高级特性 – 函数、循环、条件语句
  • 集成构建工具 – Webpack、Gulp、Parcel

推荐资源

  • 官方文档:sass-lang.com

CSS框架简介

特性维度 Bootstrap Tailwind CSS Bulma Foundation 原生 CSS (Grid/Flexbox)
设计理念 组件优先,提供完整UI组件 实用工具优先,提供原子化类名 模块化,纯CSS,基于Flexbox 响应式优先,强调可访问性和企业级应用 浏览器原生支持
学习成本 低(组件化思维,文档完善) 中(需记忆大量工具类名,但命名有规律) 低(API简洁直观) 中(比Bootstrap更灵活,定制性更强) 高(需掌握布局原理)
定制能力 中(通过Sass变量修改主题) (完全自定义主题和工具类) 中(通过Sass变量定制) 高(Sass基础,高度可定制) 极高(完全自由控制)
预置组件 丰富(按钮、表单、导航、模态框等) 无(需自行组合或使用第三方组件库如Tailwind UI) 适中(常用组件齐全) 丰富(企业级组件)
响应式支持 强大(移动优先的栅格系统) 强大(通过响应式前缀,如 md:, lg:) 强大(基于Flexbox的响应式网格) 强大(移动优先,响应式网格) 强大(需手动实现)
生态与社区 极成熟(资源丰富,社区庞大) 极活跃(插件、组件库丰富,JIT模式) 活跃(社区支持,扩展资源) 成熟(企业应用多) 基础(需自行封装)

1

性能与体积 中等(可按需引入) 轻量(JIT模式按需生成,可优化至很小) 轻量(纯CSS,无JS依赖) 中等(功能全面) 零依赖(纯原生)

1

适用项目类型 企业官网、管理后台、快速原型 高度定制化的中后台、与React/Vue等框架配合 中小型网站、个人项目、希望样式简洁现代的应用 大型企业级网站、复杂交互应用 追求极致性能或独特设计的项目

1

Bootstrap

Bootstrap是一个组件优先的开源前端框架,用于基于HTML、CSS和JavaScript构建现代和响应式的网站和应用。

  • 组件丰富:提供了大量预制的组件,如按钮、导航栏、模态框、卡片等,能快速搭建界面。
  • 强大的栅格系统:基于12列的响应式栅格系统是其核心,能轻松创建适应不同屏幕的布局。
  • 浏览器兼容性好:注重跨浏览器兼容性。
  • 定制化:通常通过Sass变量修改主题。
  • jQuery依赖:Bootstrap 5开始不再依赖jQuery,但部分组件仍涉及JavaScript。

Tailwind CSS

Tailwind CSS是一个实用程序优先的CSS框架,它提供低级的实用工具类,允许开发者通过组合这些类来直接在HTML中构建自定义设计。

  • 实用工具优先:提供了大量原子化的工具类(如 ml-4, text-center),通过组合它们来构建样式。
  • 高度可定制:通过config.js文件可以深度定制设计系统(颜色、间距、字体等)。
  • 响应式设计:提供如 sm:, md:, lg:等前缀,轻松创建响应式界面。
  • Just-In-Time (JIT) 模式:按需生成CSS,极大减少输出文件大小,并支持在类名中使用任意值。
  • 学习曲线与HTML冗长:需记忆大量类名,HTML元素上的 class列表可能变得很长。

Bulma

Bulma是一个基于Flexbox布局的现代CSS框架,以其简洁性和易用性受到欢迎。

  • 纯CSS框架:不包含JavaScript,可以自由选择所需的JS交互实现,非常适合与React、Vue等框架集成。
  • Flexbox布局:完全基于Flexbox,简化了布局操作。
  • API简洁直观:类名通常非常直观,如 is-primary, is-large。
  • 轻量与模块化:采用模块化结构,可以按需引入Sass模块。
  • 组件和定制:提供了常用的组件,如菜单、卡片、表单等,可通过Sass变量进行定制。

Foundation

Foundation是一个响应式前端框架,特别强调移动端优先和可访问性。

  • 企业级焦点:自称是“最先进的响应式前端框架”,提供全面的HTML、CSS和UI组件。
  • 可访问性:内置了对ARIA属性的支持,并致力于创建符合可访问性标准的网站。
  • 高度灵活性:提供强大的栅格系统和UI工具,定制性非常高。
  • 学习曲线:相对于Bootstrap,可能需要更多时间来掌握其全部功能。

原生 CSS (Grid/Flexbox)

  • 最大控制权与零开销:对样式有完全的控制权,不会引入任何额外的框架开销或学习成本。
  • 现代布局的强大能力:CSS Grid(二维布局)和Flexbox(一维布局)是强大的现代CSS布局工具。
  • 更高的实现成本:构建复杂的UI和响应式布局需要手动编写更多代码。

CSS学习相关

练习平台

学习心得

  • 实践!实践!实践! CSS光看理论是绝对学不会的。一定要边学边敲代码,哪怕是最简单的例子也要自己动手实现一遍。从模仿一个按钮、一个导航栏开始,再到模仿一个完整的网站页面。
  • 深刻理解“盒模型”和“文档流”。90%的布局问题都可以归结为对这两个概念理解不透彻。特别是 margin合并、position脱离文档流等问题。
  • 尽早拥抱 Flexbox 和 Grid。传统的 float和 position布局方式需要了解,但在新项目中应优先使用 Flexbox 和 Grid。它们是现代CSS布局的现在和未来,能让你事半功倍。
  • 学会使用浏览器开发者工具 (F12)。这是你调试CSS的最强武器。你可以实时修改样式、查看盒模型、调试响应式布局,能极大提高你排查问题的效率。
  • 不要死记硬背属性。CSS属性繁多,不可能也没必要全部记住。重要的是理解其工作原理和常用场景。用到时随时查文档(MDN)即可。
  • 保持耐心,接受不完美。CSS有时会显得很“玄学”,同一个效果可能有多种实现方式,并且在不同浏览器上可能有细微差异。遇到问题时不要气馁,善用搜索引擎(如 Stack Overflow),几乎所有坑都有人踩过。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注