前言

ul > li 经常会用到, 它原本的 style 很丑, 这篇介绍如果修改它.

以前学 W3Schools 的时候也有记入过: HTML – W3Schools 学习笔记

参考:

Youtube – HTML & CSS for Beginners Part 17: How to Create and Style HTML Lists

Youtube – Styling your list-items just got so much easier with this pseudo-element!

Youtube – Next-Level List Bullets With CSS ::marker

Custom bullets with CSS ::marker

HTML 默认

<div class="container">
<ul>
<li>item1</li>
<li>item2</li>
</ul>
</div>

效果

红框是 container 范围. 整个 ul 默认有一个 padding-left 40px.

如果有写 reset CSS 的话, 那么它的 padding 通常是 0

bullet 会神奇的跑出去...

list-style-type

常见的 type 有: circle, alpha, roman, decimal

甚至可以直接写 string 哦

li {
list-style-type: "> ";
}

效果

list-style-position

它的功能是设置 bullet 是在 inside 还是 outside, 默认是 outside.

padding-left: 40px 的长相:

padding-left: 0 的长相:

inside 有个体验问题, 第 2 行的字没有和第一行对齐, 反而跑到了 bullet 的区域, 这样很不整齐..

Tailwind CSS 的解释图, 非常清晰:

美化 by Default Style

先来一个最简单的美化

下面是 HTML,之后的几个美化都用这个 HTML 做 sample。

<div class="container">
<h1>Title</h1>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Odio asperiores ut nesciunt harum, in quibusdam.</p>
<ul>
<li>item1</li>
<li>item2</li>
</ul>
</div>

CSS Style

* {
margin: 0;
padding: 0;
box-sizing: border-box;
} .container {
width: 428px;
margin-inline: auto;
margin-top: 256px; padding: 24px 16px;
border: 1px solid red; h1 {
font-size: 32px;
font-weight: 700;
} p {
margin-top: 8px;
line-height: 1.3;
} ul {
margin-top: 8px;
}
}

效果

主要的问题就是 li 的点(aka marker)跑出去了。

在 ul 加上 padding-left 就可以了

ul {
margin-top: 8px;
padding-left: 16px;
}

效果

value 16px 是依据 font-size 决定的哦。假设我把 li 的 font-size 改成 24px

结果 padding-left: 16px 就不足够了。所有一般上会设置成 2ch,font-size x 2 的意思。

ul {
margin-top: 8px;
font-size: 24px;
padding-left: 2ch;
}

效果

Limitation

marker 的 size 一定和 font-size 一样。无法设置成 marker 很小,但是字很大,因为 marker 和 font 都是通过 font-size 控制的,所以只能一样大小。

美化 by Default Style ::marker

上面有提到,marker 的 pattern 只有几款 e.g. circle, alpha, roman, decimal 等。

我们可以通过伪元素来做一些 customize。

ul {
margin-top: 8px;
font-size: 24px;
padding-left: 2.4ch; ::marker {
content: '';
}
}

效果

我把 marker 改成了 emojy。(注:padding-left 改成了 2.4ch,依据不同的 content 需要改成不同的 value 哦)

Limitation

1. not fully support svg,marker content 虽然可以 url(path/icon.svg) 但是它不支持 sprite,也不可以 height: 1em,必须在 svg 写上 width height,还有 fill="currentColor" 也不行。

2. 虽然 marker size 可以被调小,让 marker 和字体大小不一样,但是大小不一之后,对齐是不可控的,它只能是 baseline。

小总结

如果 marker 和 text 的大小可以一样。

如果 marker 不需要用到 svg。

那我们可以用上面简单的 default style 方案去美化。如果要用 svg icon 那最好用下面的方案。

美化 by Custom Style

我们来突破上面的 limitation。假设我们需要

1. icon 和 text 大小不一

2. icon 要用 svg

3. text 有 multipl line

首先在 HTML 加上 svg icon

<ul>
<li>
<svg fill="currentColor" height="1em" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"/>
</svg>
Lorem ipsum dolor sit amet consectetur adipisicing elit. !
</li>
<li>
<svg fill="currentColor" height="1em" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"/>
</svg>
item2
</li>
</ul>

CSS Style

ul {
margin-top: 8px;
font-size: 24px;
list-style: none; svg {
color: red;
font-size: 24px;
}
}

效果

问题 1: multiple line 导致字跑去 marker 下面

上面的图,第二行字跑到了 icon 下面,下图才是正确的样子

我们可以用 display flex 来破

li {
display: flex;
gap: 8px; svg {
flex-shrink: 0;
}
}

效果

问题 2: 当 icon 和 text 大小不一时, vertical align 不整齐

有两种情况

icon 比字小

当 icon 只有 16px,而字有 32px 时,长这样

display flex 默认的 align-items 是 normal,所以它一开始就长那样。

我们试试 align-items center 和 baseline

第一个是 baseline,第二个是 center。

只有 center + single text 效果是 ok 的,其它的都不美。

要解决这个问题,我们需要 wrap icon,而且需要知道 text 的 line height。

在 HTML 加上一个 icon wrapper

<div class="icon-wrapper">
<svg fill="currentColor" height="1em" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"/>
</svg>
</div>

CSS Style

li {
display: flex;
gap: 8px; .icon-wrapper {
display: flex;
justify-content: center;
align-items: center;
height: calc(32px * 1.3);
}
}

text 的 font-size 是 32px,line-height 是 1.3,icon-wrapper height 必须和它一样。

效果

icon 比字大

解决方法和 icon 比字小是一致的,通过一个 text-wrapper

<p class="text-wrapper">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolore omnis excepturi quaerat delectus assumenda enim doloremque maxime nisi ipsa labore!
</p>

CSS Style

li {
display: flex;
gap: 8px; .text-wrapper {
min-height: 32px;
display: flex;
justify-content: center;
align-items: center;
}
}

32px 是 icon 的 size。

效果

总结

如果不需要 svg icon,建议使用 marker 就好,简单。

如果要 svg icon,text 和 icon 一样大,text 只有 single line,可以用 align-items: center 做对齐。

如果有 multiple 但大小一致,那勉强可以用 baseline。

如果大小不一致,最好的 solution 就是搞 wrapper。

description list (dl > dt + dd)

<dl>
<dt>Coffee</dt>
<dd>Black hot drink</dd>
<dt>Milk</dt>
<dd>White cold drink</dd>
</dl>

默认样式

它会一左一右是因为有 margin

但这种一高一低一左一右, 真的很丑. 所以很多人都问怎样让它一左一右就好. 类似 key value pair

stackoverflow – How to style dt and dd so they are on the same line?

首先是 standard 的 reset CSS, 去掉原本的 margin

* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

然后用 Flex 就可以了

dl {
display: flex;
flex-wrap: wrap;
row-gap: 1rem; dt {
flex: 0 0 50%;
}
dd {
flex: 0 0 50%;
}
}

其原理是让每个 item 占据 50%, 那么 1 row 最多只能容纳 2 个 item, 也就是 1 个 dt 和 1 个 dd.

然后剩余的就 wrap 往下掉. 再做一个 row-gap 让 row 有 spacing 就可以了

Grid 的写法也是更简单

dl {
display: grid;
grid-template-columns: 1fr 1fr;
row-gap: 1rem;
}

Float 的写法

dt,
dd {
&:nth-child(n + 3) {
margin-top: 1rem;
}
width: 50%;
float: left;
}

TODO

下面是我之前写的,上面是更新了的,过阵子确定没有遗漏就可以把下面洗掉了

Custom Styling

use Flex

设置 list-style-type: none. 在 HTML/CSS 写 icon 用 Flex 做间距.

.container {
border: 1px solid black;
width: fit-content;
min-width: 200px; padding: 0.5rem;
ul {
list-style-type: none;
li {
&::before {
font: var(--fa-font-solid);
content: "\f00c";
padding-right: 0.25rem;
}
}
}
}

效果

用 Flex 的好处是直观, 最大的问题是 align-items. Flex 只能 center 或者 baseline, 没用办法做法 vertical-align: middle

当 bullet 和 text 的大小不一致又有 2 行 text 时, 就会有麻烦了.

除非我们知道 line-height 那就可以在 icon wrap 一层居中 icon. 但 hardcode line-height 不顺风水, 不同 font-family line-height 是不太一样的, lh unit 目前又还不支持.

目前无解.

use pseudo background image

参考: codepen example

li :: before 这种做法在 text 有 2 行的时候, 第 2 行会在 icon 下面. 解决方法是定位 (但是这个很不顺风水)

use ::marker

如果只是想换 icon 用 build-in 的 ::marker 会很方便, 虽然它没有 cover 100% 场景 (不支持 margin, padding), 但是通常够用了.

ul {
font-size: 2rem;
li {
padding-left: 0.5rem;
}
::marker {
color: red;
font: var(--fa-font-solid);
content: "\f00d";
}
}

marker 可以选中 bullet, 然后就可以自定义内容了. 上面用了 fontawesome 的 code. 效果:

也可以换成 text, url(svg..) 等等

::marker {
color: red;
content: "> " counter(list-item);
}

还可以配上 counter 输出 index 哦.

它有 2 个问题

1. svg sprite 不行, 还有 svg 的 width, height 无法通过 font-size 控制 (即使在 svg 里写 width:1em 也没用, 可能是 ::marker 搞的鬼吧), 总之理想的做法是用 fontawesome

2. 当 icon 和 text 大小不一致时, 需要把 text 用 span wrap 起来然后设置 vertical-align: middle

注: 这个操作会导致 line-height 变大到 1.4 左右哦,

而且必须是 display: inline, inline-block 会变成 align center (like Flex), block 会变成 baseline

stackoverflow – Vertically align smaller bullets with larger text

总之它没有办法很容易的做出正确的 alignment, Google 给的例子也是同样的问题, 参考: Custom bullets with CSS ::marker

use list-style-image

参考: MDN – list-style-image

最大的问题是 svg 的大小无法用 CSS 控制. 只能写死在 svg 里

注意事项

1. icon, text 大小不一致时要 vertical-align 或 aligh-items

2. Flex, icon 要 flex-shrink:0 当遇到 2 行时它无法像 vertical-align 那样居中

3. svg 不管用 ::marker, ::before, list-style-image 都不顺, 尽可能用 fontawesome, 真的没办法就用 HTML svg + Flex 方案

4. 最佳方案是 ::marker 配 fontawesome, icon text 大小不一致时需要 vertical-alight: middle

间距问题

有 2 个间距挺烦人的,

第 1 个是 bullet 和 container 的间距.

ul 默认 position outside, bullet 不占据空间, 它依靠 padding-left 40px 把 bullet 弄出来.

但是这个 padding-left 不容易控制, 通常放 1.2em, 2ch, 或者 same font-size with bullet, 如果是字, 比如 "Step 1:" 用 ch 比较准. 但也只是大概准而已.

它的关键就在于 bullet 不占位子. 得靠 padding, 而这个 padding 就依赖 bullet 的大小, 然后只可以大概调.

如果用 inside 的话, 它就会刚刚好, 但是 second line 就对不齐了

我本来以为, 自己搞 Flex 就可以搞定这个对齐的问题. 后来我发现并不那么容易.

假如我们用 icon 替代 bullet, 然后让 li > icon + text, 在 li 做 Flex.

这个时候 vertical align 就难搞了. 这个 bullet 小于 text, 它又在 text 的中心, 这个是 vertical-align: middle 才做的到. 而 flex 只能 align-items: baseline.

除非我们知道 line-height 那就可以在 icon wrap 一层居中 icon. 但 hardcode line-height 不顺风水, 不同 font-family line-height 是不太一样的, lh unit 目前又还不支持.

第 2 个是 bullet 和 text 的间距.

这个是通过 li padding-left 控制的. ::marker 是写不到 padding 和 margin 的哦.

也有人通过 content: '\空格' 来实现.  .

相关参考:

stackoverflow – How to keep indent for second line in ordered lists via CSS?

CSS – Indenting the second line of LI (List Items)

HTML & CSS – Styling List的更多相关文章

  1. 【转】Styling And Animating SVGs With CSS

    原文转自:http://www.smashingmagazine.com/2014/11/03/styling-and-animating-svgs-with-css/?utm_source=CSS- ...

  2. 自定义文件上传的按钮的样式css+js

    核心就是一段css遮住了原生的input框,然后用js将文件的值传入到另一个指定的input框中 原文链接 http://geniuscarrier.com/how-to-style-a-html-f ...

  3. HTML&CSS学习笔记

    <table> <thead> <tr>            // table row <th></th> // table head & ...

  4. [codecademy]fonts in css

    Great job! You learned how to style an important aspect of the user experience: fonts! Let's review ...

  5. 纯div+css制作的弹出菜单

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. CSS 浏览器兼容

    1.  兼容 IF <!--[if lte IE 7]> <style type="text/css"> .menu { position:relative ...

  7. [Angular] How to styling ng-content

    Let's say you are builing a reuseable component. The style structure like this: div > input If yo ...

  8. (转) [it-ebooks]电子书列表

    [it-ebooks]电子书列表   [2014]: Learning Objective-C by Developing iPhone Games || Leverage Xcode and Obj ...

  9. jQuery插件之simplemodal

    1.simplemodal在内部定义了如下css类 simplemodal-overlay:遮罩 simplemodal-container:弹出窗口容器 simplemodal-wrap simpl ...

  10. BigPipe学习研究

    BigPipe学习研究   from: http://www.searchtb.com/2011/04/an-introduction-to-bigpipe.html 1. 技术背景 FaceBook ...

随机推荐

  1. 如何支持同一台电脑上使用不同版本的Node.js版本

    在我们实际项目开发过程中,经常不同项目使用的node.js版本会也有所不同,为了方便维护不同版本的项目.可以使用nvm来解决. 1.下载nvm https://github.com/coreybutl ...

  2. apache ab.exe压力测试

    ab.exe是一个性能检测工具,是apache server中的一个小组件,使用简单,方便     下载地址:http://files.cnblogs.com/files/gossip/ab.zip ...

  3. 单细胞测序最好的教程(十):细胞类型注释迁移|万能的Transformer

    作者按 本章节主要讲解了基于transformer的迁移注释方法TOSICA,该算法在迁移注释上达到了SOTA的水平,在注释这么卷的赛道愣是杀出了一条血路.本教程首发于单细胞最好的中文教程,未经授权许 ...

  4. 70%的人都答错了的面试题,vue3的ref是如何实现响应式的?

    前言 最近在我的vue源码交流群有位面试官分享了一道他的面试题:vue3的ref是如何实现响应式的?下面有不少小伙伴回答的是Proxy,其实这些小伙伴只回答对了一半. 当ref接收的是一个对象时确实是 ...

  5. SecureCRT通过vbs脚本实现自动化登录linux服务器

    1.配置登录主机名.用户和密码 2.配置登录后操作脚本目录 3.vbs操作脚本如下(crt也支持python) #$language = "VBScript" #$interfac ...

  6. 如何使用ventoy安装操作系统

    使用ventoy安装操作系统 vrntoy简介 简单来说,Ventoy是一个制作可启动U盘的开源工具. 有了Ventoy你就无需反复地格式化U盘,你只需要把 ISO/WIM/IMG/VHD(x)/EF ...

  7. 测试环境配置https+端口访问留存

    步骤1:阿里云DNS配置本地公网IP解析 步骤2:本地局域网192.168.1.10服务器配置nginx server { listen 8090 ssl; server_name localhost ...

  8. ByteHouse高性能向量检索实践——“以图搜图”

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群   随着 LLM 技术的发展,向量检索与向量数据库也受到业界持续关注,它们能够为LLM提供外置记忆单元,通过提供与 ...

  9. 【AJAX】Asynchronous JavaScript And XML (非同步的JS & XML)

    什么是AJAX? 按照使用的感觉来看 说到底就是一个可以不刷新网页就能发送POST & GET请求的技术 AJAX 即"Asynchronous Javascript And XML ...

  10. Continue-AI编程助手本地部署llama3.1+deepseek-coder-v2

    领先的开源人工智能代码助手.您可以连接任何模型和任何上下文,以在 IDE 内构建自定义自动完成和聊天体验 推荐以下开源模型: 聊天:llama3.1-8B 推理代码:deepseek-coder-v2 ...