一份覆盖完整知识点的 HTML + CSS + JavaScript 前端学习笔记。重点讲"为什么这么设计"(费曼式 📌 讲解),配可直接运行的代码示例。
HTML (HyperText Markup Language) 是描述网页结构的标记语言。它不是编程语言,而是用标签定义内容的语义结构。
📌 打个比方:HTML 像建房子的图纸——它定义"这里是客厅、那里是卧室、这面墙是承重墙",但不关心墙刷什么颜色(那是 CSS 的活),也不关心门怎么开关(那是 JS 的活)。三者分工:HTML 管结构、CSS 管样式、JS 管行为。
| 元素 | 作用 |
|---|---|
<!DOCTYPE html> |
声明 HTML5 文档类型 |
<html lang="..."> |
根元素,lang 声明语言 |
<head> |
元数据区(不显示在页面上) |
<meta charset="UTF-8"> |
字符编码声明 |
<meta name="viewport"> |
移动端视口设置 |
<title> |
浏览器标签页标题 |
<body> |
可见内容区 |
📌 为什么 <!DOCTYPE html> 这么短:HTML4 的 DOCTYPE 要写一长串 DTD URL(因为 SGML 要求引用文档类型定义)。HTML5 不基于 SGML,DOCTYPE 只是告诉浏览器"用标准模式渲染",不需要 DTD 引用。简短声明 = 标准模式,省略 = 怪异模式(兼容老浏览器)。
HTML5 引入了一批语义化标签,替代通用的 <div>:
| 标签 | 语义 | 常见用途 |
|---|---|---|
<header> |
页头/区头 | 站点顶部、文章标题区 |
<nav> |
导航 | 菜单、面包屑 |
<main> |
主要内容 | 页面核心区域(每页唯一) |
<article> |
独立内容 | 文章、帖子、评论 |
<section> |
内容分区 | 按主题划分的区域 |
<aside> |
旁侧内容 | 侧边栏、广告、相关链接 |
<footer> |
页脚/区脚 | 版权信息、联系方式 |
<figure> |
图文组合 | 图片+说明文字 |
<time> |
时间 | 机器可读的日期 |
📌 语义化标签的好处:① 搜索引擎理解内容结构(SEO);② 屏幕阅读器为视障用户导航;③ 代码可读性高。<div class="header"> 对机器无意义,<header> 对机器有明确语义。
📌 <strong> vs <b>:<b> 只是视觉加粗,无语义;<strong> 表示"内容重要",屏幕阅读器会加重语气朗读。同理 <em> vs <i>。永远优先用语义标签,样式交给 CSS。
| type | 说明 | HTML5新增 |
|---|---|---|
text |
单行文本 | |
password |
密码(掩码显示) | |
email |
邮箱(带验证) | ✓ |
number |
数字(带步进器) | ✓ |
date / time / datetime-local |
日期/时间选择器 | ✓ |
color |
颜色选择器 | ✓ |
range |
滑块 | ✓ |
file |
文件上传 | |
checkbox / radio |
复选/单选 | |
hidden |
隐藏字段 |
📌 为什么 HTML5 新增这么多 input type:以前所有输入都是 text,验证全靠 JS。HTML5 让浏览器原生支持类型验证和专用 UI(如日期选择器),减少 JS 代码量,提升一致性和可访问性。
📌 为什么用 srcset:手机屏幕小但像素密度高(Retina),如果只给一张大图,手机下载浪费流量;只给小图,Retina 屏模糊。srcset 让浏览器根据屏幕尺寸和像素密度自动选最合适的图片。
📌 sandbox 属性:默认禁止 iframe 内的所有脚本执行、表单提交、弹窗等。通过白名单逐个放行需要的权限。这是防御 iframe 嵌入内容被恶意利用的安全机制。
CSS (Cascading Style Sheets) 控制网页的视觉表现——颜色、字体、布局、动画。核心机制:选择器 + 属性声明。
| 选择器 | 语法 | 示例 | 优先级 |
|---|---|---|---|
| 标签 | tag |
p {} |
0,0,1 |
| 类 | .class |
.btn {} |
0,1,0 |
| ID | #id |
#header {} |
1,0,0 |
| 属性 | [attr] |
[type="text"] {} |
0,1,0 |
| 后代 | A B |
div p {} |
合计 |
| 子代 | A > B |
div > p {} |
合计 |
| 相邻 | A + B |
h1 + p {} |
合计 |
| 通用 | * |
* {} |
0,0,0 |
| 伪类 | :hover |
a:hover {} |
0,1,0 |
| 伪元素 | ::before |
p::before {} |
0,1,0 |
📌 CSS 优先级计算:把选择器拆成 (ID数, 类数, 标签数) 三元组比较。#nav .item a = (1,1,1),.sidebar .item = (0,2,0)。从左到右比,左边大的胜出。行内样式 style="" = (1,0,0,0) 四元组,永远高于选择器。!important 是最后手段,会覆盖一切。
📌 为什么推荐 border-box:标准盒模型下,加 padding 会让元素变宽,布局容易溢出。border-box 让 width 就是最终宽度,所见即所得。全局设置 * { box-sizing: border-box; } 是前端标配。
| 属性 | 作用 | 值 |
|---|---|---|
flex-direction |
主轴方向 | row column row-reverse column-reverse |
justify-content |
主轴对齐 | flex-start center flex-end space-between space-around space-evenly |
align-items |
交叉轴对齐 | stretch flex-start center flex-end baseline |
flex-wrap |
换行 | nowrap wrap wrap-reverse |
flex-grow |
放大比例 | 数字(0=不放大) |
flex-shrink |
缩小比例 | 数字(1=可缩小) |
flex-basis |
初始大小 | auto 或具体值 |
order |
排列顺序 | 数字(默认0) |
📌 Flexbox 解决了什么:在 Flexbox 之前,垂直居中是 CSS 最头疼的问题——需要 position: absolute + 负 margin 或 line-height hack。Flexbox 只需 display: flex; align-items: center; justify-content: center; 三行搞定。它是一维布局的最佳方案。
| Flexbox | Grid | |
|---|---|---|
| 维度 | 一维(行或列) | 二维(行+列) |
| 适合 | 导航栏、工具栏、卡片行 | 整体页面布局、仪表盘 |
| 对齐 | 主轴+交叉轴 | 行+列精确控制 |
| 排序 | order |
grid-area 任意位置 |
📌 什么时候用 Grid 什么时候用 Flex:需要同时控制行和列 → Grid。只需要控制一个方向 → Flex。实际项目中外层用 Grid 做页面骨架,内层用 Flex 做组件布局,两者配合使用。
| 单位 | 说明 |
|---|---|
px |
绝对像素 |
% |
相对父元素 |
em |
相对自身/父元素字体大小 |
rem |
相对根元素(html)字体大小 |
vw / vh |
视口宽度/高度的 1% |
vmin / vmax |
视口较小/较大边的 1% |
clamp(min, val, max) |
在 min~max 范围内取 val |
📌 移动端优先 vs 桌面端优先:移动端优先(min-width 媒体查询)是现代做法——先写最小屏幕的样式,逐步增强。因为移动端设备性能弱,不需要的样式不应该加载。桌面端优先则是先写完整样式再做降级,容易产生冗余。
| 属性 | 是否触发重排 | 性能 |
|---|---|---|
transform |
否(GPU合成层) | 最好 |
opacity |
否(GPU合成层) | 最好 |
color / background |
仅重绘 | 好 |
width / height / margin |
重排 | 差 |
top / left |
重排 | 差 |
📌 为什么动画用 transform 而不是 top/left:改变 top/left 会触发浏览器重新计算布局(重排 Reflow),影响所有元素。transform 只在合成阶段处理(GPU 层),不触发布局计算。60fps 动画的秘诀:只用 transform 和 opacity。
JavaScript 是浏览器的脚本语言,控制网页行为。现在也通过 Node.js 运行在服务端。
📌 JS 和 Java 没关系:1995 年 Netscape 的 Brendan Eich 用 10 天设计出 JS,最初叫 Mocha → LiveScript → JavaScript。改名 JavaScript 纯粹是营销策略——蹭当时 Java 的热度。两者语法风格、类型系统、设计哲学完全不同。
📌 defer vs async:默认 <script> 会阻塞 HTML 解析。defer:异步下载,等 HTML 解析完后按顺序执行。async:异步下载,下载完立即执行(可能中断 HTML 解析)。99% 的情况用 defer,它保证脚本能访问完整 DOM 且按顺序执行。
📌 为什么不用 var:var 有两个坑——① 函数作用域(而非块级),变量泄漏到函数外;② 变量提升(hoisting),在声明前访问不报错而是 undefined。let/const 是块级作用域且存在暂时性死区(TDZ),声明前访问直接报错,更安全。
| 类型 | 类别 | 说明 |
|---|---|---|
String |
基本类型 | 字符串 |
Number |
基本类型 | 数字(整数+浮点,统一 64 位浮点) |
Boolean |
基本类型 | true / false |
undefined |
基本类型 | 未定义 |
null |
基本类型 | 空值(typeof 返回 "object",历史 bug) |
Symbol |
基本类型 | 唯一标识符(ES6) |
BigInt |
基本类型 | 任意精度整数(ES2020) |
Object |
引用类型 | 对象、数组、函数、Map、Set 等 |
📌 为什么推荐 === 而不是 ==:== 会做隐式类型转换,规则复杂且反直觉(0 == "" 为 true)。=== 严格比较,类型不同直接返回 false,行为可预测。永远用 ===,除非你确切知道为什么要用 ==。
| 区别 | 普通函数 | 箭头函数 |
|---|---|---|
this |
调用时决定 | 定义时继承外层 |
arguments |
有 | 无 |
new |
可构造 | 不可构造 |
yield |
可做生成器 | 不可 |
📌 箭头函数为什么没有自己的 this:箭头函数设计初衷就是解决回调中 this 丢失的问题。以前需要 var self = this 或 .bind(this) 来保存上下文。箭头函数直接继承词法作用域的 this,代码更简洁。但这也意味着它不适合做对象方法(this 不会指向对象)。
📌 闭包的本质:函数执行完毕后,其局部变量本应被回收。但如果内部函数被返回并持有对外部变量的引用,这些变量就不会被回收——这就是闭包。它像函数的"记忆",让函数能记住自己被创建时的环境。模块模式、柯里化、防抖节流都依赖闭包。
📌 Class 是语法糖:ES6 的 class 底层仍然是原型链继承,只是语法更接近传统面向对象语言。extends = Object.create(parent.prototype),super = Parent.call(this)。理解原型链才能真正理解 JS 的继承机制。
JS 是单线程的——同一时间只做一件事。网络请求、文件读取等耗时操作如果同步等待,整个页面会卡死。异步编程让 JS 在等待时能处理其他任务。
📌 async/await 的本质:它不是新的异步机制,而是 Promise 的语法糖。await 暂停函数执行等待 Promise resolve,async 函数自动返回 Promise。它让异步代码看起来像同步代码,消除了回调嵌套和 .then() 链的可读性问题。
📌 textContent vs innerHTML:innerHTML 解析 HTML 标签,如果内容来自用户输入,可能导致 XSS 攻击。textContent 只处理纯文本,标签会被转义显示。用户内容永远用 textContent。
📌 事件委托的好处:100 个 <li> 不需要绑 100 个监听器——在父元素 <ul> 上绑一个,利用事件冒泡统一处理。动态添加的 <li> 也能自动响应,不需要重新绑定。这是性能和可维护性的最佳实践。
📌 ES Module vs CommonJS:ESM 是浏览器原生支持的模块系统(import/export),静态分析可在编译期确定依赖关系(支持 Tree Shaking)。CommonJS(require/module.exports)是 Node.js 的模块系统,动态加载,不支持 Tree Shaking。现代前端开发统一用 ESM。
| 阶段 | 说明 |
|---|---|
| 解析 HTML | 构建 DOM 树 |
| 解析 CSS | 构建 CSSOM 树 |
| 渲染树 | DOM + CSSOM 合并,排除 display:none 的元素 |
| 布局 (Layout) | 计算每个元素的位置和大小 |
| 绘制 (Paint) | 将渲染树转为屏幕像素 |
| 合成 (Composite) | GPU 合成各图层 |
📌 重排 vs 重绘:改变几何属性(width/height/margin)触发重排(Layout → Paint → Composite 全流程)。改变视觉属性(color/background)只触发重绘(跳过 Layout)。改变 transform/opacity 只触发合成(GPU 层,最快)。性能优化的核心:减少重排,用 transform 代替位置变化。
| 优化 | 方法 |
|---|---|
| 减少请求 | 合并 CSS/JS、雪碧图、内联关键 CSS |
| 压缩 | Gzip/Brotli 压缩、图片 WebP/AVIF |
| 缓存 | HTTP 缓存头(Cache-Control/ETag) |
| 懒加载 | loading="lazy"(图片)、动态 import()(JS) |
| 预加载 | <link rel="preload"> 关键资源 |
| CDN | 静态资源分发到全球节点 |
📌 防抖 vs 节流:防抖 = "等你说完我再做"(搜索框输入,停止 300ms 后才搜索)。节流 = "固定间隔做一次"(滚动事件,每 100ms 处理一次,不管滚多快)。两者都减少高频事件的执行次数,选择取决于场景。
| API | 用途 |
|---|---|
fetch() |
网络请求(替代 XMLHttpRequest) |
localStorage / sessionStorage |
本地存储 |
IntersectionObserver |
元素可见性监听(懒加载) |
MutationObserver |
DOM 变化监听 |
WebSocket |
双向实时通信 |
Canvas / WebGL |
2D/3D 绘图 |
Web Workers |
后台线程 |
Service Worker |
离线缓存、推送通知 |
| 标签 | 说明 |
|---|---|
<div> |
通用块级容器 |
<span> |
通用行内容器 |
<a href=""> |
链接 |
<img src="" alt=""> |
图片 |
<ul>/<ol>/<li> |
列表 |
<table>/<tr>/<td>/<th> |
表格 |
<form>/<input>/<select>/<textarea> |
表单 |
<button> |
按钮 |
<video>/<audio> |
媒体 |
<canvas> |
画布 |
<iframe> |
内嵌框架 |
<header>/<nav>/<main>/<footer> |
语义化结构 |
| 属性 | 说明 | 常用值 |
|---|---|---|
display |
显示方式 | block inline flex grid none |
position |
定位 | static relative absolute fixed sticky |
margin/padding |
外/内边距 | px em auto |
border |
边框 | 1px solid #ccc |
border-radius |
圆角 | px % |
box-shadow |
阴影 | 0 2px 8px rgba(0,0,0,0.1) |
color |
文字颜色 | #333 rgb() hsl() |
background |
背景 | url() linear-gradient() |
font |
字体 | 16px/1.5 sans-serif |
text-align |
文字对齐 | left center right justify |
z-index |
层叠顺序 | 数字 |
overflow |
溢出处理 | visible hidden auto scroll |
transition |
过渡 | all 0.3s ease |
transform |
变换 | translate() rotate() scale() |
opacity |
透明度 | 0~1 |
| 对象/方法 | 说明 |
|---|---|
Array.map/filter/reduce |
数组变换/过滤/聚合 |
Array.forEach |
遍历 |
Array.find/findIndex |
查找 |
Array.includes |
包含判断 |
Array.flat/flatMap |
扁平化 |
Object.keys/values/entries |
对象键/值/键值对 |
Object.assign |
合并对象 |
Object.freeze |
冻结对象 |
JSON.parse/stringify |
JSON 解析/序列化 |
String.split/replace/match |
字符串操作 |
String.trim/padStart/padEnd |
字符串修剪/填充 |
Math.max/min/floor/ceil/random |
数学运算 |
Date.now/new Date() |
日期时间 |
Map/Set |
映射/集合(ES6) |
Promise |
异步编程 |
console.log/error/warn |
调试输出 |
| 技巧 | 方法 |
|---|---|
| Console | console.log() console.table() console.group() |
| 断点 | DevTools → Sources → 点击行号 |
| 条件断点 | 右键行号 → Add conditional breakpoint |
| DOM 检查 | F12 → Elements 面板 |
| 网络分析 | F12 → Network 面板 |
| 性能分析 | F12 → Performance 面板 → Record |
| 移动端调试 | F12 → Toggle device toolbar |
debugger |
代码中插入 debugger 语句自动断点 |
$0 |
DevTools 中引用最后选中的元素 |