我正在阅读 Google 的 web.dev 博客上的 “创意列表样式”,并注意到文章中 ::marker
部分的一个代码示例有点奇怪。内置的列表标记是项目符号、序数和字母。::marker
伪元素允许我们为这些标记设置样式,或用自定义字符或图像替换它们。
::marker {
content: url('/marker.svg') ' ';
}
我注意到的示例使用 SVG 图标作为列表项的自定义标记。但是,在 CSS 值中,url()
函数旁边还有一个空格字符(" "
)。此空格的目的是在自定义标记之后插入一个间隙。

当我看到这段代码时,我立刻想知道是否有更好的方法来创建这个间隙。在 content
中追加空格感觉更像是解决方法,而不是最佳解决方案。CSS 提供了 margin
和 padding
以及其他标准方法来将页面上的元素间隔开。这些属性都不能在这种情况下使用吗?
首先,我尝试用适当的边距替换空格字符
::marker {
content: url('/marker.svg');
margin-right: 1ch;
}
这不起作用。事实证明,::marker
只支持 一小组主要与文本相关的 CSS 属性。例如,您可以更改标记的 font-size
和 color
,并通过将 content
设置为字符串或 URL 来定义自定义标记,如上所示。但是 margin
和 padding
属性 不受支持,因此设置它们不会产生任何效果。太令人失望了。
难道空格字符真的是在自定义标记之后插入间隙的唯一方法吗?我需要弄清楚。在研究这个主题的过程中,我有一些有趣的发现,我想在这篇文章中分享。
添加填充和边距
首先,让我们确认 <ul>
和 <li>
元素上的 margin
和 padding
的作用。为此,我创建了一个测试页面。拖动相关的滑块,并观察对列表标记两侧间距的影响。提示: liberally 使用“重置”按钮将所有控件重置为其初始值。
注意:浏览器会将 40px
的默认 padding-inline-left
应用于 <ol>
和 <ul>
元素。逻辑 padding-inline-start
属性等效于从左到右内联方向书写系统中的物理 padding-left
属性。在本文中,为了简单起见,我将使用物理属性。
如您所见,<li>
上的 padding-left
会增加列表标记之后的间隙。其他三个属性控制标记左侧的间距,换句话说,就是列表项的缩进。
请注意,即使列表项的 padding-left
为 0px
,标记之后仍然存在最小间隙。这个间隙无法用 margin
或 padding
缩小。最小间隙的精确长度取决于浏览器。

总而言之,列表项的内容的位置距离标记有一个浏览器特定的最小距离,并且可以通过在 <li>
上添加 padding-left
来进一步增加此间隙。
接下来,让我们看看当我们将标记定位到列表项内部时会发生什么。
将标记移动到列表项内部
list-style-position
属性接受两个关键字:outside
(默认值)和 inside
,它将标记移动到列表项内部。后者对于创建具有全宽列表项的设计很有用。

如果标记现在位于列表项内部,这是否意味着 <li>
上的 padding-left
不会再增加标记之后的间隙?让我们来了解一下。在我的测试页面上,通过复选框打开 list-style-position: inside
。这四个 padding
和 margin
属性受此更改的影响如何?
如您所见,<li>
上的 padding-left
现在会增加标记左侧的间距。这意味着我们已经失去了通过 padding-left
来增加标记之后的间隙的能力。在这种情况下,能够在 ::marker
本身添加 margin-right
非常有用,但正如我们之前所说,那并不可行。

此外,在 Chromium 中有一个错误,导致在切换到 inside
定位后,标记之后的间隙增加到原来的三倍。默认情况下,间隙的长度约为文本大小的三分之一。因此,在默认的 font-size
为 16px
时,间隙约为 5.5px
。在切换到 inside
后,间隙在 Chrome 中增长到完整的 16px
。此错误会影响 disc
、circle
和 square
标记,但 不会影响序数标记。
下图显示了三种主要浏览器在 macOS 上对外部和内部定位的列表标记的默认渲染。为了方便起见,我已经将所有列表项在其标记上水平对齐,以便于比较间隙大小的差异。

总而言之,切换到 list-style-position: inside
会带来两个问题。我们无法再通过 <li>
上的 padding-left
来增加间隙,并且间隙大小在不同浏览器之间不一致。
最后,让我们看看当我们用自定义标记替换默认列表标记时会发生什么。
切换到自定义标记
有两种方法可以定义 自定义标记
list-style-type
和list-style-image
属性::marker
伪元素上的content
属性
content
属性功能更强大。例如,它允许我们使用 counter()
函数访问列表项的序数(隐式 list-item
计数器),并用自定义字符串装饰它。
不幸的是,Safari 尚未支持 ::marker
上的 content
属性(WebKit 错误)。出于这个原因,我将使用 list-style-type
属性来定义自定义标记。您仍然可以使用 ::marker
选择器来设置通过 list-style-type
声明的自定义标记的样式。::marker
的这方面在 Safari 中受支持。
任何 Unicode 字符都有可能用作自定义列表标记,但只有少数字符在其官方名称中实际上包含“项目符号”,所以我想在这里将它们列出来供参考。
字符 | 名称 | 代码点 | CSS 关键字 |
---|---|---|---|
• | 项目符号 | U+2022 | disc |
‣ | 三角形项目符号 | U+2023 | |
⁃ | 连字符项目符号 | U+2043 | |
⁌ | 黑色左向项目符号 | U+204C | |
⁍ | 黑色右向项目符号 | U+204D | |
◘ | 反向项目符号 | U+25D8 | |
◦ | 白色项目符号 | U+25E6 | circle |
☙ | 反向旋转花卉心形项目符号 | U+2619 | |
❥ | 旋转加粗黑色心形项目符号 | U+2765 | |
❧ | 旋转花卉心形项目符号 | U+2767 | |
⦾ | 圆圈白色项目符号 | U+29BE | |
⦿ | 圆圈项目符号 | U+29BF |
注意:CSS square
关键字在 Unicode 中没有相应的“项目符号”字符。最接近的字符是黑色小型方块(▪️)表情符号(U+25AA
)。
现在让我们看看当我们将默认列表标记替换为 list-style-type: "•"
(U+2022
项目符号)时会发生什么。这与默认项目符号是相同的字符,因此不应该有任何重大的渲染差异。在我的测试页面上,打开 list-style-type
选项,并观察对标记的任何更改。
如您所见,有两个重大变化
- 标记之后不再存在最小间隙。
- 项目符号变小了,就好像它是在较小的
font-size
下渲染的一样。
根据 CSS 计数器样式级别 3,默认列表标记(disc
)应该“类似于 • U+2022
项目符号”。似乎浏览器会增大默认项目符号的大小以使其更易于阅读。Firefox 甚至为标记使用了一种特殊的字体,-moz-bullet-font
。

CSS 可以解决尺寸过小的问题吗?在我的测试页面上,打开标记样式,观察当你改变标记的 `font-size`、`line-height` 和 `font-family` 时会发生什么。
正如你所看到的,增大 `font-size` 会导致自定义标记在垂直方向上错位,并且无法通过减小 `line-height` 来纠正。`vertical-align` 属性可以轻松解决这个问题,但它不支持 `::marker`。
但是你注意到改变 `font-family` 可以使标记变大吗?尝试将其设置为 `Tahoma`。这可能是一个足够好的解决尺寸过小问题的办法,尽管我没有测试过哪种字体在主流浏览器和操作系统上效果最佳。
你可能还注意到,当你将标记定位在列表项内部时,Chromium 的错误不再出现。这意味着自定义标记可以作为该错误的解决方法。这也导致了我的主要问题,也是我开始研究这个主题的原因。**如果你定义一个自定义标记并将其定位在列表项内部,标记后面没有间隙,并且没有办法用标准方法插入间隙。**
- 自定义标记后面没有最小间隙。
::marker
不支持 `padding` 或 `margin`。<li>
上的 `padding-left` 不会增加间隙,因为标记是定位在 `inside` 的。
总结
以下是本文中提到的所有关键事实的总结
- 浏览器会对 `<ul>` 和 `<ol>` 元素应用默认的 `padding-inline-start` 为 `40px`。
- 内置列表标记(`disc`、`decimal` 等)后面有最小间隙。自定义标记(字符串或 URL)后面没有最小间隙。
- 可以通过向 `<ul>` 添加 `padding-left` 来增加间隙的长度,但这只有在标记定位在列表项外部(默认模式)时才有效。
- 自定义字符串标记的默认尺寸比内置标记小。更改 `::marker` 上的 `font-family` 可以增大其尺寸。
结论
回顾文章开头的代码示例,我认为我现在明白为什么 `content` 值中有一个空格字符。没有比这更好的方法来在 SVG 标记后面插入间隙了。这是一个必要的解决方法,因为无论使用多少 `margin` 和 `padding`,都无法在定位在列表项内部的自定义标记后面创建间隙。`::marker` 上的 `margin-right` 可以轻松做到这一点,但它不支持。
在 `::marker` 添加对更多属性的支持之前,Web 开发人员往往别无选择,只能隐藏标记并使用 `::before` 伪元素来模拟它。我最近不得不自己这样做,因为我无法更改标记的 `background-color`。希望我们不用等太久就能拥有更强大的 `::marker` 伪元素。
我以为只有我想要使用它 ;)
我有一些带 SVG 图像的自定义列表样式。我一直想知道为什么 padding 和 margin 不起作用。我打算编辑我的图形并在右侧添加一些空白… 但是后来我发现了以下属性并将其与我的情况中的 0.3em 一起使用
padding-inline-start
https://caniuse.cn/mdn-css_properties_padding-inline-start
这篇文章写得很好。我试图在以 `inline` 方式显示的 `<ol>` 中定位一个 `marker` 伪元素,但事实证明这非常具有挑战性!
感谢你,我在这场战斗中感觉很孤独。感觉自己像是“来自过去”的人,因为无法垂直对齐愚蠢的标记…
可以确认。现在是 2038 年,人类对列表符号的控制力仍然比我们对 AI 统治者的控制力要低。