Day 16 | 用 ul、ol、li 一个标签,把散资料收成有序的技能清单页
本文是《100天精通HTML基础入门》专栏第 16 篇,订阅专栏不迷路。
摘要 :本文基于 HTML5 现行规范,用演化式讲清一件事------技能清单别再一行一行用<p>硬敲。我们从一堆散乱的<p>出发,逐版演进到<ul>无序列表、<ol>有序列表带嵌套子清单、最后用<dl>把"技能名 + 熟练度"这种成对信息语义收口。四版运行结果都在 Chrome 128 下验证过。适合刚做完名片页、正往阶段二走的读者,读完你能交出一个结构正确的技能清单页,并说清li外面裸写字、嵌套漏一层ul这两个坑为什么会崩。列表的默认记号与缩进是 CSS 早期就定下的机制,长期适用。
本文目录
-
技能清单先长这样:一堆 p 标签硬堆
-
v2:一个 ul 把同级内容收成一挂
-
v3:该排序的用 ol,往里再嵌一层子清单
-
漏掉这一层 ul,子清单和父级挤成一坨
-
把字写在 li 外面,浏览器当场不收
-
v4:一组词配解释用 dl,语义才对得上
-
为什么列表天生带记号和缩进
-
今天小结:清单成了,那个点却碍眼

技能清单先长这样:一堆 p 标签硬堆
阶段一的电子名片里,"我会什么"那块多半是你一行一行敲出来的 <p>。它不难看,但难维护:想加一项得自己挪序号,想调顺序得重敲,读屏软件也数不出"这里有 3 条技能"。先把这版还原出来------运行结果在 Chrome 128 下看过,它长得像清单,骨子里是一堆各过各的段落。
Plaintext
<!-- 《100天精通HTML基础入门》Day 16 · 平头哥 · 技术改变世界,勤奋改变人生 -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>技能清单 v1 · 一堆 p 硬堆</title>
<style>
/* v1 的问题:每条技能是独立段落,彼此没有"同属一组"的关系 */
/* 序号靠手打,一旦加项或调序,下面的数字全得重敲 */
* { box-sizing: border-box; }
body { font-family: "Microsoft YaHei", sans-serif; background: #f7f5ef;
color: #24292f; margin: 0; line-height: 1.7; }
.wrap { max-width: 560px; margin: 24px auto; background: #fff;
border: 1px solid #d8d3c8; border-radius: 14px; padding: 24px 28px; }
h1 { font-size: 22px; margin: 0 0 14px; }
p { margin: 0 0 8px; font-size: 15px; }
</style>
</head>
<body>
<div class="wrap">
<h1>我的技能</h1>
<p>1. HTML 结构与语义标签</p>
<p>2. 页面排版与移动端适配</p>
<p>3. 把列表和链接组合成导航</p>
</div>
</body>
</html>


三个手打的序号就是三颗定时炸弹。更麻烦的是语义:HTML 根本不知道这三行是"一组",对它而言就是三个不相干的 <p>。这就是我们要演化的起点。
v2:一个 ul 把同级内容收成一挂
先说最要紧的改动:同级、无序、彼此并列的内容,交给一个 <ul> 包着,每条放进一个 <li>。你不用再管序号和缩进,浏览器会自动给每条前面点一个实心圆点,并留出整齐的左缩进。为什么用 ul 而不是继续 <p>?因为这组技能之间没有先后,"结构"不比"排版"更靠前,是无序关系。

样式代码不用细看,理解为给网页化妆即可,CSS 专栏里会展开。
Plaintext
<!-- 《100天精通HTML基础入门》Day 16 · 平头哥 · 技术改变世界,勤奋改变人生 -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>技能清单 v2 · 一个 ul 收成一挂</title>
<style>
/* ul 负责"这是一组",li 负责"组里的每一条" */
/* 圆点和左缩进是浏览器默认样式,这一版我们不覆盖它 */
* { box-sizing: border-box; }
body { font-family: "Microsoft YaHei", sans-serif; background: #f7f5ef;
color: #24292f; margin: 0; line-height: 1.7; }
.wrap { max-width: 560px; margin: 24px auto; background: #fff;
border: 1px solid #d8d3c8; border-radius: 14px; padding: 24px 28px; }
h1 { font-size: 22px; margin: 0 0 12px; }
ul { margin: 0; padding-left: 22px; }
li { font-size: 15px; margin-bottom: 6px; }
</style>
</head>
<body>
<div class="wrap">
<h1>我的技能</h1>
<ul>
<li>HTML 结构与语义标签</li>
<li>页面排版与移动端适配</li>
<li>把列表和链接组合成导航</li>
</ul>
</div>
</body>
</html>


运行结果对比 v1:页面长得几乎一样,但源码从"三个各过各的段落"变成了"一条列表挂三个项"。加一项只需多写一行 <li>,序号、圆点、缩进浏览器全包。这就是清单式的正确底座。
v3:该排序的用 ol,往里再嵌一层子清单
清单不只有并列。学习路径、操作步骤这种有先后 的,要用 <ol>,让浏览器替你编号。另外还有个有意思的事:清单能套清单------在某个 <li> 里面再放一个完整的 <ul>,就长出第二层。注意这条铁律:每一层子清单,都得自带一个 <ul> (或 <ol>)外壳 ,不能光秃秃地再写几个 <li>。

样式代码不用细看,理解为给网页化妆即可,CSS 专栏里会展开。
Plaintext
<!-- 《100天精通HTML基础入门》Day 16 · 平头哥 · 技术改变世界,勤奋改变人生 -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>技能清单 v3 · ol 排序 + 嵌套子清单</title>
<style>
/* ol 有先后:浏览器给 1 2 3,步骤顺序错了就得重排 */
/* 嵌套只在父 li 内部再开一个 ul,缩进由浏览器自动处理 */
* { box-sizing: border-box; }
body { font-family: "Microsoft YaHei", sans-serif; background: #f7f5ef;
color: #24292f; margin: 0; line-height: 1.7; }
.wrap { max-width: 560px; margin: 24px auto; background: #fff;
border: 1px solid #d8d3c8; border-radius: 14px; padding: 24px 28px; }
h1 { font-size: 22px; margin: 0 0 12px; }
ol { margin: 0; padding-left: 22px; }
ol > li { font-size: 15px; margin-bottom: 8px; }
ol ul { margin-top: 6px; padding-left: 22px; }
ol ul li { font-size: 14px; color: #4a5560; margin-bottom: 3px; }
</style>
</head>
<body>
<div class="wrap">
<h1>我的技能</h1>
<ol>
<li>前端基础
<ul>
<li>HTML 结构与语义标签</li>
<li>页面排版与移动端适配</li>
</ul>
</li>
<li>进阶技能
<ul>
<li>把列表和链接组合成导航</li>
<li>表单与页面结构</li>
</ul>
</li>
<li>正在学
<ul>
<li>CSS 盒模型</li>
</ul>
</li>
</ol>
</div>
</body>
</html>


现象验证:编号 1 2 3 是 ol 给的,子项前面的短横是嵌套 ul 给的,两层缩进整齐。把某条技能提到第一层,只要在 <li> 之间移动整块,浏览器会重算编号------这正是清单比手打序号值钱的地方。
漏掉这一层 ul,子清单和父级挤成一坨
新手坑里最阴的一个:你以为缩进敲到位,层级就对了。可 HTML 不认空格,只认标签。想再开一层,必须有那个 <ul> 外壳。少了它,子项的 <li> 会被当成父级的兄弟,和"前端基础""进阶技能"平起平坐,整页层级当场塌平。下面是漏掉第二层 ul 的翻车现场。
Plaintext
<!-- 《100天精通HTML基础入门》Day 16 · 平头哥 · 技术改变世界,勤奋改变人生 -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>翻车 · 嵌套漏了一层 ul</title>
<style>
/* 每个 li 描一条浅边框,让"本该是父子却被拉平"的关系肉眼可见 */
/* 现象:子项和父项同级排,少了一格缩进 */
* { box-sizing: border-box; }
body { font-family: "Microsoft YaHei", sans-serif; background: #f7f5ef;
color: #24292f; margin: 0; line-height: 1.7; }
.wrap { max-width: 560px; margin: 24px auto; background: #fff;
border: 1px solid #d8d3c8; padding: 24px 28px; }
ol { padding-left: 22px; }
li { border: 1px dashed #b0342a; margin: 6px 0; padding: 2px 6px; }
</style>
</head>
<body>
<div class="wrap">
<ol>
<li>前端基础</li>
<li>HTML 结构与语义标签</li>
<li>页面排版与移动端适配</li>
<li>进阶技能</li>
<li>把列表和链接组合成导航</li>
</ol>
</div>
</body>
</html>

对照上面 v3 的效果图:那本来该缩进一格、属于"前端基础"之下的两条,现在被拍平成了和"前端基础"同级的 2、3、5 号。修复只有一步------把这几条 <li> 用一个新的 <ul> 包起来,塞回父 <li> 里面。
把字写在 li 外面,浏览器当场不收
另一个高频手误:写着写着,把某句话打在了 <li> 结束标签之后、</ul> 之前。这行裸字不属于任何列表项,浏览器会把它当成列表外的一段普通文本,常常挤在最奇怪的位置。规则很简单:列表里的每一条文字,必须在 <li> 的开闭标签中间。

下面这份就是把一句话落在了列表结构里的正确写法:凡是补充说明,要么进 <li> 里,要么整段移到 </ul> 之后当普通 <p>,绝不能悬在 <ul> 内、<li> 外。
Plaintext
<!-- 《100天精通HTML基础入门》Day 16 · 平头哥 · 技术改变世界,勤奋改变人生 -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>技能清单 · li 内容收口对照</title>
<style>
/* 每条技能连同它的说明,整体留在同一个 li 里 */
/* 全局说明移出列表,用 p 独立成段,不污染清单结构 */
* { box-sizing: border-box; }
body { font-family: "Microsoft YaHei", sans-serif; background: #f7f5ef;
color: #24292f; margin: 0; line-height: 1.7; }
.wrap { max-width: 560px; margin: 24px auto; background: #fff;
border: 1px solid #d8d3c8; border-radius: 14px; padding: 24px 28px; }
h1 { font-size: 22px; margin: 0 0 12px; }
ul { margin: 0; padding-left: 22px; }
li { font-size: 15px; margin-bottom: 8px; }
.note { font-size: 13px; color: #6b7280; display: block; }
.out { margin: 14px 0 0; font-size: 13px; color: #6b7280; }
</style>
</head>
<body>
<div class="wrap">
<h1>我的技能</h1>
<ul>
<li>HTML 结构与语义标签<span class="note">含列表、链接的组合</span></li>
<li>页面排版与移动端适配</li>
<li>把列表和链接组合成导航</li>
</ul>
<p class="out">以上按熟练度排序,持续更新中。</p>
</div>
</body>
</html>


v4:一组词配解释用 dl,语义才对得上
到这一步清单已经很稳了。但"技能名 + 熟练度"这种一个词配一段解释 的成对信息,用 ul 其实略勉强------它不是并列同类,而是"术语---描述"关系。HTML 给了专门的 <dl>:定义列表。<dt> 是被解释的词,<dd> 是解释。把它当语义收口,读屏器和搜索引擎能准确理解你的结构。

样式代码不用细看,理解为给网页化妆即可,CSS 专栏里会展开。
Plaintext
<!-- 《100天精通HTML基础入门》Day 16 · 平头哥 · 技术改变世界,勤奋改变人生 -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>技能清单 v4 · dl 语义收口</title>
<style>
/* dl 里 dt 是技能名,dd 是熟练度说明,一一对应 */
/* 一个 dt 后面可跟多个 dd,读屏器会把它俩关联起来 */
* { box-sizing: border-box; }
body { font-family: "Microsoft YaHei", sans-serif; background: #f7f5ef;
color: #24292f; margin: 0; line-height: 1.7; }
.wrap { max-width: 560px; margin: 24px auto; background: #fff;
border: 1px solid #d8d3c8; border-radius: 14px; padding: 24px 28px; }
h1 { font-size: 22px; margin: 0 0 12px; }
dt { font-size: 16px; font-weight: 700; color: #1b4055; margin-top: 10px; }
dd { margin: 2px 0 0 0; font-size: 14px; color: #4a5560;
padding-left: 14px; border-left: 3px solid #ffd166; }
</style>
</head>
<body>
<div class="wrap">
<h1>技能清单</h1>
<dl>
<dt>HTML 结构与语义</dt>
<dd>熟练:标签闭合、嵌套、列表与链接</dd>
<dt>页面排版</dt>
<dd>熟练:间距、对齐、留白</dd>
<dd>在学:移动优先与媒体查询</dd>
</dl>
</div>
</body>
</html>


到这里技能清单页做完了:v1 散装段落 → v2 一个 ul → v3 ol 带嵌套 → v4 dl 收口。四个版本每一版都比上一版更接近数据的真实关系,这正是演化式的价值------你不是背四个标签,是学会按"关系"选标签。
为什么列表天生带记号和缩进
停一下讲原理,因为这直接决定你以后敢不敢改它。浏览器对 HTML 有一套内置的默认样式(叫 UA 样式),ul、ol 一出现,它就自动套上 list-style 记号和一个约 40px 的左内边距。之所以给缩进,是为了让"这是一组"这件事在视觉上立刻成立,不依赖任何 CSS。你写 ul { padding-left: 20px } 那行,是在覆盖浏览器已经帮你做好的事,而不是从零造。
这条机制从 CSS 早期规范起就没变过,不依赖具体版本,长期适用。风险点在于:很多人嫌圆点丑,顺手写一句 ul { list-style: none } 想全页去掉------结果把这一页所有列表的点一起抹了。这一条怎么优雅地控制,是明天 Day 17 的正题。
顺带给一个更新说明:HTML 早期还有 <menu>、<dir> 两个专门用来做列表的老标签,如今已被 ul 替代、当作过时写法基本不再使用,新代码没必要去碰它;同样地,早年有人用嵌套 <table> 硬凑出列表的缩进和记号,那套做法的语义替代方案就是今天这组 ul/ol/dl。之所以强调"替代",是因为它们都能跑、不报错,和 Day 15 复盘里那批"能跑但不对"的旧习惯是同一类陷阱------正确性要靠语义,不靠肉眼看着像。
还有一个容易被忽略的边界:嵌套列表能套多深没有硬性上限,但每多一层,可读性和缩进都会指数级变差,超过两到三层就该换成小标题分节,而不是继续往里塞 ul。这一点属于经验约束,不是规范强制,适用时留意。
今天小结:清单成了,那个点却碍眼
这一页我们做了什么
-
v1:一堆
<p>手打序号,长得像清单但不是清单; -
v2:同级无序 → 一个
<ul>收成一挂,序号缩进交给浏览器; -
v3:有先后 →
<ol>,子清单往里嵌套但每层自带一个 ****ul; -
v4:词配解释 →
<dl>,语义收口。
两个坑各配一个动作:漏一层 ul 会让子项被拉平,补外壳即可;字写在 li 外面会脱离列表,收进 li 或移出 </ul>。下面这张表把四版各自的适用场景一次看全,你对着选就不会错。
| 版本 | 标签 | 内容关系 | 什么时候用它 |
|---|---|---|---|
| v1 | <p> 手打 |
无 | 只是过渡,别在正式页里这么写 |
| v2 | <ul>+<li> |
并列无序 | 技能、要点、标签云这类同级项 |
| v3 | <ol>+<li> |
有先后 | 步骤、排名、学习路径,可再嵌 ul |
| v4 | <dl>+<dt>+<dd> |
词配解释 | 术语表、技能名对熟练度说明 |
明天 Day 17 我们接着清单往下走:列表前面那个圆点太丑怎么办?用一行 list-style 让它消失,再把无点列表改造成导航的雏形------顺便讲清楚为什么随手一句 ul { list-style: none } 会让全页列表一起遭殃。
参考资料
我是平头哥,技术改变世界,勤奋改变人生。
《100天精通HTML基础入门》每天 20:00 更新,订阅专栏不迷路。