在 HTML 的世界里,<ul> 和 <ol> 是最简单也最容易被低估的元素。许多开发者只把它们当作“加点圆点或数字的容器”,却忽略了它们所承载的结构语义、可访问性价值以及严格的嵌套规则。  

本文将带你重新认识这两个基础元素,从语义本质 → 正确结构 → 渲染机制 → 样式控制 → 可访问性 → 实战技巧六个维度,系统梳理无序列表与有序列表的正确用法,帮助你写出更健壮、更专业的前端代码。

一、语义:它们表达“关系”,而不是“样式”

元素

语义含义

典型场景

<ul>(Unordered List)

无序列表,条目之间为并列关系,顺序无关紧要

导航菜单、商品特性、标签列表

<ol>(Ordered List)

有序列表,条目之间存在顺序或步骤关系

操作步骤、排行榜、时间线

核心原则:语义由 HTML 元素本身决定,而非视觉表现。

即使你用 CSS 将 <ol> 的编号改为圆点,它在语义层面依然是“有序列表”,屏幕阅读器依然会按顺序朗读。

二、DOM 结构:严格遵循嵌套规则

标准结构
<ul>
  <li>苹果</li>
  <li>香蕉</li>
</ul>

<ol>
  <li>第一步:打开冰箱</li>
  <li>第二步:放入大象</li>
</ol>
多级列表(嵌套)
<ol>
  <li>
    前端基础
    <ul>
      <li>HTML</li>
      <li>CSS</li>
    </ul>
  </li>
  <li>
    框架
    <ul>
      <li>React</li>
      <li>Vue</li>
    </ul>
  </li>
</ol>
错误嵌套示例
<!-- 错误:ul 不能直接嵌套在 ul 下 -->
<ul>
  <ul>
    <li>错误写法</li>
  </ul>
</ul>

<!-- 错误:列表的直接子元素必须是 li -->
<ul>
  <div>这不是合法的列表项</div>
</ul>

核心规则

  • <ul> 和 <ol> 的 直接子元素只能是 <li>。

  • 嵌套列表必须放在 <li> 内部

三、<li>:列表的“原子单元”

<li> 是列表的最小组成单位,每个条目都应用 <li> 包裹。这样做的好处包括:

  • 语义明确:屏幕阅读器可准确识别“列表项”。

  • 样式可控:便于通过 CSS 统一控制间距、标记等。

  • 交互友好:便于 JavaScript 进行增删改查操作。

常见错误:用 <div> + 换行模拟列表,或用 <br> 手动分行,都会导致语义丢失、可访问性受损。

四、编号与符号:HTML 属性与 CSS 的分工

浏览器默认渲染

元素

默认 list-style-type

表现

<ul>

disc

实心圆点

<ol>

decimal

1, 2, 3 …

HTML 属性(仅 <ol>有效)
<!-- 从指定数字开始 -->
<ol start="3">
  <li>第三项</li>
  <li>第四项</li>
</ol>

<!-- 倒序 -->
<ol reversed>
  <li>第三项</li>
  <li>第二项</li>
  <li>第一项</li>
</ol>

<!-- 指定某一项的值 -->
<ol>
  <li value="10">第十项</li>
  <li>第十一项</li>
</ol>
CSS 控制(推荐方式)
/* 修改标记样式 */
ul {
  list-style-type: square;
}

ol {
  list-style-type: upper-roman;
}

/* 完全自定义标记(使用伪元素) */
ul.custom {
  list-style: none;
  padding-left: 0;
}

ul.custom li {
  padding-left: 1.5em;
  position: relative;
}

ul.custom li::before {
  content: "✓";
  position: absolute;
  left: 0;
  color: green;
}

/* 现代 CSS 增强:使用 ::marker 控制标记样式 */
li::marker {
  color: red;
  font-size: 1.2em;
}

提示:::marker 仅支持部分样式(如 color、font-size、content),但比伪元素方案更简洁。

五、布局与对齐:处理缩进与间距

浏览器默认会给列表添加左内边距(padding-left),以容纳标记符号。开发中常用以下方式调整:

/* 恢复列表无缩进,但保留标记 */
ul, ol {
  padding-left: 1.2em;  /* 保留合适空间 */
}

/* 完全移除缩进并自定义标记位置 */
ul.clean {
  list-style: none;
  padding-left: 0;
}
ul.clean li {
  padding-left: 1.2em;
  position: relative;
}

响应式适配:在小屏幕下,可适当减小左内边距,保证内容完整显示。

六、可访问性(A11Y):为所有人设计

屏幕阅读器(如 NVDA、VoiceOver、TalkBack)对列表的朗读方式如下:

  • <ul>:朗读为“列表,共 n 项”,每个 <li> 前提示“列表项”。

  • <ol>:朗读为“有序列表,共 n 项”,并播报当前序号。

最佳实践
  1. 语义优先:真正有顺序的内容使用 <ol>,不要为了样式改用 <ul>。

  2. 保持结构完整:列表项内容尽量保持语义单一,避免在 <li> 中嵌套过深的复杂布局。

  3. 提供替代信息:若使用 list-style: none,应通过文本或伪元素保留序号/层级信息。

  4. 辅助属性(可选):在复杂列表中可使用 role="list"、aria-label 增强语义。

<ol aria-label="蛋糕制作步骤">
  <li>准备材料</li>
  <li>混合搅拌</li>
</ol>

七、响应式与打印:额外考量

响应式列表
  • 在移动端,可将横向列表改为纵向,通过媒体查询调整 flex 或 grid 布局。

  • 注意标记与文本的间距,避免符号与文字重叠。

打印样式

默认情况下,浏览器打印时会保留列表标记。但若你使用 list-style: none 并自定义了伪元素,打印时伪元素可能无法正常显示。

建议在打印样式中恢复标记:

@media print {
  ul, ol {
    list-style-type: inherit;  /* 恢复默认标记 */
  }
  .custom-list {
    list-style-type: disc;  /* 强制使用圆点 */
  }
}

八、常见坑与解决方案(速查表)

问题

错误示例

正确做法

将列表用作布局容器

<ul><div>内容</div></ul>

使用<div>、<section>等布局元素

嵌套结构错误

<ul><ul>

嵌套列表必须放在 <li>内部

使用 <br> 模拟列表

 条目1<br>条目2

使用 <ul> + <li>

视觉符号消失无替代

list-style: none 无补充

使用伪元素或文本保留层级

顺序语义错位

操作步骤用 <ul>

使用 <ol> 保留顺序

忽略打印样式

打印时符号丢失

添加打印样式表,保留列表标记

无障碍缺失

列表项内无合适文本

确保列表项内容可读,必要时使用 aria-label

总结

<ul> 与 <ol> 是 HTML 中语义明确、结构严谨的基础元素。正确使用它们,不仅能让代码更规范、更易维护,还能显著提升网站的可访问性与用户体验。

三个核心原则:
  1. 语义优先:有序用 <ol>,无序用 <ul>。

  2. 结构正确:<ul> / <ol> 下只放 <li>,嵌套列表放 <li> 内部。

  3. 样式分离:用 CSS 控制视觉,保留 HTML 语义。

进阶技巧:
  • 利用 ::marker 精细控制标记样式。

  • 响应式与打印样式不可忽视。

  • 为屏幕阅读器补充 aria-label 增强语义。

掌握这些原则与技巧,你将不再把列表当作简单的“样式工具”,而是真正理解其作为 信息结构组件 的价值,写出更专业、更健壮的前端代码。

彩蛋

文中配有完整示例,点击《现代列表组件 · HTML ul/ol 深度实践》即可查看。