::marker 在 Chrome 86 之前版本中被静默忽略,不解析、不报错、DevTools 不显示,根本原因是浏览器 CSS 解析器直接跳过该伪元素规则。

为什么 ::marker 在 Chrome 里不生效
因为旧版 Chrome(::marker,Firefox 虽然支持但默认只允许改颜色、字体、内容,不能加背景或边框。如果你写了 li::marker { background: red; } 却没反应,不是写错了,是浏览器压根不认这个属性。
常见错误现象:::marker 样式完全被忽略,或者仅颜色生效,其他如 font-size、content 在部分版本中也不稳定。
- 检查浏览器版本:Chrome ≥ 110,Firefox ≥ 89,Safari ≥ 16.4 才有较完整支持
- 避免依赖
display、padding、background等布局类属性——它们在多数引擎中仍被忽略 - 可用属性其实很窄:仅
color、font-*系列、content(需配合list-style-type: none)、text-align(仅 Firefox)
list-style-type: none + ::before 是更稳的替代方案
当需要圆点变图标、加背景、响应式缩放或兼容 IE/旧 Safari 时,放弃 ::marker,用 li 自己造标记更可靠。
使用场景:设计系统组件、CMS 输出列表、需要 SVG 图标作为标记的导航菜单。
立即学习“前端免费学习笔记(深入)”;
li {
list-style-type: none;
position: relative;
padding-left: 2em;
}
li::before {
content: "•";
position: absolute;
left: 0;
color: #3b82f6;
font-size: 1.2em;
}
- 必须设
position: relative在li上,否则::before会相对父容器定位 -
padding-left要大于标记宽度,否则文字可能重叠 - 若用 SVG,推荐内联
url("data:image/svg+xml,...")或background-image,避免额外请求
用 content 动态生成标记内容要小心编码
::marker { content: "→ "; } 看似简单,但 Unicode 空格、全角符号、换行符会导致渲染错位或截断。
参数差异:CSS 中的 content 不支持变量或 JS 表达式,只能写死字符串或 attr() 取属性值。
- 避免用中文空格、不间断空格(
),改用普通 ASCII 空格或margin-inline-start控制间距 - 若从 HTML 属性读取,比如
<li data-marker="★">,写成content: attr(data-marker);,注意属性值不能含引号或 CSS 特殊字符 - Firefox 对
content在::marker中的支持比 Chrome 更早,但依然不支持counter()
性能与可访问性隐性代价
视觉上自定义标记很灵活,但屏幕阅读器仍按原 list-style-type 解析语义。比如你用 ::before 显示 “✓”,AT(辅助技术)仍会读 “list item” 而非 “checked item”。
这不是 bug,是规范行为:标记样式属于呈现层,不改变 ARIA 角色或列表语义。
- 如需语义强化,显式加
aria-label(例如<li aria-label="已完成:上传文件">) - 慎用动画:给
::marker或::before加transition可能触发重排,尤其在长列表中滚动时掉帧 - 不要为了“统一”强行用 CSS 覆盖所有列表——无序列表(
ul)和有序列表(ol)的标记逻辑本质不同,混用易出歧义
真正难的从来不是怎么画个好看的点,而是让这个点在各种浏览器、各种设备、各种辅助技术里,既看起来对,又读起来对,还动起来不卡。



















