第二篇:CSS3 全部知识点全解 + 项目样式实现

承接第一篇,我们已经用 HTML5 搭好了 TaskFlow 任务管理器的骨架。本篇将系统讲解 CSS3 的全部知识点,并让骨架变成一个漂亮的界面。


目录

  1. [CSS 是什么 & 引入方式](#CSS 是什么 & 引入方式)
  2. 选择器全解
  3. 层叠、继承与优先级
  4. 盒模型
  5. 常用属性:字体/文本/背景/边框
  6. [display 与元素类型](#display 与元素类型)
  7. [定位 position 与层叠上下文](#定位 position 与层叠上下文)
  8. [Flexbox 弹性布局全解](#Flexbox 弹性布局全解)
  9. [Grid 网格布局全解](#Grid 网格布局全解)
  10. 过渡、变形、动画
  11. [CSS 变量与函数](#CSS 变量与函数)
  12. 媒体查询与响应式设计
  13. [现代 CSS 新特性](#现代 CSS 新特性)
  14. [项目实战:TaskFlow 完整样式](#项目实战:TaskFlow 完整样式)
  15. 本篇小结与练习

一、CSS 是什么 & 引入方式

CSS(Cascading Style Sheets,层叠样式表) 负责描述 HTML 的外观表现。

三种引入方式

html 复制代码
<!-- 1. 行内样式(内联):优先级最高,但难维护,少用 -->
<p style="color: red; font-size: 16px;">文字</p>

<!-- 2. 内部样式表:写在 head 里的 <style> -->
<head>
  <style>
    p { color: red; }
  </style>
</head>

<!-- 3. 外部样式表:最推荐,可缓存、可复用 -->
<link rel="stylesheet" href="./css/main.css">

<style> 里也能用 @import(不推荐,会阻塞渲染):

css 复制代码
@import url('./variables.css');

CSS 规则的结构

css 复制代码
/* 选择器 { 属性: 值; 属性: 值; } */
.selector {
  color: #333;              /* 声明 */
  font-size: 16px;          /* 声明 */
}

组成部分:

  • 选择器(selector):选中目标元素
  • 属性(property):要修改的特性
  • 值(value):属性取值
  • 声明(declaration) :属性: 值
  • 规则块(rule) :{ } 内的全部声明

注释

css 复制代码
/* 单行注释 */
/* 多行注释
   可以换行 */
/* 注意:CSS 没有 // 注释 */

二、选择器全解

2.1 基础选择器

css 复制代码
*           { }   /* 通配符:所有元素 */
p           { }   /* 元素选择器 */
.class      { }   /* 类选择器,可多个元素共用 */
#id         { }   /* ID 选择器,页面唯一 */

2.2 组合选择器

css 复制代码
/* 后代:div 内任意层级的 p */
div p { }

/* 直接子代:div 的直系子元素 p */
div > p { }

/* 相邻兄弟:紧跟在 h2 后的第一个 p */
h2 + p { }

/* 通用兄弟:h2 之后所有同级 p */
h2 ~ p { }

2.3 属性选择器

css 复制代码
[disabled]                { }   /* 有该属性 */
[type="text"]             { }   /* 精确匹配 */
[class~="btn"]            { }   /* 空格分隔的列表中含 btn */
[lang|="zh"]              { }   /* 以 zh- 开头或等于 zh */
[href^="https"]           { }   /* 以 https 开头 */
[href$=".pdf"]            { }   /* 以 .pdf 结尾 */
[href*="example"]         { }   /* 包含 example */
[data-role="admin" i]     { }   /* 加 i 表示大小写不敏感 */

2.4 伪类选择器(:xxx)

交互状态类:

css 复制代码
a:link     { }  /* 未访问链接 */
a:visited  { }  /* 已访问链接 */
a:hover    { }  /* 悬停 */
a:active   { }  /* 按下瞬间 */
input:focus { } /* 聚焦 */
input:focus-within { } /* 自身或子元素聚焦 */

LVHA 顺序:link → visited → hover → active,否则样式不生效。

结构伪类:

css 复制代码
li:first-child       { }  /* 父元素第一个子元素 */
li:last-child        { }  /* 最后一个 */
li:only-child        { }  /* 唯一子元素 */
li:nth-child(3)      { }  /* 第 3 个 */
li:nth-child(odd)    { }  /* 奇数 1,3,5... */
li:nth-child(even)   { }  /* 偶数 2,4,6... */
li:nth-child(2n+1)   { }  /* 公式:偶数用 2n,前 3 个用 -n+3 */
li:nth-last-child(2) { }  /* 倒数第 2 个 */

/* of-type 系列:只按同类型标签计数 */
p:first-of-type      { }
p:last-of-type       { }
p:nth-of-type(2)     { }

/* 过滤空元素 */
div:empty            { }  /* 没有任何内容(包括空格) */

:nth-child 公式详解:

公式 含义
2n / even 偶数位
2n+1 / odd 奇数位
3n 3 的倍数位
n+4 第 4 个开始之后
-n+3 前 3 个
2n+3 3,5,7,9...

表单伪类:

css 复制代码
input:checked    { }  /* 勾选的 checkbox/radio */
input:disabled   { }  /* 禁用 */
input:enabled    { }  /* 启用 */
input:required   { }  /* 必填 */
input:optional   { }  /* 非必填 */
input:valid      { }  /* 校验通过 */
input:invalid    { }  /* 校验失败 */
input:in-range   { }  /* 数值在范围 */
input:out-of-range { }
input:read-only  { }
input:placeholder-shown { }  /* 显示 placeholder 时(即空) */

其他逻辑伪类:

css 复制代码
:not(.active)           { }  /* 排除 */
:is(h1, h2, h3)         { }  /* 匹配其中任意一个 */
:where(h1, h2, h3)      { }  /* 同 is,但优先级为 0 */
:has(> img)             { }  /* 包含某子元素(现代浏览器支持) */
:target                 { }  /* URL 锚点指向的元素 */
:root                   { }  /* 根元素 html,常用于定义变量 */

2.5 伪元素选择器(::xxx)

css 复制代码
p::first-line          { }  /* 第一行 */
p::first-letter        { }  /* 第一个字母 */
p::selection           { }  /* 鼠标选中文本 */
p::before              { content: "★"; }  /* 元素内容前插入 */
p::after               { content: "→"; }  /* 元素内容后插入 */
input::placeholder     { }  /* 占位文字 */
li::marker             { }  /* 列表项符号 */

::before / ::after 必须写 content ,哪怕是 content: "";。

2.6 选择器优先级(权值)

类型 权值 示例
行内样式 1000 style="..."
ID 选择器 100 #app
类/属性/伪类 10 .btn、[type]、:hover
元素/伪元素 1 div、::before
通配符/组合器 0 *、>、+

比较规则 :从左往右逐位比较,先大者赢;相同则后写的胜出(层叠)。

css 复制代码
/* 权值 (0,2,0),比下面大 */
.btn.primary { color: red; }
/* 权值 (0,1,0) */
.btn { color: blue; }

!important :强制最高优先级,但会破坏层叠,慎用:

css 复制代码
p { color: red !important; }

2.7 :is() / :where() / :has() 现代用法

css 复制代码
/* 简化重复:以前要写三次 */
article h1, article h2, article h3 { }
/* 现在 */
article :is(h1, h2, h3) { }

/* :where 优先级为 0,方便被覆盖 */
:where(ul, ol) li { margin-left: 1rem; }

/* :has 父级选择:包含 img 的 card 加边框 */
.card:has(img) { border: 1px solid #ddd; }

三、层叠、继承与优先级

3.1 层叠(Cascade)

当多条规则作用同一元素时,按以下顺序决胜:

  1. 来源 :浏览器默认 < 用户样式 < 作者样式 < 作者 !important < 用户 !important
  2. 优先级(权值)
  3. 书写顺序:后者胜

3.2 继承(Inheritance)

部分属性会自动从父元素传给子元素,无需重复声明。

可继承属性:

  • 字体:font-family、font-size、font-weight、font-style
  • 文本:color、line-height、text-align、letter-spacing、word-spacing
  • 列表:list-style
  • 可见性:visibility、cursor

不可继承(常见):

  • margin、padding、border
  • background、width、height
  • display、position、float

强制继承 / 取消继承:

css 复制代码
.child {
  color: inherit;    /* 强制继承父级 */
  border: initial;   /* 恢复为默认值 */
  margin: unset;     /* 可继承属性=inherit,其余=initial */
  color: revert;     /* 恢复为浏览器用户代理样式 */
}

技巧:整体统一字体大小用 rem + 根元素设置

css 复制代码
html { font-size: 16px; }
p { font-size: 1rem; }      /* 16px */
h1 { font-size: 2rem; }     /* 32px */

四、盒模型

4.1 四层结构

复制代码
┌─────────────────────────────────────┐
│           margin(外边距)          │
│  ┌───────────────────────────────┐  │
│  │      border(边框)           │  │
│  │  ┌─────────────────────────┐  │  │
│  │  │   padding(内边距)      │  │  │
│  │  │  ┌───────────────────┐  │  │  │
│  │  │  │  content(内容)  │  │  │  │
│  │  │  └───────────────────┘  │  │  │
│  │  └─────────────────────────┘  │  │
│  └───────────────────────────────┘  │
└─────────────────────────────────────┘

4.2 box-sizing

css 复制代码
/* 默认:width = content 宽,加上 padding/border 会更大 */
.box { box-sizing: content-box; width: 200px; padding: 20px; border: 5px; }
/* 实际占宽 = 200 + 40 + 10 = 250px */

/* 推荐:width 已含 padding + border */
.box { box-sizing: border-box; width: 200px; padding: 20px; border: 5px; }
/* 实际占宽 = 200px,内容区 = 200 - 40 - 10 = 150px */

项目全局重置 :*, *::before, *::after { box-sizing: border-box; } 是现代标配。

4.3 外边距塌陷(Margin Collapse)

三种塌陷场景:

html 复制代码
<!-- 1. 相邻兄弟:上下边距合并,取较大者 -->
<p style="margin-bottom: 30px">A</p>
<p style="margin-top: 20px">B</p>
<!-- 实际间距 = 30px,不是 50px -->

<!-- 2. 父子:子元素 margin-top 会"顶"穿父元素 -->
<div class="parent">
  <div class="child" style="margin-top: 20px">...</div>
</div>
<!-- parent 顶部也会出现 20px 的外间距 -->

<!-- 3. 空元素:自身上下边距合并 -->
<div style="margin: 20px 0"></div>

解决父子塌陷的方法:

css 复制代码
.parent {
  overflow: hidden;            /* 创建 BFC */
  /* 或者 */
  padding-top: 1px;
  /* 或者 */
  border-top: 1px solid transparent;
  /* 或者 */
  display: flow-root;          /* 现代最推荐 */
}

4.4 外边距 vs 内边距

属性 作用位置 背景色覆盖 常用于
margin 元素外部 否 元素间距
padding 元素内部 是 内容与边框距离

简写规则:

css 复制代码
margin: 10px;                 /* 四周 10 */
margin: 10px 20px;            /* 上下 10,左右 20 */
margin: 10px 20px 30px;       /* 上 10,左右 20,下 30 */
margin: 10px 20px 30px 40px;  /* 上 右 下 左(顺时针) */

margin: 0 auto;               /* 块级元素水平居中 */

4.5 BFC(块级格式化上下文)

BFC 是一个独立的渲染区域,内部布局不影响外部。

触发方式:

  • overflow 不为 visible
  • display: flow-root / inline-block / flex / grid
  • position: absolute / fixed
  • float 不为 none

应用:

  1. 清除浮动
  2. 阻止父子 margin 塌陷
  3. 阻止元素被浮动元素覆盖
css 复制代码
/* 经典两栏布局,右侧不被左侧浮动覆盖 */
.left { float: left; width: 200px; }
.right { overflow: hidden; }  /* 触发 BFC */

五、常用属性:字体/文本/背景/边框

5.1 字体

css 复制代码
.text {
  font-family: system-ui, -apple-system, "Segoe UI",
               "PingFang SC", "Microsoft YaHei", sans-serif;

  font-size: 16px;           /* px / em / rem / % / vw */
  font-weight: 400;          /* 100~900 或 normal/bold */
  font-style: italic;        /* normal / italic / oblique */

  line-height: 1.6;          /* 无单位=倍数,推荐 */
  letter-spacing: 0.5px;     /* 字间距 */
  word-spacing: 2px;         /* 词间距 */
  text-indent: 2em;          /* 首行缩进 */

  font-variant: small-caps;  /* 小型大写 */
  font-feature-settings: "liga";  /* 连字 */
}

简写 font:(顺序:style variant weight size/line-height family,size 和 family 必须写)

css 复制代码
font: italic bold 16px/1.5 "Arial", sans-serif;

单位对比:

单位 相对 场景
px 绝对 固定尺寸
em 父元素字体 组件内相对尺寸
rem 根元素字体 全局缩放
% 父元素对应值 宽高、行高
vw / vh 视口宽高 全屏布局
vmin / vmax 视口较小/较大边 自适应字体
ch "0"字符宽 输入框宽度
ex "x"字符高 少用

5.2 文本

css 复制代码
.text {
  color: #333;
  text-align: center;        /* left/center/right/justify */
  text-decoration: underline wavy red;  /* 下划线,波浪线,红色 */
  text-transform: uppercase; /* 大写 */
  text-shadow: 2px 2px 4px rgba(0,0,0,.3);

  white-space: nowrap;       /* 不换行;normal 换行;pre 保留空白 */
  word-break: break-all;     /* 长英文强制换行 */
  overflow-wrap: anywhere;   /* 更智能的折行 */
  hyphens: auto;             /* 连字符 */

  /* 单行溢出省略号 */
  overflow: hidden;
  text-overflow: ellipsis;

  /* 多行溢出省略号 */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;

  vertical-align: middle;    /* 行内元素垂直对齐 */
  direction: rtl;            /* 文字方向 */
  writing-mode: vertical-rl; /* 竖排 */
}

5.3 背景

css 复制代码
.box {
  /* 颜色 / 图片 / 渐变 */
  background-color: #f5f5f5;
  background-image: url('./bg.png');
  background-image: linear-gradient(135deg, #667eea, #764ba2);
  background-image: radial-gradient(circle, #fff, #333);
  background-image: conic-gradient(red, yellow, lime, aqua, blue, magenta, red);

  background-repeat: no-repeat;    /* repeat-x / repeat-y / space / round */
  background-position: center center;  /* 可用百分比、关键字、长度 */
  background-size: cover;          /* cover / contain / 100px 200px */
  background-attachment: fixed;    /* 视差滚动效果 */
  background-origin: content-box;  /* 定位基准 */
  background-clip: text;           /* 文字裁剪背景(配透明色) */
  background-blend-mode: multiply; /* 混合模式 */
}

简写:

css 复制代码
background: #333 url('./bg.png') no-repeat center / cover;
/*          颜色  图片           重复      位置 / 尺寸 */

多背景(从上到下):

css 复制代码
background:
  url('./icon.png') no-repeat 10px center,
  linear-gradient(to right, #fff, #eee);

文字渐变技巧:

css 复制代码
.gradient-text {
  background: linear-gradient(90deg, #3b82f6, #ec4899);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

5.4 边框与圆角

css 复制代码
.box {
  border: 2px solid #333;                   /* 简写 */
  border-width: 1px 2px 3px 4px;
  border-style: dashed;
  border-color: red blue green gold;

  border-top: 1px solid #eee;               /* 单边 */
  border-radius: 8px;
  border-radius: 8px 0 8px 0;               /* 四角 */
  border-radius: 50%;                        /* 圆形 */
  border-radius: 50% / 30%;                  /* 椭圆角 */

  outline: 2px solid #3b82f6;               /* 轮廓,不占空间 */
  outline-offset: 2px;

  box-shadow: 0 4px 12px rgba(0,0,0,.1),    /* 多层阴影 */
              0 1px 3px rgba(0,0,0,.06);
  /* 参数:水平偏移 垂直偏移 模糊 扩展 颜色 inset */
}

CSS 边框也能做三角形:

css 复制代码
.triangle {
  width: 0; height: 0;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
  border-bottom: 10px solid #3b82f6;
}

5.5 溢出与光标

css 复制代码
.box {
  overflow: auto;              /* visible / hidden / scroll / auto */
  overflow-x: hidden;
  overflow-y: auto;
  overflow-clip-margin: 5px;
}

.btn { cursor: pointer; }      /* default/pointer/text/move/not-allowed/... */

六、display 与元素类型

6.1 display 常用值

css 复制代码
.el {
  display: block;         /* 块级:独占一行,可设宽高 */
  display: inline;        /* 行内:不换行,宽高无效 */
  display: inline-block;  /* 行内块:不换行 + 可设宽高 */
  display: none;          /* 隐藏,不占位 */
  display: flex;          /* 弹性容器 */
  display: inline-flex;
  display: grid;
  display: inline-grid;
  display: flow-root;     /* BFC 容器 */
  display: contents;      /* 自身盒消失,子元素上提 */
}

6.2 三种元素对比

特性 block inline inline-block
换行 ✅ ❌ ❌
设 width/height ✅ ❌ ✅
垂直 margin ✅ ❌(不生效) ✅
水平 margin ✅ ✅ ✅
padding ✅ 全方向 仅左右有效(上下视觉生效不影响布局) ✅

6.3 visibility vs display:none

css 复制代码
.a { display: none; }        /* 不渲染,不占空间,不可交互 */
.b { visibility: hidden; }   /* 不可见,仍占空间 */
.c { opacity: 0; }           /* 透明,仍占空间,可交互 */

6.4 float 浮动(了解)

css 复制代码
.left { float: left; }
.right { float: right; }

/* 清除浮动 */
.clearfix::after {
  content: "";
  display: block;
  clear: both;
}

现代布局优先 Flex/Grid ,float 只用于文字环绕图片等场景。


七、定位 position 与层叠上下文

7.1 position 五种取值

css 复制代码
.static   { position: static; }    /* 默认,文档流 */
.relative { position: relative; }  /* 相对自身原位置偏移,占位保留 */
.absolute { position: absolute; }  /* 相对最近的已定位祖先偏移,脱离文档流 */
.fixed    { position: fixed; }     /* 相对视口,滚动不动 */
.sticky   { position: sticky; }    /* 滚动到阈值后粘住,top/bottom 等生效 */

配合的偏移属性:

css 复制代码
.el {
  top: 10px;
  right: 20px;
  bottom: 0;
  left: 50%;
  z-index: 10;    /* 仅对定位元素(非 static)生效 */
}

7.2 定位的经典技巧

居中(绝对定位):

css 复制代码
.parent { position: relative; }
.child {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
}

撑满父元素:

css 复制代码
.overlay {
  position: absolute;
  inset: 0;         /* 等价 top:0; right:0; bottom:0; left:0 */
}

吸顶导航:

css 复制代码
.header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: #fff;
}

固定底栏:

css 复制代码
.footer {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  padding: 1rem;
}

7.3 层叠上下文(Stacking Context)

z-index 只在同一层叠上下文中比较。以下情况会创建新层叠上下文:

  • position 非 static 且 z-index 非 auto
  • opacity < 1
  • transform 非 none
  • filter 非 none
  • will-change 指定以上属性
  • isolation: isolate
  • mix-blend-mode 非 normal

常见坑:

html 复制代码
<div style="position: relative; z-index: 1">
  <div style="position: absolute; z-index: 9999">A</div>
</div>
<div style="position: relative; z-index: 2">
  B
</div>
<!-- A 永远盖不过 B,因为 A 被限制在父级 z-index:1 的上下文中 -->

同一上下文内的排序(从后到前):

  1. 背景与边框
  2. 负 z-index 子元素
  3. 块级子元素
  4. 浮动子元素
  5. 行内子元素
  6. z-index: 0 / auto
  7. 正 z-index 子元素

八、Flexbox 弹性布局全解

8.1 基本概念

复制代码
flex container(容器)
  ├─ main axis(主轴):默认水平
  ├─ cross axis(交叉轴):默认垂直
  └─ flex items(项目)

  [item] [item] [item]
   ↑ main-start      ↑ main-end
html 复制代码
<div class="flex-container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
</div>
css 复制代码
.flex-container { display: flex; }

8.2 容器属性(父元素上)

1. flex-direction:主轴方向

css 复制代码
flex-direction: row;             /* 默认:左→右 */
flex-direction: row-reverse;     /* 右→左 */
flex-direction: column;          /* 上→下 */
flex-direction: column-reverse;  /* 下→上 */

2. flex-wrap:换行

css 复制代码
flex-wrap: nowrap;         /* 默认,不换行(可能挤压) */
flex-wrap: wrap;           /* 换行 */
flex-wrap: wrap-reverse;   /* 反向换行 */

3. justify-content:主轴对齐

css 复制代码
justify-content: flex-start;    /* 起点对齐 */
justify-content: flex-end;      /* 终点对齐 */
justify-content: center;        /* 居中 */
justify-content: space-between; /* 两端对齐,中间均分 */
justify-content: space-around;  /* 每项两侧空间相等 */
justify-content: space-evenly;  /* 所有间距完全相等 */

4. align-items:交叉轴对齐(单行)

css 复制代码
align-items: stretch;     /* 默认:拉满交叉轴 */
align-items: flex-start;
align-items: flex-end;
align-items: center;
align-items: baseline;    /* 基线对齐 */

5. align-content:多行对齐(需 flex-wrap: wrap)

css 复制代码
align-content: flex-start / flex-end / center /
               space-between / space-around / space-evenly / stretch;

6. gap:项目间距(现代推荐)

css 复制代码
gap: 16px;              /* 行、列均 16 */
gap: 10px 20px;         /* 行 10,列 20 */
row-gap: 10px;
column-gap: 20px;

8.3 项目属性(子元素上)

1. flex(最重要)

css 复制代码
/* 简写:flex-grow flex-shrink flex-basis */
flex: 1;                /* = 1 1 0%:平均分配剩余空间 */
flex: auto;             /* = 1 1 auto */
flex: none;             /* = 0 0 auto:不伸不缩 */
flex: 0 0 200px;        /* 固定 200px 不可伸缩 */
  • flex-grow:空间富余时放大比例,默认 0
  • flex-shrink:空间不足时缩小比例,默认 1
  • flex-basis:主轴上的基础尺寸,默认 auto

2. align-self:单独覆盖 align-items

css 复制代码
align-self: flex-start / center / flex-end / stretch;

3. order:排列顺序,数字越小越靠前

css 复制代码
order: -1;

8.4 Flex 经典布局案例

① 水平垂直居中:

css 复制代码
.parent {
  display: flex;
  justify-content: center;
  align-items: center;
}

② 导航栏(左 logo,右菜单):

css 复制代码
.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 24px;
}

③ 两栏布局(左固定,右自适应):

css 复制代码
.layout { display: flex; gap: 20px; }
.sidebar { flex: 0 0 220px; }
.main    { flex: 1; min-width: 0; }  /* min-width: 0 防溢出 */

④ 圣杯布局(头/中/尾,中间三栏):

css 复制代码
body { display: flex; flex-direction: column; min-height: 100vh; }
main { display: flex; flex: 1; }
.left, .right { flex: 0 0 200px; }
.center { flex: 1; }

⑤ 等分布局:

css 复制代码
.row { display: flex; }
.row > * { flex: 1; }

⑥ 卡片列表自动换行:

css 复制代码
.cards {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}
.cards > .card {
  flex: 1 1 260px;   /* 基础宽 260,可伸可缩 */
}

九、Grid 网格布局全解

9.1 基本概念

复制代码
grid container(容器)
  ├─ grid lines(网格线,从 1 开始计数)
  ├─ grid tracks(行/列轨道)
  ├─ grid cell(单元格)
  └─ grid area(网格区域,可跨行列)
css 复制代码
.grid {
  display: grid;
  grid-template-columns: 200px 1fr 100px;
  grid-template-rows: 80px auto;
  gap: 16px;
}

9.2 容器属性

1. 定义列/行:

css 复制代码
/* 固定尺寸 */
grid-template-columns: 100px 200px 100px;

/* 混合单位 */
grid-template-columns: 200px 1fr 2fr;

/* repeat 简化 */
grid-template-columns: repeat(4, 1fr);        /* 4 等份 */
grid-template-columns: repeat(3, 100px);

/* 自动填充 / 自动适应 */
grid-template-columns: repeat(auto-fill, 200px);      /* 尽量塞满,可能留空 */
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); /* 填满 */

/* minmax + 响应式 */
grid-template-columns: minmax(200px, 1fr) 2fr;

/* 命名网格线 */
grid-template-columns: [start] 100px [mid] 1fr [end];

/* 命名区域 */
grid-template-areas:
  "header header"
  "sidebar main"
  "footer footer";

2. 行高:

css 复制代码
grid-template-rows: 80px auto 60px;
grid-auto-rows: 100px;         /* 隐式行高度 */
grid-auto-columns: 100px;

3. 间距:

css 复制代码
gap: 16px;
row-gap: 20px;
column-gap: 10px;

4. 对齐:

css 复制代码
/* 所有单元格内部内容的对齐 */
justify-items: start | end | center | stretch;
align-items:   start | end | center | stretch;

/* 整个网格在容器内的对齐 */
justify-content: start | end | center | space-between |
                 space-around | space-evenly;
align-content:   同上;

5. 自动排列方向:

css 复制代码
grid-auto-flow: row;          /* 默认:按行填 */
grid-auto-flow: column;       /* 按列填 */
grid-auto-flow: row dense;    /* 密集排列,填补空洞 */

9.3 项目属性

1. 按网格线定位:

css 复制代码
.item {
  grid-column-start: 1;
  grid-column-end: 3;       /* 跨 2 列(1 到 3) */
  grid-row-start: 2;
  grid-row-end: 4;

  /* 简写 */
  grid-column: 1 / 3;
  grid-row: 2 / 4;

  /* 跨 N 格 */
  grid-column: span 2;

  /* 用负线号(从末尾数) */
  grid-column: 1 / -1;   /* 撑满整行 */
}

2. 用命名区域定位:

css 复制代码
.layout {
  display: grid;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
  grid-template-columns: 200px 1fr;
  grid-template-rows: 60px 1fr 60px;
  min-height: 100vh;
  gap: 12px;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main    { grid-area: main; }
.footer  { grid-area: footer; }

3. 自身对齐:

css 复制代码
.item {
  justify-self: start | end | center | stretch;
  align-self:   start | end | center | stretch;
}

9.4 Grid 经典布局案例

① 响应式卡片墙:

css 复制代码
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 20px;
}

② 12 列栅格系统:

css 复制代码
.row {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 16px;
}
.col-6 { grid-column: span 6; }
.col-4 { grid-column: span 4; }

③ 页面对角布局(大屏):

css 复制代码
.page {
  display: grid;
  grid-template-areas:
    "nav nav"
    "hero sidebar"
    "content content"
    "footer footer";
  grid-template-columns: 1fr 300px;
  grid-template-rows: 60px 400px auto 80px;
}

9.5 Flex vs Grid 选择

场景 推荐
一维布局(一行或一列) Flex
二维布局(行+列同时) Grid
内容驱动尺寸 Flex
布局驱动尺寸 Grid
导航、按钮组、卡片内布局 Flex
页面骨架、杂志排版、卡片墙 Grid

实践中两者混用,Grid 做外层骨架,Flex 做组件内部。


十、过渡、变形、动画

10.1 过渡 transition

css 复制代码
.btn {
  background: #3b82f6;
  transition: background-color .3s ease, transform .2s ease-out;
  /* transition: all .3s; 简单但性能差,不推荐 */
}

.btn:hover {
  background: #2563eb;
  transform: translateY(-2px);
}

完整语法:

css 复制代码
transition: [property] [duration] [timing-function] [delay];
transition: background-color 0.3s cubic-bezier(.4,0,.2,1) 0.1s;

缓动函数:

值 效果
linear 匀速
ease 慢-快-慢(默认)
ease-in 慢进
ease-out 慢出
ease-in-out 两端慢
cubic-bezier(x1,y1,x2,y2) 自定义贝塞尔

性能提示 :优先过渡 transform 和 opacity(触发 GPU 合成),避免过渡 width/height/top/left(触发重排)。

10.2 变形 transform

css 复制代码
.el {
  /* 平移 */
  transform: translate(10px, 20px);
  transform: translateX(10px);
  transform: translate3d(10px, 20px, 0);

  /* 缩放 */
  transform: scale(1.2);
  transform: scaleX(2) scaleY(0.5);

  /* 旋转 */
  transform: rotate(45deg);
  transform: rotateX(45deg);   /* 3D */
  transform: rotateY(45deg);

  /* 倾斜 */
  transform: skew(10deg, 5deg);

  /* 多重变形:从右往左应用 */
  transform: translate(-50%, -50%) rotate(45deg) scale(1.2);

  /* 3D */
  transform: perspective(500px) rotateY(30deg);
  transform-style: preserve-3d;
  backface-visibility: hidden;
  transform-origin: center center;   /* 变换原点 */
}

经典应用:

  • 居中:translate(-50%, -50%)
  • 悬停浮起:transform: translateY(-4px)
  • 加载动画旋转:animation: spin 1s linear infinite; @keyframes spin { to { transform: rotate(360deg); } }
  • 翻转卡片:rotateY(180deg) + backface-visibility

10.3 关键帧动画 @keyframes

css 复制代码
@keyframes fadeInUp {
  0% {
    opacity: 0;
    transform: translateY(20px);
  }
  100% {
    opacity: 1;
    transform: translateY(0);
  }
}

.card {
  animation-name: fadeInUp;
  animation-duration: 0.5s;
  animation-timing-function: ease-out;
  animation-delay: 0.1s;
  animation-iteration-count: 1;        /* infinite 无限 */
  animation-direction: normal;          /* reverse / alternate */
  animation-fill-mode: both;            /* forwards / backwards */
  animation-play-state: running;        /* paused */

  /* 简写 */
  animation: fadeInUp 0.5s ease-out 0.1s 1 normal both;
}

简写顺序(时间值):第一个是 duration,第二个是 delay。

animation-fill-mode 详解:

值 含义
none 动画前后无样式
forwards 保留最后一帧样式
backwards 应用第一帧到延时期间
both 前后都保留

10.4 常用动画案例

加载圈:

css 复制代码
@keyframes spin { to { transform: rotate(360deg); } }
.spinner {
  width: 40px; height: 40px;
  border: 4px solid #e2e8f0;
  border-top-color: #3b82f6;
  border-radius: 50%;
  animation: spin .8s linear infinite;
}

骨架屏闪烁:

css 复制代码
@keyframes shimmer {
  0% { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}
.skeleton {
  background: linear-gradient(90deg, #eee 25%, #f5f5f5 37%, #eee 63%);
  background-size: 200% 100%;
  animation: shimmer 1.4s infinite;
}

脉冲:

css 复制代码
@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}
.pulse { animation: pulse 2s ease-in-out infinite; }

10.5 prefers-reduced-motion(无障碍)

css 复制代码
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

十一、CSS 变量与函数

11.1 自定义属性(CSS Variables)

css 复制代码
:root {
  --color-primary: #3b82f6;
  --space-4: 16px;
  --radius: 8px;
}

.btn {
  background: var(--color-primary);
  padding: var(--space-4);
  border-radius: var(--radius);
}

/* 带默认值 */
color: var(--text-color, #333);

/* 局部覆盖 */
.dark { --color-primary: #60a5fa; }

/* JS 读写 */
/* el.style.setProperty('--color-primary', 'red'); */
/* getComputedStyle(el).getPropertyValue('--color-primary'); */

优势:

  • 主题切换、响应式、JS 动态修改
  • 全局统一管理设计变量
  • 可继承、可作用域

11.2 常用函数

颜色:

css 复制代码
color: rgb(59 130 246);
color: rgba(59, 130, 246, 0.5);
color: hsl(217 91% 60%);
color: #3b82f6;
color: #3b82f680;                     /* 带透明度 */

color: color-mix(in srgb, #3b82f6 50%, white);

尺寸计算:

css 复制代码
width: calc(100% - 32px);
height: calc(100vh - 60px);
font-size: calc(1rem + 0.5vw);

最值:

css 复制代码
width: min(90%, 1200px);          /* 取较小 */
width: max(320px, 50%);           /* 取较大 */
font-size: clamp(1rem, 2.5vw, 1.5rem);  /* min, 理想值, max */

其他:

css 复制代码
/* 变量 */
var(--x)

/* 引用属性值 */
width: attr(data-width px);

/* 环境变量(iOS 安全区) */
padding-bottom: env(safe-area-inset-bottom);

11.3 clamp() 响应式排版

css 复制代码
h1 { font-size: clamp(1.75rem, 5vw, 3rem); }
.container { width: clamp(320px, 90vw, 1280px); margin-inline: auto; }

十二、媒体查询与响应式设计

12.1 基本语法

css 复制代码
@media screen and (min-width: 768px) {
  .container { max-width: 720px; }
}

@media (max-width: 767px) {
  .sidebar { display: none; }
}

/* 组合条件 */
@media (min-width: 600px) and (max-width: 900px) { }
@media (min-width: 600px) and (orientation: landscape) { }

/* or */
@media (max-width: 600px), (min-width: 1200px) { }

/* 深色模式 */
@media (prefers-color-scheme: dark) { }

/* 打印 */
@media print { .no-print { display: none; } }

/* 悬停能力 */
@media (hover: hover) { .btn:hover { ... } }

12.2 断点策略

移动优先(Mobile First)------推荐:

css 复制代码
/* 基础样式:手机 */
.container { width: 100%; padding: 16px; }

/* 平板 ≥ 640 */
@media (min-width: 640px) {
  .container { max-width: 600px; padding: 24px; }
}

/* 桌面 ≥ 1024 */
@media (min-width: 1024px) {
  .container { max-width: 960px; }
}

/* 大屏 ≥ 1280 */
@media (min-width: 1280px) {
  .container { max-width: 1200px; }
}

12.3 常用响应式技巧

① 响应式图片:

css 复制代码
img { max-width: 100%; height: auto; display: block; }

② 响应式网格(无需媒体查询):

css 复制代码
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px;
}

③ 响应式字体:

css 复制代码
html { font-size: clamp(14px, 1vw + 10px, 18px); }

④ 容器查询(现代):

css 复制代码
.card-container { container-type: inline-size; }

@container (min-width: 400px) {
  .card { display: flex; }
}

⑤ 逻辑属性(支持 RTL):

css 复制代码
.el {
  margin-inline: auto;         /* 替代左右 */
  margin-block: 16px;          /* 替代上下 */
  padding-inline: 12px;
  border-inline-start: 2px solid;
}

12.4 视口单位与安全区

css 复制代码
.hero {
  min-height: 100vh;
  min-height: 100dvh;   /* 动态视口,移动端更准 */
  min-height: 100svh;   /* 小视口,最保守 */
}

十三、现代 CSS 新特性

13.1 嵌套(CSS Nesting)

css 复制代码
.card {
  padding: 16px;

  & .title { font-size: 1.25rem; }
  &:hover { box-shadow: 0 4px 12px rgba(0,0,0,.1); }
  &.is-active { border-color: #3b82f6; }
  @media (min-width: 768px) {
    padding: 24px;
  }
}

13.2 逻辑属性

css 复制代码
.el {
  margin-inline: auto;
  padding-block: 1rem;
  border-inline-start: 3px solid var(--color-primary);
  inset-inline-end: 0;
}

13.3 aspect-ratio

css 复制代码
.thumb {
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

13.4 object-fit / object-position

css 复制代码
img {
  width: 200px; height: 200px;
  object-fit: cover;      /* cover / contain / fill / none / scale-down */
  object-position: center top;
}

13.5 scroll-behavior 与平滑滚动

css 复制代码
html { scroll-behavior: smooth; }

13.6 scroll-snap 滚动吸附

css 复制代码
.carousel {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
}
.carousel > .slide {
  flex: 0 0 100%;
  scroll-snap-align: start;
}

13.7 :focus-visible

css 复制代码
/* 鼠标点击不出轮廓,键盘 Tab 出轮廓 */
button:focus { outline: none; }
button:focus-visible { outline: 2px solid #3b82f6; outline-offset: 2px; }

13.8 accent-color

css 复制代码
input[type="checkbox"],
input[type="radio"],
progress {
  accent-color: #3b82f6;
}

13.9 backdrop-filter

css 复制代码
.glass {
  background: rgba(255, 255, 255, 0.6);
  backdrop-filter: blur(12px) saturate(150%);
  -webkit-backdrop-filter: blur(12px) saturate(150%);
}

13.10 text-wrap

css 复制代码
h1 { text-wrap: balance; }    /* 标题行更均衡 */
p  { text-wrap: pretty; }     /* 避免孤字 */

13.11 color-scheme

css 复制代码
:root { color-scheme: light dark; }

十四、项目实战:TaskFlow 完整样式

现在把第一篇的 HTML 骨架变成漂亮的成品。

14.1 完整 css/main.css

css 复制代码
/* ============================================================
   TaskFlow · 主样式
   依赖:reset.css、variables.css
   ============================================================ */

/* ---------- 基础 ---------- */
body {
  background: var(--bg-page);
  color: var(--text-primary);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  transition: background-color .3s, color .3s;
}

::selection { background: var(--color-primary); color: #fff; }

/* 焦点可见性 */
:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* ---------- 页头 ---------- */
.app-header {
  position: sticky;
  top: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-6);
  background: color-mix(in srgb, var(--bg-card) 85%, transparent);
  backdrop-filter: blur(12px) saturate(180%);
  -webkit-backdrop-filter: blur(12px) saturate(180%);
  border-bottom: 1px solid var(--border-color);
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.brand h1 {
  font-size: 1.25rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  background: linear-gradient(135deg, var(--color-primary), #ec4899);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.nav-list {
  display: flex;
  gap: var(--space-1);
}

.nav-link {
  display: inline-block;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  font-size: 0.9rem;
  color: var(--text-secondary);
  transition: background-color .2s, color .2s;
}

.nav-link:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
}

.nav-link.is-active {
  background: var(--color-primary);
  color: #fff;
}

/* ---------- 主体 ---------- */
.app-main {
  flex: 1;
  width: 100%;
  max-width: 860px;
  margin-inline: auto;
  padding: var(--space-6);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* 卡片容器 */
.panel {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  box-shadow: var(--shadow-sm);
  transition: box-shadow .3s;
}

.panel:hover { box-shadow: var(--shadow-md); }

.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-3);
}

.panel-head h2 { font-size: 1.1rem; }

/* ---------- 表单 ---------- */
.task-form {
  display: grid;
  grid-template-columns: 1fr auto auto auto;
  gap: var(--space-2);
  align-items: center;
}

@media (max-width: 720px) {
  .task-form {
    grid-template-columns: 1fr;
  }
}

.field { position: relative; }

.task-form input[type="text"],
.task-form input[type="date"],
.task-form select,
.dialog-form input,
.dialog-form select {
  width: 100%;
  padding: var(--space-2) var(--space-3);
  background: var(--bg-page);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  font-size: 0.95rem;
  color: var(--text-primary);
  transition: border-color .2s, box-shadow .2s;
}

.task-form input:focus,
.task-form select:focus,
.dialog-form input:focus,
.dialog-form select:focus {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 20%, transparent);
  outline: none;
}

.task-form input:invalid:not(:placeholder-shown) {
  border-color: var(--color-danger);
}

.form-error {
  margin-top: var(--space-2);
  color: var(--color-danger);
  font-size: 0.85rem;
}

/* ---------- 按钮 ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-md);
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
  transition: transform .15s, background-color .2s, box-shadow .2s;
  white-space: nowrap;
}

.btn:active { transform: translateY(1px) scale(0.98); }

.btn-primary {
  background: var(--color-primary);
  color: #fff;
  box-shadow: 0 2px 8px color-mix(in srgb, var(--color-primary) 30%, transparent);
}

.btn-primary:hover {
  background: var(--color-primary-dark);
  box-shadow: 0 4px 12px color-mix(in srgb, var(--color-primary) 40%, transparent);
}

.btn-ghost {
  background: transparent;
  color: var(--text-secondary);
  border: 1px solid var(--border-color);
}

.btn-ghost:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
}

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-md);
  font-size: 1rem;
  cursor: pointer;
  color: var(--text-secondary);
  transition: background-color .2s, transform .2s;
}

.icon-btn:hover {
  background: var(--bg-hover);
  transform: scale(1.08);
}

/* ---------- 统计 ---------- */
.stats { display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap; }

.stat-list {
  display: flex;
  gap: var(--space-4);
  flex: 1;
}

.stat {
  display: flex;
  flex-direction: column;
  min-width: 60px;
}

.stat dt { font-size: 0.75rem; color: var(--text-muted); }

.stat dd {
  font-size: 1.5rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--color-primary);
}

.progress-wrap { flex: 1 1 200px; }

progress {
  width: 100%;
  height: 8px;
  border: none;
  border-radius: 999px;
  overflow: hidden;
  accent-color: var(--color-primary);
}

progress::-webkit-progress-bar {
  background: var(--bg-hover);
  border-radius: 999px;
}

progress::-webkit-progress-value {
  background: linear-gradient(90deg, var(--color-primary), #ec4899);
  border-radius: 999px;
  transition: width .4s ease;
}

progress::-moz-progress-bar {
  background: linear-gradient(90deg, var(--color-primary), #ec4899);
  border-radius: 999px;
}

/* ---------- 任务列表 ---------- */
.task-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  list-style: none;
}

.task-item {
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--bg-page);
  border: 1px solid var(--border-color);
  border-left: 4px solid var(--color-primary);
  border-radius: var(--radius-md);
  transition: transform .2s, box-shadow .2s, opacity .3s;
  animation: taskIn .25s ease-out both;
}

@keyframes taskIn {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: translateY(0); }
}

.task-item:hover {
  transform: translateX(2px);
  box-shadow: var(--shadow-sm);
}

.task-item[data-priority="high"]   { border-left-color: var(--color-danger); }
.task-item[data-priority="normal"] { border-left-color: var(--color-primary); }
.task-item[data-priority="low"]    { border-left-color: var(--color-success); }

.task-item[data-done="true"] {
  opacity: 0.55;
  border-left-color: var(--text-muted);
}

.task-item[data-done="true"] .task-title {
  text-decoration: line-through;
  color: var(--text-muted);
}

/* 自定义复选框 */
.task-check {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  cursor: pointer;
  min-width: 0;
}

.task-check input[type="checkbox"] {
  position: absolute;
  opacity: 0;
  width: 1px; height: 1px;
}

.checkmark {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  border: 2px solid var(--border-color);
  border-radius: 6px;
  display: grid;
  place-items: center;
  transition: background-color .2s, border-color .2s, transform .15s;
}

.checkmark::after {
  content: "";
  width: 5px; height: 9px;
  border: solid #fff;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg) scale(0);
  transition: transform .15s;
  margin-top: -2px;
}

.task-check input:checked + .checkmark {
  background: var(--color-success);
  border-color: var(--color-success);
}

.task-check input:checked + .checkmark::after {
  transform: rotate(45deg) scale(1);
}

.task-check input:focus-visible + .checkmark {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.task-title {
  font-size: 0.95rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 元信息 */
.task-meta {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 0.75rem;
  color: var(--text-muted);
}

.badge {
  padding: 2px 8px;
  border-radius: 999px;
  font-weight: 600;
  font-size: 0.7rem;
}

.badge-high   { background: color-mix(in srgb, var(--color-danger) 15%, transparent); color: var(--color-danger); }
.badge-normal { background: color-mix(in srgb, var(--color-primary) 15%, transparent); color: var(--color-primary); }
.badge-low    { background: color-mix(in srgb, var(--color-success) 15%, transparent); color: var(--color-success); }

.task-item[data-done="true"] time { text-decoration: line-through; }

.task-delete { opacity: 0; transition: opacity .2s, transform .2s; }

.task-item:hover .task-delete,
.task-delete:focus-visible { opacity: 1; }

.task-delete:hover { color: var(--color-danger); }

/* ---------- 空状态 ---------- */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-8) var(--space-4);
  color: var(--text-muted);
  text-align: center;
}

.empty-state img { opacity: 0.6; }

/* ---------- 页脚 ---------- */
.app-footer {
  padding: var(--space-4) var(--space-6);
  text-align: center;
  font-size: 0.8rem;
  color: var(--text-muted);
  border-top: 1px solid var(--border-color);
}

.app-footer a { color: var(--color-primary); }
.app-footer a:hover { text-decoration: underline; }

.app-footer abbr { cursor: help; }

/* ---------- 弹窗 ---------- */
.dialog {
  border: none;
  border-radius: var(--radius-lg);
  padding: 0;
  background: var(--bg-card);
  color: var(--text-primary);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25);
  max-width: 420px;
  width: calc(100% - 32px);
}

.dialog::backdrop {
  background: rgba(15, 23, 42, 0.5);
  backdrop-filter: blur(4px);
  animation: fadeIn .2s ease;
}

@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }

.dialog[open] { animation: dialogIn .25s cubic-bezier(.4,0,.2,1); }

@keyframes dialogIn {
  from { opacity: 0; transform: translateY(16px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

.dialog-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-5);
}

.dialog-form h2 { font-size: 1.1rem; margin-bottom: var(--space-1); }

.dialog-form label {
  font-size: 0.85rem;
  color: var(--text-secondary);
  margin-bottom: calc(var(--space-1) * -1);
}

.dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

/* ---------- 深色主题切换过渡 ---------- */
* {
  transition-property: background-color, border-color, color;
  transition-duration: .25s;
  transition-timing-function: ease;
}

14.2 主题切换 JS(后续篇章详解)

javascript 复制代码
// js/main.js 片段
const themeToggle = document.getElementById('themeToggle');
const savedTheme = localStorage.getItem('taskflow.theme');

if (savedTheme === 'dark') {
  document.documentElement.setAttribute('data-theme', 'dark');
}

themeToggle.addEventListener('click', () => {
  const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
  if (isDark) {
    document.documentElement.removeAttribute('data-theme');
    localStorage.setItem('taskflow.theme', 'light');
  } else {
    document.documentElement.setAttribute('data-theme', 'dark');
    localStorage.setItem('taskflow.theme', 'dark');
  }
});

14.3 用到的 CSS 知识点索引

知识点 项目位置
CSS 变量 variables.css 全局
层叠与继承 全局 body、* 过渡
盒模型 / box-sizing reset.css
BFC / flow-root 页头 backdrop 隐含
Flex 页头、按钮、统计区、dialog-actions
Grid .task-form、.task-item、.panel
grid-template-columns: 1fr auto auto 任务项
定位 sticky .app-header
定位 absolute .task-check input 隐藏、::backdrop
z-index 页头
伪类 :hover :focus-visible :checked :not 多处
伪元素 ::after ::backdrop ::-webkit-progress-value 复选框、弹窗、进度条
属性选择器 [data-priority] [data-done] 任务项状态
transition 全局过渡
transform + translate + scale + rotate 复选勾、按钮、弹窗
@keyframes taskIn、fadeIn、dialogIn
linear-gradient logo 文字、进度条
color-mix() 主题色派生
clamp() / minmax() 响应式布局
aspect-ratio(可扩展) 图片
媒体查询 .task-form 移动端单列
prefers-reduced-motion 可加在末尾
backdrop-filter 页头、dialog backdrop
object-fit 图片(可扩展)
text-overflow: ellipsis 任务标题
font-variant-numeric 统计数字
逻辑属性 margin-inline 容器居中

14.4 关键视觉细节讲解

① 半透明毛玻璃页头

css 复制代码
background: color-mix(in srgb, var(--bg-card) 85%, transparent);
backdrop-filter: blur(12px) saturate(180%);

用 color-mix 让卡片色变成 85% 透明,配 backdrop-filter 实现 iOS 风格毛玻璃。

② 自定义复选框

原生的 checkbox 各浏览器样式不一,我们用:

css 复制代码
/* 隐藏原生 */
input[type="checkbox"] { position: absolute; opacity: 0; }
/* 用 span 自绘方框 */
.checkmark { border: 2px solid; border-radius: 6px; }
/* 用 ::after + 旋转做勾 */
.checkmark::after {
  content: ""; width: 5px; height: 9px;
  border: solid #fff; border-width: 0 2px 2px 0;
  transform: rotate(45deg) scale(0);
}
/* 勾选时放大 */
input:checked + .checkmark::after { transform: rotate(45deg) scale(1); }

这是纯 CSS 打勾动画的经典写法。

③ 任务状态用 data-* 驱动样式

css 复制代码
.task-item[data-priority="high"] { border-left-color: var(--color-danger); }
.task-item[data-done="true"] .task-title { text-decoration: line-through; }

JS 只需改 dataset.priority,样式自动跟随,样式与逻辑解耦。

④ 深色主题切换

variables.css 里的 [data-theme="dark"] 覆盖变量,html 上切换 data-theme 属性,所有引用变量的元素瞬间换色,无需重写任何组件样式。

⑤ 入场动画

css 复制代码
.task-item { animation: taskIn .25s ease-out both; }

新增任务时自动播放,both 让动画结束保留终态。

14.5 运行效果检查

打开 index.html 应看到:

  • 顶部毛玻璃导航栏,logo 渐变文字
  • 中间添加任务表单(桌面 4 列,手机单列)
  • 统计卡片 + 渐变进度条
  • 任务列表,左侧彩条表示优先级,hover 浮起
  • 勾选任务后变灰 + 删除线
  • 点击 🌙 切深色模式
  • 点击任务区(若 JS 已实现)弹出 dialog

14.6 Lighthouse 优化建议

跑一次 Chrome DevTools → Lighthouse,注意:

  1. 颜色对比度 :--text-muted 若太浅可能不达标,调整到 #64748b 以上
  2. 可点击区域:图标按钮至少 44×44px(本项目 36px,可加大)
  3. 字体可读性:正文不小于 16px(本项目 0.95rem ≈ 15.2px,可提升到 1rem)
  4. 动画 :追加 prefers-reduced-motion 规则

十五、本篇小结与练习

知识点回顾

模块 核心要点
引入方式 行内 / style / link,link 最优
选择器 基础、组合、属性、伪类、伪元素、:is/:where/:has
优先级 行内 > ID > 类/属性/伪类 > 元素/伪元素
层叠继承 来源→优先级→顺序;inherit/initial/unset
盒模型 content-box / border-box;margin 塌陷;BFC
常用属性 字体、文本、背景、边框、阴影、圆角
display block / inline / inline-block / flex / grid / none
定位 static / relative / absolute / fixed / sticky;层叠上下文
Flex 容器 6 属性 + 项目 3 属性 + 经典布局
Grid 行列定义 + 区域命名 + auto-fit/minmax
动画 transition、transform、@keyframes
变量函数 var()、calc()、clamp()、min/max、color-mix()
响应式 移动优先、媒体查询、clamp、容器查询、逻辑属性
新特性 嵌套、aspect-ratio、object-fit、scroll-snap、backdrop-filter

动手练习

  1. 基础 :用纯 CSS 做一个"汉堡菜单"图标(三横线变 X),要求用 ::before/::after 和 transform 过渡。
  2. 进阶 :用 Grid 实现一个"图片瀑布流"(grid-auto-rows + span),再用 Flex 实现同样效果对比。
  3. 挑战 :给 TaskFlow 加上"卡片视图/列表视图"切换,用 body[data-view="card"] 切换 Grid/Flex 布局,并加过渡动画。

常见坑清单

  • ❌ 忘记 box-sizing: border-box → 尺寸计算爆炸
  • ❌ 用 transition: all → 性能差、意外过渡
  • ❌ 父子 margin 塌陷没处理 → 布局错位
  • ❌ z-index 不生效 → 父级建了新层叠上下文
  • ❌ flex: 1 内部内容溢出 → 加 min-width: 0
  • ❌ 移动端 100vh 高度抖动 → 用 100dvh
  • ❌ 只写 :hover 不写 :focus-visible → 键盘用户体验差
  • ❌ 用 !important 抢救样式 → 恶性循环
  • ❌ 忽略 prefers-reduced-motion → 无障碍扣分
  • ❌ 颜色硬编码不抽变量 → 主题无法切换

下一篇预告

第三篇:JavaScript 基础语法全解

  • JS 的引入、执行环境、<script> 与模块
  • 变量 var/let/const 与作用域、TDZ、提升
  • 数据类型全解(7 种原始 + 引用)+ typeof
  • 类型转换(隐式/显式)
  • 运算符全解(算术、比较、逻辑、位、空值合并、可选链)
  • 流程控制(if/switch/for/while/for-in/for-of)
  • 函数(声明、表达式、箭头、参数、默认值、剩余、回调、纯函数)
  • 数组方法全解(map/filter/reduce/sort/...)
  • 对象、this、call/apply/bind
  • 错误处理、严格模式
  • 实战:用 JS 实现 TaskFlow 的 localStorage 与基础逻辑(第四篇进一步接 DOM 事件)

继续把第二篇的 CSS 保存好,第三篇我们让页面"动起来"。🚀

相关推荐
一木 之林1 小时前
Agent智能体学习总结:从一次调用到模型自主规划、工具调用与 ReAct 循环的项目实战-6/6
前端·人工智能·学习·react.js
程序员大阳1 小时前
副队长CSS教程(36)–移动布局与响应式
前端·css·响应式·媒体查询·移动布局
程序员Sunday1 小时前
React 的 useEffect 怎么工作?依赖数组、清理函数和重复执行如何理解?
前端·javascript
lank_M1 小时前
Word裁剪图片转HTML走样,该在渲染层修还是入口修
前端·图像处理·人工智能·计算机视觉·html·word
IT_陈寒1 小时前
深入理解Redis:核心原理与最佳实践
前端·人工智能·后端
Zhu7581 小时前
开源项目-Sablewisp-轻量、现代的 Chrome 书签管理扩展(Manifest V3)
前端·chrome
wespaul1 小时前
一条自然语言命令的 49 个节点:可视化编排与每段强校验
前端·数据库
OH_TPC1 小时前
【鸿蒙优选三方库】@ohos/axios:前端转鸿蒙,网络层几乎不用改
前端·华为·harmonyos·鸿蒙
程序员大阳1 小时前
副队长CSS教程(38)–transform 变换
前端·css·变换·transform