這篇筆記技術成分不高,主要是自己備忘用的。如果你已知道(或是完全不想知道)怎麼在網頁用 <ol> <li> 配 CSS 做出如下圖的 1) 2)、3.1、3.2,請略過本文。

寫了十幾年網頁,前陣子才遇到這個需求。條文資料分兩層 <ol> <li>,第一層用 1. 2. 3.,第二層要顯示成 1) 2) 3)。若是 Word 文件我知道怎麼做,在網頁做倒是第一次。

爬了文章,MDN Web Docs 有說明與範例 ,主要原理是利用 counter-reset: counterVarName; 重設計數器,在 <li> 宣告 counter-increment: counterVarName; 自動跳號、content: counter(section) ". "; 指定呈現格式。

      1. 案例我在第二層 <ol> 加了 class="sub",然後用 li::marker 將跳號格式設為 content: counter(count) ') '; :Live Demo
<!DOCTYPE html>

<html>
<head>
    <style>
    ol.sub {
        padding-left: 20px;
        padding-inline-start: 20px;
        counter-reset: count;
    }
    ol.sub li {
        counter-increment: count;
    }
    ol.sub li::marker {
        content: counter(count) ') ';
    }
    </style>
</head>
<body>
    <ol>
        <li>First</li>
        <li>Second</li>
        <li>
            Third
            <ol class="sub">
                <li>Sub-First, Lorem ipsum dolor sit amet, 
                consectetur adipiscing elit. 
                Aliquam mattis mauris et elit luctus, 
                at condimentum odio rhoncus.</li>
                <li>Sub-Second</li>
            </ol>
        </li>
        <li>Forth</li>
        <li>Fifth</li>
    </ol>
</body>

這個寫法在 Chrome 顯示很完美,可是瑞凡,IE 他X的不支援 ::marker 偽元素啊....

替代寫法是用 libefore 取代 limarker,並用 list-style-type: none 取消內建跳號,但 li 文字如有多行,跟數字會靠左對齊,不符合慣例,肯定要被客戶挑剔: (內心 OS: 大家都別用 IE 了好嗎?放過 IE 也放過自己...)

最後我試著將 li::before 設成 postion: absolute + margin-left: -1.2em,得到可接受的結果: Live Demo

<!DOCTYPE html>

<html>
<head>
    <style>
    ol.sub {
        padding-left: 1.5em;
        padding-inline-start: 1.5em;
        counter-reset: count;
    }
    ol.sub li {
        counter-increment: count;
        list-style-type: none;
    }
    ol.sub li::before {
        content: counter(count) ') ';
        position: absolute;
        margin-left: -1.2em;
    }
    </style>
</head>
<body>
    <ol>
        <li>First</li>
        <li>Second</li>
        <li>
            Third
            <ol class="sub">
                <li>Sub-First, Lorem ipsum dolor sit amet, 
                consectetur adipiscing elit. 
                Aliquam mattis mauris et elit luctus, 
                at condimentum odio rhoncus.</li>
                <li>Sub-Second</li>
            </ol>
        </li>
        <li>Forth</li>
        <li>Fifth</li>
    </ol>
</body>

IE 跟 Chrome 檢視都 OK。

多層跳號還有一個花式用法:content: counters(count, '.') ' ' 配多層 <ol> 可做出 3、3.1、3.1.1 的效果。為了支援 IE,我又得含淚放棄好用的 li::marker,改用 li:before + postion: absolute + margin-left: 負值算位置。但挑戰來了,3 跟 3.1.1 寬度差很多,若預留放得下 3.1.1 寬度,對 3 及 3.1 會留白過多,像以下這樣:

最後我想到的解法是在第二、三層 <ol> 加上 class="l2" / class="l3" (或者不加 class,靠 ol ol、ol ol ol 選擇器自動識別也可以),再指定不同 padding-left 及 margin-left:Live Demo

<!DOCTYPE html>

<html>
<head>
    <style>
    ol {
        padding-left: 1.2m;
        padding-inline-start: 1.2em;      
        counter-reset: count;
    }
    li {
        counter-increment: count;
        list-style-type: none;      
    }
    li::before {
        content: counters(count, '.') ' ';
        display: block;
        position: absolute;
        margin-left: -1.2em;
    }
      ol.l2 {
        padding-left: 2em;
        padding-inline-start: 2em; 
      }
      .l2 li::before {
        margin-left: -2em;
      }
      ol.l3 {
        padding-left: 2.8em;
        padding-inline-start: 2.8em; 
      }
      .l3 li::before {
        margin-left: -2.8em
      }
    </style>
</head>
<body>
    <ol>
        <li>First</li>
        <li>Second</li>
        <li>
            Third
            <ol class="l2">
                <li>Sub-First
                    <ol class="l3">
                      <li>Sub-Sub-First Lorem ipsum dolor sit amet, 
                      consectetur adipiscing elit. 
                      Aliquam mattis mauris et elit luctus, 
                      at condimentum odio rhoncus.</li>
                      <li>Sub-Sub-Second</li>
                    </ol>
                </li>
                <li>Sub-Second</li>
            </ol>
        </li>
        <li>Forth</li>
        <li>Fifth</li>
    </ol>
</body>
</html>

逐層設 class 及指定 margin-left、padding-left 的寫法有點笨拙,但看起來還堪用就是了。

大家如果知道其他巧妙解法,歡迎分享給我。

[2020-12-19 更新] 在專頁貼文後,讀者 Kei Cheng 分享了他的 CSS Framework - Kule Lazy 4,從中我偷學到改用 table-row、table-cell 解決 3、3.1、3.1.1 的對齊問題,比原本為各層設定不同 margin-left、padding-left 的寫法簡潔許多: Live Demo

<!DOCTYPE html>

<html>
<head>
    <style>
    ol {
        counter-reset: count;
        padding-left: 0;
    }
    li {
        counter-increment: count;
        list-style-type: none;      
        display: table-row;
    }
    li::before {
        content: counters(count, '.') ' ';
        display: table-cell;
        min-width: 2.5em;
        padding-right: 0.25em;
        text-align: right;
    }
    </style>
</head>
<body>
    <ol>
        <li>First</li>
        <li>Second</li>
        <li>
            Third
            <ol>
                <li>Sub-First
                    <ol>
                      <li>Sub-Sub-First Lorem ipsum dolor sit amet, 
                      consectetur adipiscing elit. 
                      Aliquam mattis mauris et elit luctus, 
                      at condimentum odio rhoncus.</li>
                      <li>Sub-Sub-Second</li>
                    </ol>
                </li>
                <li>Sub-Second</li>
            </ol>
        </li>
        <li>Forth</li>
        <li>Fifth</li>
    </ol>
</body>

最後補充一些花式技巧:

Examples of customizing LI counter format with CSS styles.


Comments

# by null

現在應該可以不用管 IE 了吧?都要廢棄了。

# by Jeffrey

to null, 看情況,如果你網站用戶都來自 Internet,現在已經可以放生 IE 了,但 IE 在企業內網估計還會再戰十年。https://blog.darkthread.net/blog/is-ie-dead/

Post a comment