Fullstack 面试复习笔记:HTML / CSS 基础梳理
之前的笔记:
- Fullstack 面试复习笔记:操作系统 / 网络 / HTTP / 设计模式梳理
- Fullstack 面试复习笔记:Java 基础语法 / 核心特性体系化总结
- Fullstack 面试复习笔记:项目梳理总结
- Fullstack 面试复习笔记:Spring / Spring Boot / Spring Data / Security 整理
- SCSS的学习笔记
本来是想把H5C3JS的东西放一起整理的,然后看了下有点长……
毕竟主自用,还是先拆开来方便自己复习了
HTML 基础
meta tag
<meta>
tag 是 HTML 中用于提供页面元数据(metadata)的标签,它不会直接显示在页面中,但会被浏览器、搜索引擎、社交平台等工具读取。
常见用途包括:
设置字符编码(charset)
控制 viewport(响应式布局)
设置 SEO 信息(如 description, keywords)
定义页面作者
配置浏览器行为(如
http-equiv
)常见的
<meta>
& 用法<!-- 设置字符编码,防止乱码问题 --> <meta charset="UTF-8" /> <!-- 响应式设计,配合 viewport 缩放行为 --> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <!-- SEO:定义页面描述 --> <meta name="description" content="A lightweight e-commerce site built with React and Node.js" /> <!-- SEO:定义关键字(现在搜索引擎不怎么用)--> <meta name="keywords" content="React, Node.js, MongoDB, E-commerce" /> <!-- 定义作者 --> <meta name="author" content="Louise Han" /> <!-- 控制缓存策略 --> <meta http-equiv="cache-control" content="no-cache" />
semantic syntax
Semantic tags 是指那些 带有语义(semantic meaning) 的 HTML 标签,它们告诉浏览器、开发者和 assistive technology(如 screen reader)“这块内容的作用是什么”。
常见的语义标签
标签 用途说明 释义 <header>
页面或 section 的头部区域 页眉区域 <nav>
网站导航栏 导航栏 <main>
页面主内容,唯一出现一次 主体内容 <section>
拥有独立主题的一块内容 内容区块 <article>
独立的文章、博文、论坛贴文等 独立内容 <aside>
与主内容相关但不直接相关的信息(如侧边栏) 侧边信息 <footer>
页面或 section 的底部区域 页脚 <figure>
/<figcaption>
图像 + 图说 图片配文 <time>
时间元素,可被机器读取 机器可识别的时间 <mark>
高亮文本 高亮词汇(搜索匹配) 为什么使用 Semantic Tags
- 对搜索引擎友好(Better SEO)
- 对 screen reader 更友好(提升 Accessibility)
- 可读性提升,便于团队协作和维护
- 明确结构,有助于浏览器默认样式渲染(如
<nav>
默认有焦点样式)
常见 input type
text
:单行文本输入(默认类型)password
:密码输入,用户输入内容会以圆点/星号显示email
:必须为邮箱格式,会启用浏览器校验url
:必须为合法的 URL(浏览器校验)number
:只能输入数字,可配合min
、max
、step
tel
:电话号码输入,不会强制格式校验,但移动端会弹出数字键盘search
:语义上表示搜索,功能上类似 text,可提供清除按钮(某些浏览器)date
:选择日期(浏览器弹出日期选择器)time
:选择时间datetime-local
:选择本地时间和日期month
:选择月份week
:选择第几周checkbox
:复选框,可多选,值为true
/false
radio
:单选按钮(需要name
相同才能形成互斥组)range
:滑动条(可配合 min/max/step)file
:文件上传,accept
可限定类型color
:颜色选择器,返回 HEX 色值hidden
:隐藏字段(不显示在页面上,但提交时会包含)可以传递包括用户id、CSRF Token之类的字段
注意不要放敏感信息,毕竟还是可以被JS所访问的
datalist vs options
特性 | <datalist> + <input> |
<select> + <option> |
---|---|---|
是否可自由输入 | ✅ Yes(可选或自填) | ❌ No(只能选择) |
外观可定制性 | 基于 <input> ,可定制性高 |
原生样式难以改造 |
表单提交值 | 仅提交 <input> 的值 |
提交 <select> 的选中值 |
使用场景 | 搜索框、模糊匹配、辅助推荐 | 下拉菜单、选项限定 |
datalist的用法:
<label for="browser">Choose your browser:</label>
<input list="browsers" name="browser" id="browser">
<datalist id="browsers">
<option value="Chrome">
<option value="Firefox">
<option value="Safari">
<option value="Edge">
</datalist>
select+options的用法:
<select name="fruit">
<option value="apple">Apple</option>
<option value="banana">Banana</option>
<option value="mango" selected>Mango</option>
</select>
form vs div
维度 | <form> |
<div> |
---|---|---|
语义(Semantics) | 表示“表单提交区域” — 属于结构语义标签之一 | 没有语义,只是一个容器 |
默认行为 | 提交时会触发表单事件、支持 submit 操作 |
不会自动触发提交行为 |
可访问性支持 | 默认被 Assistive Technology 识别为表单 | 屏幕阅读器不会当做表单处理 |
事件行为支持 | 可监听 onSubmit 事件 |
没有 submit 行为 |
可与按钮协作 | <button type="submit"> 可直接触发表单提交 |
必须手动添加 JS 才能模拟提交 |
浏览器原生校验 | 支持如 required 、pattern 等自动校验 |
不支持,需要自己写 JavaScript 校验逻辑 |
标签嵌套规则 & DOM 结构
HTML 并不是可以随意嵌套标签的语言,浏览器会根据 HTML 规范对结构做自动修正。如果标签嵌套不当,可能会出现异常、访问性问题,和语义化校验失败
基础语义分类
分类 示例标签 描述说明 Metadata content <title>
,<style>
,<meta>
用于页面 <head>
内,定义页面元信息Flow content 绝大多数标签(如 <div>
,<p>
,<ul>
)通常可出现在 <body>
内的所有内容Sectioning content <section>
,<article>
,<nav>
,<aside>
定义页面结构和内容区块,具有 outline 层级意义 Heading content <h1>
–<h6>
用于标识内容标题,必须嵌套在 Sectioning Content 中 Phrasing content <span>
,<a>
,<strong>
,<img>
行内文本及格式化元素,用于构成段落内部的细节内容 Embedded content <iframe>
,<img>
,<video>
嵌入其他资源的标签 Interactive content <a>
,<button>
,<details>
具备交互能力的元素,不应彼此嵌套 Form-associated content <input>
,<textarea>
,<form>
与表单行为有关的控件或容器 List content <ul>
,<ol>
,<li>
有序或无序列表 通用嵌套规则
外层元素语义类型 可嵌套的内容类型 不合法的内容类型(应避免) 备注 / 举例 Sectioning content Flow content、Heading content Metadata content <article><h2>Title</h2><p>text</p></article>
Heading content Phrasing content Block-level content(如 <div>
,<p>
)<h1><em>Title</em></h1>
✅Flow content Sectioning、Heading、Phrasing、Embedded、Interactive Metadata content 几乎可嵌套任何主体内容 Phrasing content 其他 phrasing content(span、a、strong) Block-level content <p><span>hello</span></p>
✅List container ( <ul>
/<ol>
)<li>
(唯一直接子元素)<div>
、直接文本、其他 block(除非包裹在<li>
中)❌ <ul><div>错</div></ul>
✅<ul><li><div>合法</div></li></ul>
<li>
元素Flow content(包括 p、div、a、ul) 仅 metadata <li><p>Item</p></li>
✅<form>
元素Flow content、Form-associated content(不能嵌套 <form>
)<form>
<form><input /></form>
✅❌<form><form>错</form></form>
<p>
元素Phrasing content Block-level content(div、ul、table) <p><strong>Yes</strong></p>
✅❌<p><div>No</div></p>
Interactive content(a, button) Phrasing(text、span、img) 其他 interactive(a、button) ❌ <a><button>错误</button></a>
✅<button><span>确定</span></button>
一些个人的总结 & 反思
span
不是一定要嵌套在p
里使用span
负责的还是段落内做标记使用,只不过大多数情况下这个段落直译成了 paragraph,也就是p
标签。不过从其他的UI库中也可以看到,不少的UI库直接使用span
做样式——比如说封装成button交互元素之间的嵌套
其实之前没注意到这个问题,一直到写React的时候碰到了,就是
a
标签 → 由 React Router DOM 提供的Link
和button
嵌套的时候出现了问题,就是重定向不工作找了一下才发现,HTML规定了交互元素(interactive content)不能互相嵌套,否则会发生不可预期的问题,在我当时的情况下就是重定向失败,点击没有任何的反应
React本身是不会修正这种问题的,所以实现的时候还是需要注意一下……本地没有报错是运气好,特别是现在本地开发环境React会渲染两次,这个情况确实mask了很多问题。上了production再出现问题就糟糕了……
表单标签进阶
对于 label
、fieldset
、legend
这些 表单进阶标签,它们主要起的是结构化和可访问性(accessibility)优化的作用,只需要熟悉它们的作用和用法场景即可
<label>
作用:用于描述表单控件的含义(文本说明)
常用写法:
<label for="username">Username</label> <input type="text" id="username" /> <label> Username <input type="text" /> </label>
优势:
- 点击 label 可以自动聚焦对应 input
- 提升可访问性(屏幕阅读器友好)
<fieldset>
作用:将多个表单控件逻辑分组,用于视觉区块化和辅助语义划分
使用场景:例如“个人信息”、“支付方式”这样的分块区域
通常搭配
<legend>
使用示例:
<fieldset> <legend>Personal Info</legend> <label for="name">Name:</label> <input id="name" type="text" /> <label for="age">Age:</label> <input id="age" type="number" /> </fieldset>
<legend>
- 作用:为
<fieldset>
提供标题说明,是视觉和语义上的「小标题」 - 注意事项:
<legend>
只能直接作为<fieldset>
的第一个子元素出现- 不建议单独使用
<legend>
,它没有独立语义意义
- 作用:为
Accessibility (A11Y)
Accessibility(可访问性)指的是:**确保网页内容对所有用户都可用,包括视障、听障或行动不便的用户;**常见实践不仅提升用户体验,也有助于 SEO
核心目标
- 页面结构 语义清晰,便于辅助技术(如屏幕阅读器)识别
- 所有交互元素都能被 键盘导航
- 提供 文字替代(alt text) 以支持非视觉用户
- 使用合适的ARIA 属性增强语义(仅在 HTML 不够时使用)
实用标签
标签 功能 label
关联表单元素,提升 screen reader 识别准确性 fieldset
+legend
对表单区域进行语义分组和说明 button
明确的交互控件,优于滥用 <div>
/<a>
a
(超链接)应该有明确 href
,避免仅作按钮用nav
,header
,main
,footer
结构语义清晰,有助 assistive tech 理解页面 alt
(图片说明)为 img
提供描述内容或说明装饰性(如alt=""
)推荐实现
- 为所有图片添加
alt
描述 - 使用语义化 HTML 结构
- 交互元素需可用键盘访问
- 使用
<button>
、<input>
等原生可交互元素 - 避免用
<div>
模拟点击(无法 tab focus) - 如必须自定义组件,添加
tabindex="0"
和role="button"
- 使用
- 添加 Skip to Content 跳转锚点(推荐大项目)
- 为所有图片添加
ARIA(Accessible Rich Internet Applications)
ARIA 是补充机制,优先使用原生语义标签
ARIA的使用方式包括:
属性 用途 aria-label
给元素添加可识别名称 aria-hidden="true"
隐藏不重要的视觉装饰元素 role
补充 HTML 结构中缺失的语义,例如 role="dialog"
aria-live
通知 screen reader 某区域内容动态更新
HTML 加载顺序与性能
浏览器加载顺序是 HTML → CSS → JS,即:
- 自上而下解析 HTML
- 遇到
<link rel="stylesheet">
:阻塞渲染(必须等待 CSS 下载 & 解析) - 遇到
<script>
(无async
/defer
):阻塞解析(必须等待 JS 执行完,才继续解析 HTML)JS前如果有CSS文件,并且CSS尚未加载完毕,那么JS会等到CSS加载完成后再执行
因此传统做法——在
defer
未出现时——是将JS放到<body>
最底部,让HTML先完成解析,渲染部分UI现代开发则是通过使用
defer
+ 将 script 放在<head>
,配合模块化打包(vite/webpack)实现更好的加载性能与维护行<script>
加载方式对比属性 是否阻塞 HTML 解析 执行时机 执行顺序 使用场景 默认 ✅ 阻塞 下载完立即执行 顺序执行 样板页 script、页面逻辑入口 async ❓ 不完全阻塞 下载时不阻塞解析 但是下载完成后,执行时会阻塞 下载完立即执行(⚠ 无顺序) ⚠️ 不保证顺序 独立脚本(如广告/统计脚本) defer ❌ 不阻塞 DOM 全解析后、DOMContentLoaded 前执行 顺序执行 页面初始化逻辑推荐使用 preload ❌ 不执行,仅预取 N/A N/A 提前加载 JS,但需配合 <script>
- 解析完成后,构建 DOM、CSSOM → 生成 Render Tree → 触发绘制 &布局
CSS 样式机制
CSS 选择器分类
类型 | 示例 | 说明 | Specificity 权重 |
---|---|---|---|
通配选择器 | * |
匹配所有元素 | 0,0,0,0 |
元素选择器(Element) | div , p , a |
匹配特定标签 | 0,0,0,1 |
类选择器(Class) | .card , .active |
匹配指定 class 的元素 | 0,0,1,0 |
属性选择器(Attribute) | [type="text"] |
匹配指定属性的元素 | 0,0,1,0 |
伪类选择器(Pseudo-class) | :hover , :nth-child(2) |
选择特定状态 | 0,0,1,0 |
ID 选择器(ID) | #header , #app |
匹配特定 ID 的元素 | 0,1,0,0 |
伪元素(Pseudo-element) | ::before , ::after |
针对元素插入虚拟节点 | 0,0,0,1 (同元素选择器) |
组合选择器(Combinator) | div .title , ul > li |
父子/兄弟等嵌套结构 | 权重相加(逐个计算) |
优先权最高:内联样式 | style="color: red;" |
直接写在元素上 | 1,0,0,0 (最高) |
!important (特例) |
color: red !important |
不属于 specificity,但强制优先 | 会覆盖正常权重规则(除非被另一条更强的 !important 覆盖) |
CSS Specificity 是 4 维度权重,记作 a,b,c,d
:
a
:是否为内联样式 →1,0,0,0
b
:ID 选择器数量c
:Class、属性、伪类d
:标签选择器、伪元素
box model
Box Model 是 HTML 元素在页面中所占空间的数学模型。
每个元素都可以看作一个矩形盒子,由以下几部分组成:
(Outline - 不占空间)
+---------------------------+
| Margin |
| +---------------------+ |
| | Border | |
| | +---------------+ | |
| | | Padding | | |
| | | +--------+ | | |
| | | | Content | | | |
| | | +--------+ | | |
| | +---------------+ | |
| +---------------------+ |
+---------------------------+
层级 | 是否占据空间 | 描述说明 |
---|---|---|
outline |
❌ 否 | 仅视觉效果,不影响布局,常用于焦点提示 |
margin |
✅ 是 | 元素与外部元素的距离 |
border |
✅ 是 | 包裹 padding + content 的边线 |
padding |
✅ 是 | 内容与边框之间的内边距 |
content |
✅ 是 | 实际显示文本/图片的区域 |
标准盒模型(content-box)→ 默认
width
为 content的宽度,所以计算的时候需要通过 c o n t e n t + p a d d i n g + b o r d e r content + padding + border content+padding+border 的方式去计算替代盒模型(border-box)→ 推荐
width
为 c o n t e n t + p a d d i n g + b o r d e r content + padding + border content+padding+border 的宽度,即元素的整体宽度,计算起来相对省心也是现代CSS框架的默认计算方式
display
display
定义了元素的布局行为,是 CSS 中最基础也最重要的属性之一。它决定了元素如何参与文档流以及是否能成为容器
属性值 | 说明 |
---|---|
block |
块级元素,占满整行,可设置宽高(如 <div> ) |
inline |
行内元素,不可设置宽高(如 <span> ) |
inline-block |
兼具行内与块级特性,可并排也可设置宽高 |
none |
元素隐藏且不参与渲染,不占据空间 |
flex |
启用 Flex 一维弹性布局容器 |
inline-flex |
行内弹性容器,可与文字并排显示 |
grid |
启用 Grid 二维网格布局容器 |
inline-grid |
行内网格容器 |
table |
模拟表格布局行为 |
contents |
不渲染元素自身,只保留子元素结构(⚠ 有兼容性问题) |
list-item |
元素表现为列表项,通常带有 • 符号 |
常见场景推荐:
- 页面区域布局 → 推荐使用
flex
或grid
- 水平排布多个组件 → 使用
inline-block
或flex
- 条件渲染 → 用
display: none
控制显示与隐藏
position 定位机制
position
定义元素脱离文档流的方式,影响其在页面中的位置计算方式
属性值 | 说明 |
---|---|
static |
默认值,按照文档流正常排列 |
relative |
相对自身原位置偏移,可配合 top/right/bottom/left 使用 |
absolute |
相对最近的非 static父元素定位,脱离文档流 |
fixed |
相对于 视口(viewport) 定位,常用于吸顶、悬浮按钮 |
sticky |
在滚动时在 relative 与 fixed 之间切换,实现“粘性”效果 |
配套偏移属性(仅 relative
/ absolute
/ fixed
/ sticky
有效):
top: 10px;
left: 20px;
right: 0;
bottom: auto;
注意:
absolute
必须有明确定位上下文,否则会相对body
定位fixed
不随滚动条滚动,适合做悬浮按钮sticky
需要设置top
或其他边界,且外层容器不能有overflow: hidden
实用技巧:
经典居中方法:
.centered { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }
粘性标题栏:
header { position: sticky; top: 0; background: white; }
column layout
允许将一个元素的内容分成多个列,类似报纸排版
核心属性包括:
属性名 | 说明 |
---|---|
column-count |
指定列的个数 |
column-width |
指定每列的理想宽度(浏览器会根据实际情况调整) |
columns |
简写形式:columns: column-width column-count; |
column-gap |
列与列之间的间隙(默认 1em ) |
column-rule |
列之间的分隔线(包含宽度、样式、颜色) |
break-inside |
控制子元素是否可中断换列(避免被拆开) |
它的限制与注意事项:
特点 | 说明 |
---|---|
❌ 支持不如 Flex/Grid 丰富 | 无法灵活控制每列内容的对齐、分布 |
❌ 不支持嵌套列 | 嵌套结构时可能会失效或排版错乱 |
✅ 非常适合内容流排版 | 如长文本、段落内容、简报式展示 |
flex layout
Flex 是一种一维布局系统,擅长处理 主轴方向的对齐、伸缩、排序等问题。核心概念是容器(flex container)和项目(flex item)
启用flex的方法比较简单,将 display改成flex即可:
.container { display: flex; /* 或 inline-flex */ }
这样所有的自元素都自动成为flex item
主轴方向控制使用
flex-direction
:.container { flex-direction: row | row-reverse | column | column-reverse; }
换行控制使用
flex-wrap
:.container { flex-wrap: nowrap | wrap | wrap-reverse; }
主轴对齐:
justify-content
.container { justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly; }
交叉轴对齐使用
align-items
:.container { align-items: stretch | flex-start | flex-end | center | baseline; }
现在比较流行的一种水平/垂直的实现方法,就是使用
justify-content
+align-items
实现的多行对齐:
align-content
.container { align-content: stretch | flex-start | flex-end | center | space-between | space-around; }
子项控制:
flex
简写.item { flex: [flex-grow] [flex-shrink] [flex-basis]; }
子项对齐(覆盖 align-items):
align-self
.item { align-self: auto | flex-start | flex-end | center | baseline | stretch; }
间距控制:
gap
.container { gap: 1rem; /* 行列统一间距 */ row-gap: 10px; /* 仅行间距 */ column-gap: 20px; /* 仅列间距 */ }
grid layout
Grid 是一种 二维布局系统,适合处理复杂网格、区域布局等需求。与 Flex 不同,Grid 可以同时控制行(row)和列(column)
启用 Grid 布局
.container { display: grid; /* 或 inline-grid */ }
定义网格行与列
.container { grid-template-columns: 100px 1fr 2fr; /* 列宽 */ grid-template-rows: auto 50px; /* 行高 */ }
设置间距:
gap
.container { gap: 10px; /* 同时设置行列间距 */ row-gap: 10px; column-gap: 20px; }
放置子项:行列定位
.item { grid-column: 1 / 3; /* 第1列开始到第3列前结束(跨2列) */ grid-row: 2 / span 2; /* 从第2行开始,跨2行 */ }
命名区域(推荐)
.container { grid-template-areas: "header header" "sidebar main" "footer footer"; } .item-header { grid-area: header; }
自动排列:
auto-fill
与auto-fit
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
对齐内容
.container { justify-items: start | center | end; align-items: start | center | end; }
column vs flex vs grid
特性 | Column Layout | Flexbox | Grid |
---|---|---|---|
排版方式 | 垂直分栏 | 一维(行或列) | 二维(行 + 列) |
控制力 | ⭐️ 中等 | ⭐️⭐️⭐️ 强 | ⭐️⭐️⭐️⭐️ 最强 |
内容流动 | 自动分流 | 子项自己布局 | 显式定义区域 |
使用场景 | 报纸式文本 | UI组件对齐 | 页面布局骨架 |
响应式布局&媒体查询
响应式设计是指页面可以根据不同屏幕尺寸、分辨率和设备特性自动调整布局与样式,从而提供良好用户体验的一种设计理念
核心目标
- 同一个 HTML 页面,适配不同设备(手机、平板、桌面)
- 自动调整布局、字号、边距、组件显示/隐藏等
- 避免内容“溢出”或“太小看不清”
实现方法
主要通过media query去做,基础的模板代码为:
@media <媒体类型> and (<条件>) { /* 只在满足该条件下才生效 */ }
如:
/* 屏幕宽度小于等于 768px(平板及以下) */ @media (max-width: 768px) { .sidebar { display: none; } } /* 屏幕宽度大于等于 1024px(桌面端) */ @media (min-width: 1024px) { body { font-size: 16px; } }
常用断点
断点类型 宽度范围(参考值) 用途 Extra small ( xs
)< 576px
手机竖屏 Small ( sm
)≥ 576px
手机横屏 Medium ( md
)≥ 768px
平板设备 Large ( lg
)≥ 992px
小型桌面 Extra large ( xl
)≥ 1200px
常规桌面 XXL ( xxl
)≥ 1400px
大屏显示器 响应式单位 &技巧补充
单位 说明 %
相对于父元素的宽/高 vw
视口宽度的百分比(100vw = 屏幕宽) vh
视口高度的百分比(100vh = 屏幕高) em/rem
字体相对单位,适用于字号随屏幕变小自动缩放 clamp()
设定最小、推荐值、最大值,实现响应式字体大小: clamp(14px, 2vw, 18px)
响应式布局技巧
使用
flex-wrap: wrap
或 Grid 布局 +auto-fit
使用
gap
代替传统margin-right
/padding
合理隐藏某些组件:
@media (max-width: 768px) { .menu-sidebar { display: none; } }
用容器类限制最大宽度(如
max-width: 1200px; margin: 0 auto;
)
Mobile First
目前responsive design的主流策略,核心理念是从小屏幕(如手机)出发设计 UI,再逐步为大屏幕添加增强样式
这种设计用
max-width
更加的合适,反之,如果从 desktop first 则用min-width
BEM 命名
BEM 是一种 结构化命名规范,用于让 CSS 类名清晰表达组件结构与状态,便于维护、避免冲突
部分 | 描述 | 示例 |
---|---|---|
Block | 独立的功能模块(可以单独复用) | card , nav , form |
Element | Block 内部的组成部分 | card__title , nav__item |
Modifier | 表示 Block 或 Element 的状态 / 变体 | card--highlighted , button--disabled |
如:
/* Block */
.button {}
/* Element:使用两个下划线 */
.button__icon {}
/* Modifier:使用两个连字符 */
.button--primary {}
.button__icon--large {}
一般来说用BEM的话,写原生CSS比较多,或者是需要构建比较大的UI库这种情况,我们项目的话,因为有自己的UIF(UI Framework),所以反而会比较多的依赖UIF的实现,有需要重在的情况BEM也帮不上什么忙,就用JSX里的inline css搞定了
SCSS/SASS 简述
底层编译器相同:两者都使用 Dart Sass(现在是官方唯一支持的实现),不过实现的格式有些许的不同:
特性 | SASS (.sass) | SCSS (.scss) |
---|---|---|
语法风格 | 缩进式(无大括号、分号) | 类似 CSS(用大括号和分号) |
可读性 | 更简洁,偏向 Ruby 风格 | 更接近原生 CSS,学习曲线低 |
支持程度 | 老项目可能使用 | 新项目主流使用 |
推荐程度 | 可选(老项目或喜欢极简) | ✅ 推荐(兼容性、迁移、团队协作) |
变量定义
$primary-color: #3498db; .button { background: $primary-color; }
嵌套规则(Nested Rules)
.navbar { ul { list-style: none; } li { display: inline-block; } }
Mixin(类似函数,可传参)
@mixin flex-center { display: flex; justify-content: center; align-items: center; } .container { @include flex-center; }
Extend(继承已有样式)
%base-button { padding: 0.5rem 1rem; border-radius: 4px; } .btn-primary { @extend %base-button; background-color: blue; }
条件和循环(Control Directives)
$themes: light, dark, blue; @each $theme in $themes { .theme-#{$theme} { // 动态类名 } }
过渡
元素状态变更时的过渡,一般与 :hover
、:focus
等伪类配合使用,如:
.button {
transition: all 0.3s ease-in-out;
}
.button:hover {
transform: scale(1.05);
}
具体结构为:
transition: <property> <duration> <timing-function> <delay>;
动画
animation
:关键帧动画(更复杂),使用方法如下:
@keyframes fade-in {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.card {
animation: fade-in 0.6s ease forwards;
}
具体结构为:
animation: <name> <duration> <timing-function> <delay> <iteration-count> <direction> <fill-mode>;
常见参数:
infinite
:无限循环alternate
:来回动画forwards
:保留最后状态(常用!)
animation vs. transition
点 | transition |
animation |
---|---|---|
用途 | 简单状态切换(如 hover) | 复杂序列动画 |
触发方式 | 被动(如鼠标 hover) | 可自动播放(无须交互) |
控制方式 | 仅开始状态和结束状态 | 多帧(keyframes) |
写法复杂度 | 低 | 中高 |
视觉可访问性 Visual Accessibility
重要性:
- WCAG(Web Content Accessibility Guidelines)明确要求视觉元素满足对比和聚焦可见性要求
- 企业级产品(尤其 B2B/Gov)经常要通过 A11y 审核
- Tailwind / Chakra / MUI 等现代框架已经内建
颜色对比 color contrast
元素类型 最低对比度比值 正文文字 4.5:1 粗体大文字(≥18px bold / 24px regular) 3:1 UI 组件边界(如按钮边框) 通常建议 ≥ 3:1 检查工具包括:
- WebAIM Contrast Checker
- Figma 的 A11y 插件
- VS Code 插件:WCAG Color Contrast Checker
焦点可见性 focus outline
目标用户:键盘用户(Tab键导航者)、辅助技术用户
推荐实现方法:
button:focus, a:focus { outline: 2px solid #2684FF; outline-offset: 2px; }
outline
: 视觉边框,不占空间,适合可访问性标示outline-offset
: 将 outline 往外或内偏移,不会遮住按钮内容- ⚠️ 如果用了
outline: none
,必须自己补上焦点状态的视觉标识(如box-shadow
、border
等),否则违反可访问性规范
图片与alt文字,之前提过
可感知的状态变化(Visible State Change)
仅靠颜色可能不太明确,正确方法推荐:
**<input type="email" aria-invalid="true" /> <span class="error">邮箱格式不正确</span>**
这个应该是针对色盲/色弱做的优化
深色模式支持 Dark Mode Support
属于现代设计中的视觉舒适性优化,对于光敏感用户尤为关键
字体大小 / 可缩放性(Zoom & Font Size)
页面应支持最高到 200% 的缩放,仍能正常操作和阅读
那……很多网页应该是做不到的……
认知可访问性(Cognitive Accessibility)
- 避免使用动图、闪烁图像(容易引发癫痫/认知负担)
- 避免使用过多动画(结合
prefers-reduced-motion
) - 保持按钮文本明确(如“提交表单”比“点我一下”更清晰)