::marker伪元素存在兼容性与功能限制,应优先使用并配合list-style:none+::before回退;它仅支持内容、颜色、字体等基础样式,不支持背景、边框等,且对display:inline的li无效;需通过css变量与counter()结合实现动态序号;自定义符号时须兼顾可访问性,保留语义结构。

li 的 marker 伪元素不支持所有浏览器,别直接当通用方案用
Chrome 和 Edge 117+、Firefox 68+ 支持 ::marker,但 Safari 直到 iOS 17.4 / macOS 14.4 才开始有限支持(且不支持背景、渐变等),旧版 Safari 完全忽略。如果你的项目要兼容 iOS 16 或更早用户,::marker 不能作为唯一手段。
真正稳妥的做法是:优先用 ::marker 写现代样式,再用 list-style: none + ::before 回退。不是“二选一”,而是“先试新、再兜底”。
-
::marker只能控制内容、颜色、字体、text-align,不能设 background、border、padding、transform - 它对
display: inline的li无效 —— 必须保持默认display: list-item - 不能通过 JavaScript 动态修改
::marker的 content,只能靠 CSS 变量间接影响(见下一条)
用 CSS 变量 + ::marker 实现可配置的序号样式
原生 ::marker 的 content 不接受变量,但可以用 counter() 配合 --counter-value 这类自定义属性,在伪元素里“模拟”动态序号。不过更实际的路径是:用 counter-increment 控制计数,再用 ::marker 绑定 counter(),同时用 :root 或父容器设置变量控制颜色/大小。
ol {
counter-reset: step;
}
ol li {
counter-increment: step;
}
ol li::marker {
color: var(--marker-color, #333);
font-weight: 600;
}
ol li::marker {
content: counter(step) ". ";
}
注意:content 在 ::marker 里写死没问题,但如果你需要不同层级用不同前缀(比如 “1.1” “1.2”),就得嵌套 counter(),这时必须确保父级 ol 有对应 counter-reset 和 counter-increment。
立即学习“前端免费学习笔记(深入)”;
用 ::before 替代 marker 的典型回退写法
当 ::marker 不可用时,主流做法是关掉原生符号,改用 ::before 模拟。关键点不在“怎么加”,而在“怎么对齐”和“怎么避免重叠”。
- 必须给
li设list-style: none,否则原生符号和::before会并存 -
::before推荐用position: absolute+left: -1.5em,而不是float: left—— 后者在 flex/grid 容器里容易失效 - 文字缩进要用
padding-left补齐,值建议设为1.5em左右,和::before的 left 值匹配 - 如果要支持 RTL(右向文本),
left得换成right,或用inset-inline-start
li {
list-style: none;
position: relative;
padding-left: 1.5em;
}
li::before {
content: "•";
position: absolute;
inset-inline-start: 0;
color: #666;
font-size: 1.2em;
}
自定义符号时最容易被忽略的可访问性问题
用 ::before 或 ::marker 替换原生符号后,屏幕阅读器可能读不出序号或符号含义。例如 content: "→" 对视障用户就是个无意义符号。
- 如果是有序列表,保留
ol结构,哪怕视觉上隐藏了数字 —— 屏幕阅读器仍会播报序号 - 如果用了
ul+::before模拟箭头,建议加aria-label="步骤 1"或用role="listitem"+aria-setsize/aria-posinset - 不要用图片替代符号(比如
background-image),除非同时提供aria-hidden="true"并确保语义由 HTML 承担
最省事又合规的方式:用 ol 或 ul 保持语义结构,只改样式,不碰语义标签。复杂样式可以加,但别为了效果牺牲结构。










