1. 注释这件事,真的不该被轻视
入行前端这些年,代码写过不少,code review也做了很多次,有个现象我一直很困惑:很多开发者对注释的态度非常两极分化。一种是完全不爱写注释,代码交上去像天书,过两周自己都看不懂;另一种是注释写得太“水”,满屏都是“// 定义一个变量”“// 循环遍历”这种废话,代码本身已经表达得很清楚的东西,再用注释说一遍,反而干扰阅读。
我自己的看法是:注释是代码的一部分,而且是极其重要的一部分。它承载的是代码无法表达的信息——这段代码为什么要这么写、在什么业务背景下诞生、有哪些坑需要注意、未来的扩展方向是什么。代码负责告诉机器“怎么做”,注释负责告诉下一个开发者“为什么这么做”。两者缺一不可。
这篇文章把我这些年写 HTML 注释、以及前端开发中各个场景下的注释实践经验,系统梳理一下。包括 HTML 里的注释写法、CSS/JS 的注释规范、团队协作里的提交注释规范、还有 VSCode 和 IDEA 的注释模板配置、乱码排查这些实操向的内容。不管是刚入门的初学者,还是带团队的技术负责人,应该都能从中找到一些可用的东西。
2. HTML 注释的写法,从基础语法到高级场景
2.1 基础语法:注释标签的规则和边界
HTML 注释的语法很简单,就是<!-- 注释内容 -->。但这简单背后有几个细节值得注意。
第一个细节是注释标签内部不能出现两个连续的连字符--。HTML 规范明确规定,注释内容不能包含--,因为解析器会把它当作注释结束符的一部分。实际开发中在 HTML 注释里写诸如“这是一个 -- 特殊场景”这类内容,浏览器解析时大概率会把注释提前截断,后面的代码全部变成页面内容展示出来,导致布局错乱。
第二个细节是注释不能嵌套。<!-- 外层注释 <!-- 内层注释 --> 外层继续 -->这种写法在 HTML 里是非法的,第一个-->就会让注释结束,后面的内容全部暴露成页面文本。需要临时屏蔽一段包含注释的代码时,得先把内部注释删掉,或者改用其他方式,比如用 CSSdisplay: none临时隐藏元素、用 JavaScript 注释掉脚本逻辑。
第三个细节是注释会占用文档体积。虽然现代浏览器对注释的解析消耗可以忽略,但如果一个 HTML 文件里堆积了大量历史遗留注释,文件体积会增大不少。在移动端弱网环境下,每多一个字节都是成本。生产环境的文件建议用构建工具(如html-minifier)统一剥离注释。
<!-- 正确的注释写法 --> <div class="header">页面头部区域</div> <!-- 下面这种写法是错的,会在浏览器里产生解析错误 --> <!-- 注释内容 — 这里有两个连字符 -- 会导致解析异常 -->2.2 结构化注释:用注释给 HTML 分区,提升可读性
痛点场景:一个页面几百行甚至上千行 HTML,没有注释的情况下,要找到某一个模块的开头和结尾非常费力。Ctrl+F 搜索 class 名是一种办法,但遇到动态拼接 class 或者重复嵌套的模块就失效了。
我个人的习惯是给每个页面区块写结构注释,分为下面三类。
第一类是“抬头注释”,写在 HTML 文件最顶部,说明页面名称、作者、创建时间、依赖资源、修改历史。这类似一个文件的“身份铭牌”,让任何人打开文件第一眼就能了解到基本信息。
<!-- 页面名称:商品列表页 创建时间:2024-03-15 修改记录:2024-05-20 增加促销模块 依赖资源:main.css / product.js -->第二类是“区块注释”,标注每个功能模块的开始与结束,建议用同样的格式和分隔线,例如<!-- header 头部区域 start -->对应<!-- header 头部区域 end -->。这种成对出现的注释标记,配合编辑器的代码折叠功能,可以大幅提升大文件的可读性和维护效率。
<!-- header 头部区域 start --> <header> <h1>网页标题</h1> <nav>导航菜单</nav> </header> <!-- header 头部区域 end --> <!-- main 主体内容区域 start --> <main> <section class="product">商品信息</section> <section class="cart">购物车信息</section> </main> <!-- main 主体内容区域 end -->第三类是“特殊场景注释”,用于标注可能会让后来者困惑的代码片段。举个例子:某个 DOM 结构是为了适配旧版浏览器的怪癖而存在的,或者某段代码是临时的业务补丁,这类信息必须写清楚原因,否则下一个接手的人大概率会把这段“看起来很冗余”的代码删掉,然后线上出问题再紧急回滚。
2.3 条件注释:针对旧版浏览器的差异化处理
条件注释是 HTML 注释的一个特殊变体,曾经在 IE 浏览器时代非常常用。它的原理是 IE 浏览器会识别注释中的条件表达式,而其他浏览器会把它当作普通注释忽略掉。
<!--[if IE]> <p>您正在使用旧版浏览器,建议升级。</p> <![endif]--> <!--[if !IE]> <link rel="stylesheet" href="modern.css"> <![endif]-->随着 IE 浏览器的淘汰,条件注释已经没有必要新写了,但排查老项目时会经常遇到。理解它的语法规则很重要——如果误删了条件注释的结束标记,可能导致整个页面在 IE 下渲染异常。我做项目重构时遇到老代码里的条件注释,一般都会顺手清理掉,因为现在的浏览器已经不再支持这套机制,留着只会增加噪音。
2.4 调试注释与临时注释的管理
项目开发过程中,经常需要在 HTML 里临时屏蔽一段代码来排查问题。我的建议是,锁定问题时优先使用编辑器里的“切换注释”快捷键(VSCode 里是 Ctrl+/),而不是手动删除再撤销。
临时注释虽然好用,但最怕的是遗留到生产环境。这里有三个实用的管理技巧:
- 提交代码前全局搜索
<!--和-->,肉眼扫一遍所有注释内容,确认没有遗留的临时调试注释。 - 用构建工具自动剥离注释:
html-loader配合html-minifier-terser的removeComments选项,在生产构建时自动把所有注释清除。 - 需要长期保留的“重要逻辑说明”注释,建议统一加上前缀,比如
<!-- [说明] xxx -->,方便后续统一检索和管理。
2.5 HTML 模板中的注释:避免覆盖原生逻辑
现代前端开发中,HTML 往往不是纯静态文件,而是模板引擎的产物,比如 Vue 的 SFC 模板、React 的 JSX、EJS、Handlebars、Thymeleaf 等等。在这些场景里写 HTML 注释,有几个额外的注意事项。
Vue 模板里<!-- 注释 -->和普通 HTML 一样会被渲染时忽略,但要注意v-if等指令的临时禁用,不能直接把注释写在指令所在的标签上,否则指令不生效。正确做法是保留标签,只注释掉指令值,或者用v-if="false"来控制。
<!-- 正确:禁用按钮的点击事件绑定 --> <button :disabled="!isAllowed">提交</button> <!-- 错误:整个标签被注释掉了,按钮也不渲染了 --> <!-- <button :disabled="!isAllowed">提交</button> -->React JSX 里的注释写法就完全不一样了,必须用{/* 注释内容 */}的形式,因为 JSX 本质上是 JavaScript 表达式,<!-- -->在这里只是个普通文本节点。很多从传统 HTML 转过来的开发者第一次写 React 时都踩过这个坑。
// 正确写法 const App = () => ( <div> {/* 这是 JSX 注释 可以写多行内容 */} <h1>标题</h1> </div> );EJS 模板里推荐用<%# 注释 %>,这个写法在服务端渲染时就直接被剔除,不会输出到客户端 HTML 源码里。如果用的是<!-- -->,注释会出现在浏览器开发者工具的元素面板中,暴露内部信息(比如版权的内部备注、业务注意点),有一定信息安全风险。
3. CSS 与 JavaScript 注释的写法规范
3.1 CSS 注释:分模块、分层级地写
CSS 文件的注释和 HTML 不太一样。HTML 注释更多是区块性的,CSS 注释在本体之外,还承担了“目录”功能。一个大型项目的 CSS 文件可能有几千行,没有目录索引,维护起来痛苦指数极高。
推荐的写法是先写一个文件头,把文件内容的大纲列出来,然后每个模块的注释用统一的格式标记。例如:
/* ============================================ 全局样式表 作者:张三 主要模块:base / layout / components / pages ============================================ */ /* ========== layout 布局模块 ========== */ .header { width: 100%; height: 64px; } /* ========== components 组件模块 ========== */ .btn-primary { background: #1890ff; color: #fff; }CSS 注释还有一个特殊用法:配合 CSS 预处理器(Sass/LESS)的变量定义,把变量的业务含义写清楚。比如/* 主品牌色,用于所有按钮和链接 */写在$primary-color: #1890ff;上方,这样用变量的地方就不用到处翻来源了。
3.2 JavaScript 注释:从单行注释到文档级注释
JavaScript 里注释的写法比较丰富,从最简单的//到块级注释/* */,再到 JSDoc 风格的文档注释/** ... */,覆盖了不同场景的需求。
日常开发中,逻辑复杂的函数一定要写 JSDoc 注释。所谓 JSDoc,是一种基于注释的文档生成语法,它用@param、@returns、@throws等标签描述函数的参数、返回值和异常,配合编辑器的智能提示,可以让调用者写代码时直接看到函数说明,不用跳转到定义处。
/** * 计算两个数的和 * @param {number} a 第一个加数 * @param {number} b 第二个加数 * @returns {number} 两数之和 * @throws {TypeError} 参数不是数字时抛出 */ function add(a, b) { if (typeof a !== 'number' || typeof b !== 'number') { throw new TypeError('参数必须为数字'); } return a + b; }在 VSCode 中,将鼠标悬停在add函数的调用处,会直接弹出这段注释提示,非常直观。
注释不应该逐行解释代码“做了什么”,而是解释“为什么这么做”。代码let total = items.reduce((sum, item) => sum + item.price, 0)不需要注释来解释累加逻辑,但如果有业务背景——比如“价格字段可能为负数,这里用 reduce 而不是 forEach 是为了同时处理异常值”——那就必须写注释。
3.3 注释代码的隐藏问题:死代码清理是常态
前端项目里最常见的一个问题就是“注释掉的历史代码”堆积成山。开发者出于各种原因,把暂时不用的代码注释掉而不是删除,怕将来还要用。但事实是,大部分注释掉的代码永远不会再恢复了,它们只会增加阅读负担,让后来者分不清哪些是有效代码、哪些是废弃的代码。
我的建议是:如果某段代码暂时不想要了,直接用 Git 提交记录来保存它的历史版本,然后把工作区里的注释代码删掉,这是最干净的做法。如果一定要注释着保留,建议在注释开头注明“废弃时间”和“废弃原因”,并且设置一个定时清理的提醒,比如每季度全局搜索一下TODO、FIXME、HACK、@deprecated这些标记。
// TODO: 待接口联调完成后,补充 loading 状态 // FIXME: 当前实现存在边界问题,当用户快速点击两次时数据会重复提交 // HACK: 临时绕过 WebKit 的布局 bug,待浏览器更新后移除这些标记是前端社区通行的注释规范,很多编辑器插件(如 Todo Tree)会高亮它们,配合任务管理工具可以形成完整的技术债务跟踪机制。
3.4 CSS/JS 压缩与注释剥离:生产环境的正确做法
开发时写的注释在部署到生产环境前,一般会被构建工具剥离掉,以减小文件体积。Webpack 的CssMinimizerPlugin默认会移除 CSS 注释,TerserPlugin默认移除 JavaScript 的注释,但保留包含@license、@preserve这些特定标记的注释。这其实是刻意的设计——版权信息不应该被压缩工具剥掉。
如果自己写构建配置,需要注意TerserPlugin的extractComments配置。默认情况下它会收集所有@license注释到单独的文件里,如果没有配置好,可能出现“注释被剥了但文件没生成”的尴尬情况。还有个经验之谈:字体版权信息、API 文档类的注释,建议写在外部文档而不是源码注释里,构建时就不用考虑保留策略了。
4. 全场景注释规范:从编辑器配置到团队协作
4.1 VSCode 注释相关的实用配置与体验优化
VSCode 是前端开发者的主力编辑器,它本身的注释功能已经不错,但有几个设置项默认不是最优的,我建议按下面的方式调整。
第一,注释快捷键。默认的Ctrl+/是切换行注释,Shift+Alt+A是切换块注释。很多人只记得第一个,遇到要注释一大段 HTML 时就手动写<!-- -->,效率很低。记住Shift+Alt+A在 HTML、CSS、JS 里都能正确切换成对应语法的注释块,这个快捷键值得下意识去用。
第二,自动添加 JSDoc 注释。VSCode 默认没有这个功能,但安装扩展Document This或koroFileHeader后,在函数上方输入/**再按回车,就会自动生成带有参数名列表的 JSDoc 模板,填内容就行。这个插件也支持文件头注释模板的配置——可以预设作者名、时间、描述,在每次新建文件时自动生成类似本文前面提到的“抬头注释”。
第三,Todo Tree 扩展。安装后,项目里所有TODO:、FIXME:标记都会在侧边栏显示成一个树形列表,点击可以跳转到对应位置。我维护老项目时,会先用它全局扫一遍历史标记,评估技术债规模,再决定重构优先级。
4.2 IDEA 与 WebStorm 的注释模板配置
做 Java 后端的人切到前端开发时,通常会带着 IDEA 或 WebStorm 的使用习惯。IDE 系编辑器在注释模板这块比 VSCode 更自动化。
WebStorm 里点击File -> Settings -> Editor -> Live Templates,可以自定义注释模板。我个人配置了一个函数注释模板,触发关键字fc后,按 Tab 自动展开为:
/** * 函数功能描述 * @param {*} params 参数描述 * @returns {*} 返回值描述 * @author 张三 * @date 2024-03-15 */ function fn(params) { return params; }原理是 WebStorm 的变量表达式系统,@date后面的date()函数会自动填充当前日期,不用手动维护。这种模板一旦配好,写注释的效率能提升好几倍,而且团队里统一模板的情况下,代码风格也会特别整齐。
IDEA 或 WebStorm 里还支持“文件头模板”的配置,在Editor -> File and Code Templates里设置默认的包含页脚,新建文件时自动带上。配置路径稍微有点绕,但配好之后一劳永逸。
4.3 注释语言选中文还是英文?团队规范说了算
这个问题经常有开发者在社区里吵。我的看法是:取决于团队的代码评审规范和成员的阅读习惯。
如果你的团队全员都是中文母语,代码注释用中文完全没问题,可读性最高,交流成本最低。但如果项目要交付给海外团队维护,或者代码仓库有开源计划,那就必须统一用英文注释。
最怕的情况是“中英混杂”。一段代码的关键函数注释用英文,业务逻辑注释用中文,变量名又是拼音缩写,这种项目接手起来极其痛苦。
另外一个细节:HTML 页面本身的lang属性,应该和页面内容语言保持一致。热词里反复出现<!doctype html>和<html lang="zh-cn">的搜索记录,看起来简单,实际很多开发者会忽略。lang="zh-cn"标识了页面主语言是简体中文,这对无障碍阅读、搜索引擎优化、浏览器翻译工具都有影响。HTML 注释的内容建议也遵循同样的语言规则——注释本身不出现在页面上,但代码维护者的阅读体验同样是项目质量的一部分。
4.4 Git Commit 注释:被低估的“时间机器”
Git 提交信息的注释规范,是前端代码注释体系里最容易被忽视、实际上又最重要的部分。很多人提交时随手写fix bug、update、test,过三个月去看历史记录,完全不知道那次提交改了什么、为什么改。
主流的规范是 Conventional Commits 格式,它的核心是让提交信息可以被人类和工具共同解读。格式如下:
<type>[optional scope]: <description> [optional body] [optional footer]其中type用于说明提交的类别,包括:
feat:新功能fix:修复缺陷docs:文档变更style:格式调整refactor:重构perf:性能优化test:测试相关build:构建系统或外部依赖变更ci:CI 配置变更
配合scope指定影响范围,例如feat(cart): 增加优惠券抵扣功能。这种格式的价值在于:
- 通过
git log --oneline可以快速筛选某一类变更。 - 配合
semantic-release工具能自动生成版本号和变更日志。 - 代码评审时,评审者通过提交信息就能判断这次变更的意图和风险等级。
还有一个小技巧:提交前用git diff --check检查是否有空白字符错误,这虽然不是注释问题,但能减少代码评审过程中的琐碎返工。
4.5 字段注释与数据接口注释的联动
热词里出现了“字段注释”和“文档级 doxygen 注释”,这两个都和前端开发紧密相关。
前端联调接口时,后端返回的 JSON 数据字段,如果没有清楚地标注含义,前端拿到data.status会猜测它到底代表什么业务状态。现在很多团队用 OpenAPI 规范(Swagger)来管理接口文档,每个字段都能配上描述注释,前端可以直接根据接口文档生成类型定义。
前端侧的类型注释同样重要。TypeScript 项目里,每个接口的类型定义都应该写注释,说明字段的含义和取值范围。
/** * 商品信息 */ interface Product { /** 商品 ID,全局唯一 */ id: string; /** 商品名称 */ name: string; /** 价格,单位:分,正数为收入,负数为退款 */ price: number; /** 商品状态:0-下架,1-上架,2-售罄 */ status: 0 | 1 | 2; }这种注释配合 VSCode 的智能提示,在写业务代码时能直观看到每个字段的说明,能大幅降低沟通成本。
5. 注释的常见问题与排查技巧实录
5.1 VSCode 注释乱码:编码问题的根源与排查
热词里有“vscode注释乱码”,这确实是个非常常见的问题,尤其是项目中混合了中文、日文等非英文字符时。
乱码的核心原因是文件编码不一致。很多项目在创建时是 UTF-8 编码,但某些文件可能被别人用 GBK 等编码保存过。当 VSCode 用 UTF-8 打开一个 GBK 编码的文件时,中文注释就变成了乱码。
排查思路如下:
第一步,看 VSCode 右下角的编码标识。状态栏会显示当前文件的编码格式,如果不是 UTF-8,点击它进行转换。
第二步,如果已经是 UTF-8 但还是乱码,说明文件被“双重编码”了,需要用转换工具重新处理。VSCode 里可以用命令面板(Ctrl+Shift+P)执行Change File Encoding,或者安装扩展gbk相关插件来强制转换。
第三步,从源头解决。配置files.encoding为utf8,并设置files.autoGuessEncoding为true,这样 VSCode 会自动识别文件编码。
// settings.json { "files.encoding": "utf8", "files.autoGuessEncoding": true }第四步,如果是 Git 操作导致的乱码,检查.gitattributes文件,确保文本文件都强制 UTF-8 编码:
*.html text eol=lf *.css text eol=lf *.js text eol=lf *.json text eol=lf实测中,第四步是“根治”的关键。很多团队的项目乱码问题反复出现,就是因为 Git 服务器上存的文件编码本身已经乱了,本地改配置只治标不治本。
5.2 HTML 注释导致的页面布局异常
之前遇到一个线上事故,某个页面的底部突然出现了一行文字“测试中”。排查原因是某位同事为了调试临时注释掉了一个</div>,导致 DOM 结构错位,后面的区块全部变成了上一区块的子级,CSS 样式也乱了。
这类问题排查的步骤是:
- 在浏览器开发者工具中检查 Elements 面板的 DOM 结构,看标签闭合的层级关系是否正确。
- 用 VSCode 的括号着色功能(Bracket Pair Colorizer 或内置的括号颜色)检查 HTML 标签是否配对。
- 如果注释中出现了
--,优先怀疑注释是否被提前终止了。
经验总结:HTML 注释虽然简单,但在团队协作的项目里,不经意的一行注释可能引发连锁的布局问题。提交代码前建议用html-validate或编辑器自带的格式化功能(如 Prettier 配合html支持)做一遍语法检查。
5.3 注释中的敏感信息泄露事件
这个要专门提醒一下。注释里写敏感信息(数据库连接地址、内网服务器 IP、密钥、token 等),在开源项目或外包项目中是非常危险的行为。
我见过一个真实的案例:某外包开发者在 HTML 注释里写了数据库登录账号和密码,项目测试时通过浏览器“查看网页源代码”就能直接看到。虽然内网数据库没有直接暴露在公网,但万一测试服务器被攻破,这些注释里的信息就成了搭建跳板的关键情报。
注释安全规范有三条:
- 源码中禁止出现密码、密钥、token 等敏感信息。
- 内网 IP、生产环境的服务器地址、端口号不要写进 HTML 注释。
- 涉及商业机密的算法逻辑,不要用注释明文描述,要用文档形式管理并设置访问权限。
5.4 常见问题速查表
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| HTML 注释导致页面出现乱码文字 | 注释中出现--或结束标记丢失 | 全局搜索<!--检查注释块配对情况 |
| VSCode 打开老项目中文注释乱码 | 文件编码不是 UTF-8 | 设置 autoGuessEncoding 为 true,用 Change File Encoding 转换 |
| 注释里的链接点击后跳转错误 | 注释中包含相对路径被浏览器解析 | 使用绝对路径或移除链接 |
JSX 里写<!-- -->页面渲染出注释文本 | JSX 语法不支持 HTML 注释 | 改用{/* 注释 */} |
| 构建后版权声明被剥离 | TerserPlugin 未配置 extractComments | 使用@license标记并在配置中开启保留 |
| 注释过多导致 HTML 文件体积膨胀 | 历史遗留注释堆积 | 构建时开启 removeComments,定期清理死注释 |
| 团队提交信息乱七八糟,无法追溯 | 个人随意写提交信息 | 统一用 Conventional Commits 规范 |
项目里TODO标记太多,不知道从哪开始 | 缺乏技术债管理工具 | 安装 Todo Tree 插件,定期 Review |
6. 关于注释的一些个人体会与实用建议
6.1 注释是写给“未来自己”的备忘录
写注释最核心的价值,其实是写给未来的自己看的。很多开发者都有过这样的经历:某段代码当时写的时候觉得逻辑很顺畅,过了三个月再回头看,完全不知道当时的自己是怎么想的,花了很长时间才能捡起来。
我个人的实践是:凡是遇到需要“思考过才能写出来的逻辑”,就顺手写一句注释。这不是什么高深的原则,而是很朴素的投入产出比。
6.2 好的注释是“少而精准”,不是“多而全”
注释不是写得越多越好,恰恰相反,大量冗余注释会让代码的可读性下降。判断一段注释是否合格的简单标准是:删掉这段注释后,代码本身是否还能被完整理解?
如果删除后逻辑依然清晰,那这段注释就是冗余的。如果删除后让人困惑,那这段注释就是有价值的。代码注释的粒度应该保持在“逻辑决策点”层面,而不是“语法执行点”层面。
6.3 关于“AI 自动生成注释”的使用经验
这两年 AI 编程工具(如 GitHub Copilot、Claude Code 前端开发插件)逐渐普及,自动生成注释的功能用得越来越多。我的实践体会是:
AI 生成的注释,适合“解释性注释”,比如函数签名、参数说明、数据结构的字段定义,这类注释有固定格式,AI 生成得又快又准。
AI 生成“决策性注释”需要谨慎。比如“为什么这里用useMemo而不是useEffect”“为什么这个接口要轮询而不是长连接”,这类业务决策的背景信息 AI 并不了解,它生成的解释很可能是“从代码推导出的合理猜测”而非真实原因。这些注释还是要开发者自己写清楚。
6.4 一个实用的注释风格自检清单
最后分享一份注释风格的自检清单,也是我在 code review 时实际使用的检查项:
- HTML 区块注释是否成对出现,开始标记和结束标记是否对应。
- 删除的代码是彻底删除,还是注释保留但标注了废弃原因。
- 有没有包含 TODO 标记,如果有,是否关联了任务系统编号。
- 提交信息是否符合 Conventional Commits 格式,scope 是否准确。
- 有没有把密码、token、内网 IP 写进注释里。
- CSS 的注释是否用于解释“为什么这么写”,而不是重复选择器的名称。
- JavaScript 的 JSDoc 注释是否完整覆盖了参数和返回值类型。
- 新建文件时是否自动生成了文件头模板,模板里的信息是否准确。
按照这份清单,逐条自查一遍,大概只需要三分钟。但这三分钟能大大降低代码出问题的概率,也给后续接手的人减少很多猜测和试错成本。注释这件事,说到底是一种技术习惯,也是个人职业素养的体现。我持续练了很多年之后最大的收获是:代码托管平台上的记录越来越干净,每次回看自己的历史代码,都能快速进入状态,不会因为注释问题浪费研发时间。这才是注释写得好的长期红利。