写HTML看起来是前端开发里最没有门槛的事,标签套标签,会打字就能上手。但我见过太多人学了大半年,写出来的页面结构一塌糊涂:标签嵌套没逻辑、代码里没有一条注释、属性随手乱写。浏览器倒是都能打开,改起样式来却像在盲人摸象。所以这期笔记,我想把HTML标签之间的关系、HTML注释、标签属性这三个基本功一次性聊透。别小看这三样东西,很多写了两年页面的前端都不一定搞清楚了。它们不像JavaScript那么考验逻辑,也不像CSS那么讲究设计感,但它们决定了你的页面结构干不干净、代码好不好维护、浏览器解析会不会出错。
如果你是刚入门H5开发的新手,这一期建议从头看到尾。内容不深,但每一条都是日常写页面时高频踩中的点。如果你已经写了一段前端代码,也可以重点看后面的“避坑”和“实战”部分,对照一下自己平时有没有犯过类似的问题。
1. 先搞懂HTML标签之间的“家庭关系”
1.1 父子关系:谁包着谁,谁就是“父”
HTML本身就是一个嵌套结构,标签套标签,就像文件夹套文件夹一样。我们把“直接包裹其他标签”的标签称为父元素,被包裹在里面的那一个称为子元素。
<div> <p>我是子元素</p> </div>在这个例子里,<div>就是<p>的父元素,<p>是<div>的子元素。这个关系是直接的、相邻的,中间没有隔其他标签。如果<p>里面又塞了一个<span>,那么<div>相对于<span>来说就不再是父元素,而是祖先元素。同理,<span>相对于<div>是后代元素。
这个关系能不能再通俗一点?你把它想象成家庭族谱:
- 父元素 = 爸爸
- 子元素 = 儿子
- 祖先元素 = 爷爷、太爷爷
- 后代元素 = 孙子、重孙子
很多新手搞混的地方是“父元素”和“祖先元素”的区别。举个真实场景:你在CSS里写div p { color: red; },这个选择器是把div里面所有的p(不管隔多少层)都选中了;但如果写的是div > p { color: red; },就只选中div直接包住的那一层p。这两个效果完全不同,根源就是在标签关系的理解上。
1.2 兄弟关系:同一层级的小伙伴
有上下级,就有平级。同一个父元素下的、处于同一层级的标签之间,称为兄弟元素。
<div> <h1>标题</h1> <p>第一段</p> <p>第二段</p> </div>这里的<h1>和两个<p>都是兄弟关系。<p>和<p>之间也是兄弟。当然,我们说的“兄弟”不是真的有血缘关系,只是在DOM树里处在同一层罢了。
理解兄弟关系有什么用?先说CSS。像h1 + p { margin-top: 0; }这种相邻兄弟选择器,用的就是“两个标签是紧挨着的兄弟”这个前提。再说JavaScript,你通过document.querySelector('.item').nextElementSibling拿到下一个兄弟节点,也是在操作这层关系。如果你脑子里没有兄弟这个概念,后面学DOM操作很容易绕晕。
还有一层作用在页面结构上。一个父元素里如果有多个兄弟元素,它们默认会按照从上到下的顺序在页面里排列。块级元素会占满整行,一个接一个往下排;行内元素会从左往右排。这个“排列规则”虽然是由CSS决定的,但HTML里的层级关系是它的大前提。
1.3 嵌套规则:哪些标签不能“乱伦”
标签的关系不是你想怎么套就怎么套,HTML规范对“谁里面能放谁”有明确要求,专业一点的叫法是内容模型(Content Model)。这里我不把规范条文全部搬出来,只讲日常开发中最常踩的几个硬性规则:
<p>里面不能放块级元素。<p>是段落标签,段落里应该是文字、<span>、<a>、<img>这类行内内容。如果你在<p>里面塞一个<div>,浏览器会自动把<p>在<div>前“切断”,导致结构错乱。<ul>和<ol>的直接子元素只能是<li>。也就是说<ul>外面可以套其他标签,但<ul>里面第一层就是<li>。如果你直接写<ul><div>xxx</div></ul>,浏览器虽然不会报错,但渲染出来的DOM结构会和预期不一样。<a>标签不能嵌套<a>标签。这一点非常隐蔽,很多人写卡片式链接,在<a>里面又套了<a>,结果点击区域错乱、跳转失效。为什么不能套?因为浏览器解析到第二个<a>时,会自动闭合第一个<a>,等于你写了一层,但实际DOM里被拆成了两层,完全失去本意。<button>里面不能放<button>、<input>、<select>等交互元素。否则会出现事件冲突,比如点击内层按钮,外层按钮也响应了。
这些规则不是浏览器故意为难你。HTML的设计原则是“容错优先”,浏览器在遇到不合法的嵌套时会自动纠正,但纠正的结果往往不是你想要的。很多“页面看起来正常但样式对不上”的诡异问题,根源就是标签嵌套不规范。
2. HTML注释:写给代码的“便利贴”
2.1 注释的基本写法与快捷键
HTML注释看起来没什么技术含量,格式只有一种:
<!-- 这是一段注释,不会显示在页面上 -->注释可以写在任意位置,可以占一行,也可以跨多行:
<!-- 作者:某开发者 日期:2025-01-10 用途:产品列表区域 --> <div class="product-list"> <!-- 单个商品卡片 --> <div class="product-item">...</div> </div>编辑器里一般都有注释快捷键:
- VS Code / Sublime / WebStorm 等:Windows 用
Ctrl + /,Mac 用Cmd + / - 选中多行再按快捷键,可以一次性注释多行;再按一次,取消注释
刚开始学的时候,很多人觉得注释“写了跟没写一样,反正用户看不见”。但注释是写给写代码的人看的,这个“人”包括未来的你、你的同事、你的团队成员。页面最终展示给用户的是渲染之后的HTML,但代码从诞生到维护、重构,整个过程都是人在看,不是浏览器在看。
2.2 注释的三种实用场景
我自己的习惯是,只要代码里出现下面三种情况之一,就一定会写注释:
第一,标记模块的边界。一个真实页面动辄几十个区块,代码写到后面你自己都忘了哪个</div>对应哪个开头。这时候用注释把“门户”标出来:
<!-- ===== 头部导航栏 start ===== --> <header> <nav>...</nav> </header> <!-- ===== 头部导航栏 end ===== -->配合编辑器的代码折叠功能,整个页面的结构一目了然。这个习惯在团队协作里尤其重要,别人接手你代码的时候,不用从头一行一行猜。
第二,临时禁用代码做调试。页面渲染出问题,你想确认是不是某一块代码引起的,不用删掉它,直接注释掉。刷新浏览器看看效果,确定问题所在再决定去留。这个操作比反复删了又粘贴回来要高效得多。
第三,留“提醒”给未来的自己。比如某段结构写得比较绕,或者有已知的兼容性问题,你可以在旁边注释一句:
<!-- 注意:这里不要改成 div,会影响后台管理系统的样式覆盖 --> <div class="card-item">...</div>我见过很多项目上线几个月后,有人乱改一段看不懂的代码导致线上样式崩了,翻提交记录才发现半年前有人在注释里写了“不要动这里”。写注释的成本极低,收益却很高。
2.3 注释的禁忌
注释也有几个容易踩的坑。
注释里不能嵌套注释。HTML注释不支持嵌套,你在
<!-- ... -->里面再写<!-- ... -->,第一个-->会把整段提前闭合,后面内容全部暴露出来,直接变成页面上的乱码。注释内容里不要出现两个连续的连字符
--。HTML规范要求注释内容不能含有--。有的字符串文本里带了,浏览器解析时就可能出错。我见过有人在注释里写时间范围“2023--2024”,结果页面结构乱了,排查了半天才找到这条注释。注释不能写在标签内部。比如
<div <!-- 注释 -->>,这会让浏览器解析混乱,标签直接失效。注释只能写在标签外面,或者标签对之间的位置。
3. 标签属性:给HTML元素加“参数配置”
3.1 属性的构成与写法规范
如果说标签定义了元素“是什么”,那属性就规定了元素“怎么配置”。标签属性写在开始标签内部,由“属性名”和“属性值”组成:
<a href="https://www.example.com" target="_blank">访问示例网站</a>结构拆开看:
href:属性名"https://www.example.com":属性值target:第二个属性名,多个属性之间用空格隔开"_blank":它的属性值
写属性有几个硬性规范,照着做不容易出错:
- 属性名小写,虽然HTML5对大小写不敏感,但统一小写是行业习惯,也是团队协作的基础。
- 属性值用双引号包起来。单引号也可以,但混用会导致解析歧义。比如
href='https://example.com'合法,但你写href='https://example.com"就会出问题。 - 属性名和属性值之间用等号连接,等号两边不要随便加空格。写成
href = "url"在多数浏览器里能容错,但规范上不推荐,而且会干扰后续的代码格式检查。
再说说属性值里的特殊字符。最典型的是链接地址里带了&参数,比如:
<a href="https://example.com/search?keyword=a&page=2">搜索</a>这个&符号在HTML里有特殊含义,如果直接用会带来不可控的解析风险。规范做法是写成实体字符&:
<a href="https://example.com/search?keyword=a&page=2">搜索</a>这段可能有人看不懂,我举个生活化的例子:属性值里的双引号是做“外壳”的,&就是藏在壳里容易被误拆的“定时炸弹”,不转义它,浏览器会以为自己看到了新的标签起点。
3.2 全局属性:所有标签都能用的“通用配置”
有一类属性是几乎所有标签都可以使用的,叫做全局属性。它们不依赖具体的标签,是HTML这门语言统一提供的“基础设施”。