ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

HTML语义化与页面结构搭建:从正确标签到整站信息架构

HTML语义化与页面结构搭建:从正确标签到整站信息架构

结构这件事,是我做了这么多年页面之后,重新回过头看才真正重视起来的。当年最早写HTML的时候,脑子里想的是"把效果调出来就算完事",一个页面下来满屏都是div,套了一层又一层,浏览器能渲染、看着差不多,就觉得自己会了。直到后来接手一个别人留下的项目,几千行的div嵌套,改一个样式要顺藤摸瓜翻半天,那时候才意识到:HTML结构从来不只是"把内容摆上去",它是整个页面的骨架,是浏览器、搜索引擎、辅助工具共同理解你页面的唯一途径。

这篇东西想聊的,就是"结构"这件事本身。从HTML5语义化标签怎么选、heading层级怎么排,到单页结构做明白了之后,怎么往整站规划走。适合刚入门HTML但想把基础打扎实的人,也适合写了一阵子页面、总觉得自己代码"能跑但别扭"的朋友。看完之后你至少能回答一个问题:一个页面、一个站点,结构到底应该怎么搭才算合格。

1. 结构这件事,为什么值得单独拿出来说

1.1 浏览器看到的和你看到的不是一回事

你可能觉得,页面嘛,不就是浏览器把HTML渲染成视觉界面嘛。这个理解没错,但你得知道,浏览器拿到HTML之后做的第一件事不是画界面,而是解析标签,构建一棵DOM树。这棵树里的节点关系,决定了后续所有CSS和JavaScript的操作方式。

举个例子:你写了两个div,一个在里面,一个在外面。浏览器不认识"里面""外面"这种视觉概念,它只认嵌套关系——外层是父节点,内层是子节点。CSS的层叠、JavaScript的事件冒泡、甚至屏幕阅读器的朗读顺序,全部建立在这棵树的父子关系之上。

所以结构这件事,本质上是你在决定这棵树长什么样。你用div还是用article,浏览器都能渲染,但树的"语义信息"完全不同。div在语义上就是个空箱子,它告诉浏览器"这里有个容器",至于容器里装的什么、和周边内容是什么关系,它一概不管。而article、nav、main这些标签,本身就带着含义:这是一篇文章、这是一组导航、这是页面的主体内容。

1.2 全div页面的代价,往往是后知后觉的

我见过最多的结构问题,不是标签用错,而是压根不用语义标签——从头到尾全是div+class。class名取得还挺讲究,什么"header-container""content-wrapper"之类,看起来好像还行。但实际上你有现成的header、main、footer标签不用,非要自己造一套命名体系,等于亲手把语义信息扔掉了。

这个代价分三层。第一层是开发维护成本:class名是你们团队自己约定的,换一个人来接手,得先读一遍所有命名规则才能看懂页面骨架。第二层是SEO成本:搜索引擎爬虫判断页面重点内容,很大程度上依赖语义标签,一个全是div的页面,它只能靠猜。第三层是无障碍成本:依赖屏幕阅读器的用户,通常会用快捷键在页面的"地标区域"之间跳转,比如按一下跳到主导航、再按一下跳到正文。这些地标就是靠语义标签提供的,没有它们,辅助工具用户就像走进了一个没有指示牌的商场。

我最深的体会是:**结构选型的错误,从来不会在当下暴露,而是在你改第二次、第三次、第十次的时候才爆发。**等到那时候再回头重构,代价远比你一开始多想五分钟大得多。

2. 语义化标签的正确打开方式:别把标签当装饰

2.1 六个高频标签的使用边界

HTML5的语义标签不少,日常用得最勤的其实是六个:header、nav、main、article、section、footer。我逐个说下它们的使用边界,不是背概念,是给你一个能直接参考的判断标准。

header:它表示"某一块内容的头部区域"。很多人默认header就是页面上方那一整条,其实不对——header可以出现在article里、section里,表示那部分内容的标题区域。反过来,页面顶部的那个"大通栏"也不一定非叫header,它更准确的角色是页面级的地标。

nav:专门用来放导航链接的区块。注意两点:一是页面可以有多个nav,比如顶部主导航一个、页脚导航一个,它们都是nav;二是nav和footer里的一堆链接是有区别的,footer里的链接列表如果只是版权信息、备案号之类,不算导航,不用包nav。

main:页面的主体内容区域,它代表当前页面的核心内容。一个页面有且只能有一个main,这是硬性规定。main不能被嵌套在article、section这种结构里面,它应该是直接挂在body下的顶层地标。另外,像侧边栏这种次要内容,不应该放进main里。

article:代表一个独立完整的内容单元。判断标准很简单:**这段内容脱离当前页面,单独拿出来,是否仍然站得住?**如果能,它就是article。一篇博客、一条新闻、一个评论,都是典型的article。注意,article可以嵌套——一条评论可能包含一条回复,这两个都是article,但回复是嵌套在评论里面的。

section:这个标签是很多人用得最糊涂的。它代表一个主题分组,比如一篇文章里的"背景介绍"和"数据分析"两大部分。**section在使用上有两条硬要求:一是它内部的第一个子节点应该是一个标题标签(h1到h6),二是如果内容能单独成立,你应该用article而不是section。**我建议你把section理解成"章",article理解成"篇",这样会好记很多。

footer:和header对称,代表"某块内容的结尾区域"。同样也不只限于页面底部,article内部、section内部都可以有footer,用来放作者信息、版权声明、相关阅读这些收尾性质的内容。

这六个标签都搞清楚之后,页面结构基本就清晰了。还有一个容易忽略的点:标签是有默认样式的,比如h1到h6字号不同、article和sections在浏览器默认样式里就是块级元素。很多人用语义标签的时候习惯性地全部reset掉,这没错,但别把语义标签当纯"容器"用——既要它的语义,又要重写成div的样子,那跟用div没区别。

2.2 heading层级:最容易被忽视的文档骨架

标题标签h1到h6,是除了那些语义结构标签之外,最能影响页面"骨架感"的元素。为什么这么说?因为标题定义了内容的层级关系——h1是这篇文章的大主题,h2是下面的大章节,h3是大章节里的小节,依此类推。

常见的错误有两种。

一种是一页堆好几个h1。正常逻辑下一个页面只应该有一个h1,它代表整个页面的主题。其他板块的标题,应该依次用h2、h3去承接。现在的浏览器和SEO工具虽然对这种做法比较宽容,但结构上的层级感已经被破坏了。

另一种是跳级。写完h1直接写h3,中间的h2不出现。这在逻辑上就像一本书,目录直接从"第一章"跳到"1.1.3小节",读者会困惑:还有一个小节去哪了?屏幕阅读器的用户尤其依赖标题导航,跳级等于把他们的目录撕掉了一页。

我给一个非常朴素的建议:**写结构的时候,先不管样式,只关注"内容的章法"——页面的核心主题是h1,往下每切入一个新的内容层面,就降一级标题。**等结构梳理顺了,再去考虑字号和视觉层级。我在实际项目里发现,很多样式上的"标题不够突出"问题,根源都不是CSS没写好,而是标题层级本身就乱,视觉上自然就乱了。

2.3 一个典型页面结构拆解

把上面这些串起来,一个典型的内容型页面长这样:

<body> <header> <h1>站点名称</h1> <nav> <ul> <li><a href="/">首页</a></li> <li><a href="/articles/">文章</a></li> <li><a href="/about/">关于</a></li> </ul> </nav> </header> <main> <article> <h2>文章标题</h2> <p>发布时间、作者等元信息</p> <section> <h3>背景介绍</h3> <p>正文内容……</p> </section> <section> <h3>具体分析</h3> <p>正文内容……</p> </section> </article> <aside> <h2>相关阅读</h2> <ul> <li><a href="#">推荐一篇</a></li> <li><a href="#">推荐二篇</a></li> </ul> </aside> </main> <footer> <p>版权信息</p> <nav> <ul> <li><a href="/privacy/">隐私条款</a></li> </ul> </nav> </footer> </body>

注意几个细节:站点名称用h1,文章的标题用h2——这里只有一个h1,因为页面级别上说,这个页面首先属于这个站点,站点名才是页面主题;侧边栏的"相关阅读"在结构上放到article旁边,都是main的子级;页脚的nav是"辅助导航",和顶部的"主导航"是两个nav,但内容性质不同,这就形成了清晰的语义分区。

这就是一个页面的结构骨架。也许你会觉得这套东西和之前看过的资料差不多,但真正用的时候容易被各种细节绊住。下一节把单页结构往外扩一层,聊整站规划的思路。

3. 从单页到整站:信息架构先行

3.1 整站规划的第一步不是写代码

我见过不少开发者,做一个站点的时候,打开编辑器就是一顿操作,首页写完写列表页,列表页写完写详情页,写到最后发现页面之间的结构对不上:这个页面h1是站点名,那个页面h1是文章名,导航在这里是三列,在那里是两列。

问题的根源在于:**一开始就没有一张"地图"。**整站规划的第一步,不是写HTML,而是梳理信息架构——这个站有哪些类型的页面?它们之间的层级关系是什么?用户最常走的路径是哪几条?

拿一个典型的内容站举例。它至少有四类页面:首页、栏目列表页、内容详情页、关于页。这四类页面的结构角色完全不同:

  • 首页:信息聚合地,它要回答"这个站是干什么的、最新有什么",所以结构上是多个内容区块的组合,h1是站点名称。
  • 列表页:某一类内容的索引,结构上通常是"分类标题+文章列表",h1应该是这个分类的名称。
  • 详情页:具体内容的展示,h1应该是内容本身的标题,站点名称退到header区域里,降为其他层级。
  • 关于页:相对独立,h1是页面自身的主题。

这四类页面的结构虽然细节不同,但共用的导航、页脚这些"框架部分"是完全一致的。所以整站规划的核心,是先把框架部分的结构定下来,再为每一类页面定义主体区域的内部结构规则。

3.2 URL与目录结构怎么定

信息架构确定之后,下一个落地的就是URL结构。URL不只是网址,它是整站结构在用户面前最直接的体现,也直接反映你的目录层级。

我给你的建议是三个字:短、平、稳。

短,指的是不要搞多层嵌套。有人喜欢按内容分类层层往下切,比如 /tech/frontend/html/basics/,看起来很有条理,但层级太深,用户看URL都猜不出自己到底在哪一层。一般实践上,两级到三级就够用了:/分类/内容名/,或者 /分类/子分类/内容名/。

平,指的是同一层级的内容尽量平行,不要出现"这个分类下有个子分类,子分类下还有个专题"这种无限下钻的树状结构。层级越深,导航和面包屑的压力越大,用户迷路的概率也越高。

稳,指的是URL一旦确定并对外发布,就不要轻易改。改URL等于把书架的编号体系推倒重来,存量链接、收藏夹、搜索引擎收录全部受影响。这也是为什么我建议在项目一开始就花时间把URL规则定死,而不是上线之后不断调整。

有一个细节值得提:文件命名也要跟着语义走。比如列表页的模板叫 list.html 还是 category.html,详情页叫 single.html 还是 article.html,名字本身不是关键,关键是全站要统一,别一个项目三种命名风格,后面找文件的时候,你会感谢当时定规矩的自己。

3.3 导航设计的层级原则

整站结构最终要落到导航上。导航不是随便列几个链接,它是信息架构在界面层的投影。

关于导航层级,我有个非常实用的建议:**主导航放一到两级就够了,不要试图在一个导航里展示全站所有内容。**如果主导航的每一项下面还有一大串下拉子菜单,通常说明你的信息架构分类没过关——这些子类大概率是可以合并、归并或者平移到二级页面的。

另外,导航里每个链接的锚文本要能"自我解释"。"产品服务"这种模糊的标题,用户点了才知道里面是什么,"文档""定价""客户案例"这种就非常清楚。别小看锚文本,它对SEO和辅助工具用户都有直接影响——屏幕阅读器在页面上快速扫过链接列表时,用户听到的就是锚文本本身。

还有一个经常被忽略的角色:面包屑。面包屑不只是给用户看"我在哪",它在结构上还承担着"当前位置与站点的层级关系"的表达。如果你用了面包屑,注意它最好放在main区域的开头,并且用nav包裹,方便辅助工具识别。页面层级越深,面包屑越重要。

4. 结构搭建中的常见坑与排错思路

4.1 嵌套错误:main套main、section里没有标题

结构类问题不像JS报错那样会弹出红色警告,它是"默默长歪"的。我收集了三个高频问题,你可以拿自己的页面对照一下。

第一个坑是main的嵌套问题。前面说过,一个页面只能有一个main。但很多人会在组件化开发的时候,把main写进一个公共组件里,然后在不同页面里复用这个组件,结果每个页面就出现两三个main。排查方法很简单:打开浏览器开发者工具,在Console里执行document.querySelectorAll('main').length,输出大于1,说明结构有问题。

第二个坑是section没有标题。section的语义是"一个主题分组",没有标题的分组对于读者来说就是一团内容块。如果你发现自己写了一个section,但怎么都放不进去合适的标题,那大概率你应该用div而不是section。回到前面那个判断标准:div是"没有含义的容器",section是"有主题的分组",放不进去标题就说明它没有主题。

第三个坑是滥用aside。aside是"与主体内容相关的次要内容",很多人把广告位、追番按钮、什么乱七八糟的悬浮组件全塞进aside里。这些内容如果和当前页面的主体没有直接相关性,它就不该出现在aside里,而应该作为独立的区块放在main外面。怎么判断?如果你把aside里的内容遮住,完全不影响理解当前页面的主题,它就配不上aside这个语义。

4.2 用开发者工具和校验器做"结构体检"

排查结构问题,推荐三个工具,都是免费的,日常完全够用。

第一个是浏览器自带的开发者工具。除了刚才说的查main数量,你还可以用Elements面板看DOM树的整体形状,一眼扫过去就能发现是不是有奇怪的嵌套。另外,在Console里可以快速检查关键节点:document.querySelectorAll('header').length、document.querySelectorAll('nav').length,看看数量是否符合预期。

第二个是W3C官方的HTML校验器。把页面代码贴进去,它会非常严格地把结构问题一条条列出来,比如"section缺少标题""footer不应包含main"这种。虽然它的标准比较严苛,有些小问题可以忽略,但结构类的警告,建议全都处理掉。

第三个是无障碍检查工具,浏览器插件形式就有。这类工具会模拟屏幕阅读器的视角,生成页面地标和标题结构的清单,你一眼就能看出页面结构是否让辅助工具用户顺畅理解。我每做完一个页面结构,都会跑一遍,基本能拦截80%的结构问题。

4.3 移动优先的DOM顺序

响应式布局遇到一个常见问题:视觉上优先展示的内容,和DOM里优先排列的内容不一致。比如一段文字配一张图,移动端希望先显示文字再显示图片,桌面端希望图在左边文字在右边。很多人的第一反应是靠CSS的flex-direction或者order去调顺序,短期内能搞定,但这里有个隐患:CSS调整的是视觉顺序,DOM顺序不变,屏幕阅读器的朗读顺序依然跟着DOM走。

正确思路是:**在写HTML的时候,就把移动端用户和辅助工具用户最关心的内容,放在DOM里靠前的位置。**视觉上的左右调换,交给CSS去处理;移动端和桌面端的展示差异,通过CSS Flexbox或Grid的排列属性解决。这样结构上"先主体后附属"的语义顺序得以保持,视觉上又灵活。

我见过不止一次的反面案例:为了让桌面端好看,把侧边栏放到了DOM的最前面,结果移动端页面上,侧边栏内容和主体内容在DOM里挤成一团,正常的朗读顺序完全错乱。这个坑很隐蔽,因为大家日常肉眼看不到,一旦被辅助工具用户反馈,改起来就是伤筋动骨的事情。

5. 实操案例:从零搭一个内容站点的结构骨架

5.1 先画站点地图,再动手

光说不练不行。我拿一个模拟的内容站点项目举例,从零到一把结构搭起来。先说需求:做一个三人小团队的技术博客,内容分为前端、后端、随笔三个栏目,有首页、栏目页、文章详情页、关于页。

第一步永远是画站点地图:

首页 / ├── 前端栏目 /frontend/ │ └── 文章详情 /frontend/文章名/ ├── 后端栏目 /backend/ │ └── 文章详情 /backend/文章名/ ├── 随笔栏目 /notes/ │ └── 文章详情 /notes/文章名/ └── 关于 /about/

三栏目的结构是平行的,URL层级统一是两级:栏目/文章名。这个地图画完之后,框架层的公共结构就非常好定了:顶部header里是站点名+三个栏目导航,底部footer是版权和几个辅助链接。所有页面共用这套框架。

5.2 首页与列表页的结构模板

首页结构上,h1直接用站点名,主体main里放两个区块:一个是"最新文章"列表,一个是"热门推荐"。这两个区块在语义上是"主题分组",所以用section,每个section放一个h2标题。每个文章条目本身是一个独立的新闻条目,用article包裹。

列表页的结构则要再仔细想一步。栏目页的h1应该是栏目名,比如"前端";文章列表是一个"主题分组",包在section里,每个条目用article;如果列表要分页,可以加一个nav来做分页导航。

这两个页面共用一个公共模板,唯一的差异在main区域内部的组织方式。做到这一步你已经能体会到:整站规划的价值在于,你只需要把首页和列表页的结构各做一次,后续新增栏目、新增文章,都是套模板的事。

5.3 详情页的结构:语义标签的主场

详情页是语义标签最能体现价值的地方。一个文章详情页,我建议至少保证下面的结构层次:

<body> <header><!-- 公共头部,h1是站点名 --></header> <main> <article> <header> <h1>这篇文章的标题</h1> <p>作者、日期、阅读时长</p> </header> <section> <h2>第一节</h2> <p>正文……</p> </section> <section> <h2>第二节</h2> <p>正文……</p> </section> <footer> <p>标签、版权说明</p> </footer> </article> <aside> <h2>猜你喜欢</h2> <ul><!-- 推荐文章列表 --></ul> </aside> </main> <footer><!-- 公共页脚 --></footer> </body>

注意这里有个细节:详情页的h1是文章标题,不是站点名。头部的站点名降级,不再用h1,或者甚至不需要再出现一次。很多人做详情页的时候,把站点名的h1和文章标题的h1同时放上去,这就是前面说的多h1问题。整站只有一个页面——首页——的h1是站点名,其他页面h1都应该是页面自己的主题。

5.4 结构搭完之后,验证清单

结构搭完之后不要急着写样式,先过一遍验证清单。我在实际开发中,每个页面的结构都会按这四个问题自查一遍:

  1. 唯一性:页面里只有一个main,只有一个h1。
  2. 完整性:每个section都有标题,每块独立完整的内容是article而不是div。
  3. 顺序合理性:DOM顺序从"主体内容"开始,附属内容靠后,没有被CSS的视觉顺序带偏。
  4. 导航可识别性:主导航是nav,面包屑是nav,分页是nav,这些nav的链接文本都能自解释。

做到这四点,哪怕还没写一行CSS,这个页面的"骨架"已经是健康的了。后面改样式、加交互、上响应式,都在这棵健康的树上操作,出问题的概率会小很多。

我自己的体会是,结构健康的东西,后期维护的心情完全不一样。写CSS的时候选择器简单、不依赖一大堆嵌套层级;写JavaScript的时候querySelector能找到明确的目标;改版重构的时候,顺着语义标签走一遍,页面骨架一目了然。这个前期投入的半小时,换来的是后面无数个少掉的深夜排查。

如果你手头正好有一个写了一半的页面,不妨现在就打开开发者工具,点开Elements面板,从头到尾看一眼你的DOM树。它看起来像一个结构清晰的文档,还是像一盘缠在一起的耳机线?如果是后者,那就从这篇说的这套思路开始,重新搭一遍骨架——这是整个前端技能体系里,性价比最高的一次重构。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进