/ TOC

[CSS 年終特賣] 讓 CSS 自動幫你數數

先來一下國語正音班。

數數,第一個字唸數,三聲數,第二個字唸數,四聲數。

最近因為在做 TOC 所以就把這個陳年的東西拿出來講一下,順便趁著是芥末日之前把一些筆記寫一寫,不然現在不寫,就只能明年才寫得完了(這個哏你要用幾次)。

我們在撰寫很長篇的文章的時候,常常需要主標題,副標題這一類的東西。但是最麻煩的地方在於,我如果中途一時興起多開了一個標題,那麼接下來的標題順序就悲劇了。

1. 我是第一章
  a. 我是第 1.1 章
2. 我是第二章
  a. 我是第 2.1 章
  b. 我是第 2.2 章
3. 我是第三章
  a. 我是第 3.1 章
  b. 我是第 3.2 章
  c. 我是第 3.3 章
  d. 我是第 3.4 章

如果我在 2, 3 章之中多開了一個章節,那麼,第三章勢必要跟著修改,這麼做的話不僅僅費時耗工,而且也很容易打錯(你累了嗎~)。

沒關係,CSS 已經為你想好了!

12 Generated content, automatic numbering, and lists

CSS 2.1 版本中,提供了 Generated content, automatic numbering, and lists 功能,而制定這些東西的年份冗長,最後一次修訂是在 2008 年 4 月。換句話說,這個東西已經存在超過 10 年之久。話雖如此,我們強大的IE6/7/8 全部不支援喔,啾咪

在 w3c 官方說明的 12.4 Automatic counters and numbering 提到,有兩種數數的設定方式。

  • counter-reset 顧名思義,把計數器歸零(回到初始值,未必是零)
  • counter-increment 顧名思義 part 2,把計數器數數

以上這兩種屬性只能用在元件與擬似元件(pseudo-element)上面,其他的地方用了是沒有反應的。另外,如果你的元件或是擬似元件沒有被產生或是被隱藏(display: none),那麼上面兩個屬性也是無效的。不過,倘若是看不見(visibility: hidden),這倒是會生效喔。

而且,有關於 counter-reset 在官方也有特別說明,在同一個元件上,如果要重設多個計數器,撰寫的方式是這樣的:

h1 {
    counter-reset: chapter section money nobody
}

重新設定計數器的寫法,可以組合 計數器名稱計數器初始值 這兩種設定,也就是說,上述的重設範例,我還可以寫成這樣:

h1 {
    counter-reset: chapter 99 section -1 money 200000000 nobody
}

這樣的意思就是:

  • chapter 這個計數器重設,初始值是 99
  • section 這個計數器重設,初始值是 -1
  • money 這個計數器重設,初始值是 2 萬郝,1 夢想家 200000000
  • nobody 這個計數器重設,不給初始值所以固定是 0

這樣應該看得出重設屬性的精髓了吧,計數器可以隨時被重設,只要你高興的話要多少有多少。然而,我們有了初始值,就要開始累加(或是遞減)這個數字,這個時候就會用上數數器的屬性了。

h2 {
    counter-increment: chapter -2
    counter-increment: money 100
    counter-increment: nobody
}

這裡的 counter-increment 是依照你給的 計數器增量 來計算這個數字是多少,以上面的例子,搭配我們當初所設定好的計數器,我們如果跑一次 h2 會得到下列的數值:

  • chapter = 97
  • money = 200000100
  • nobody = 1

這樣對於數數器應該就了解了吧。那,我們要怎麼把這些產生的數值,自動的幫我們放在標題的前面呢?這個時候就需要用到擬似元件(pseudo-element)這個東西了。什麼叫做擬似元件?

  • ::before
  • ::after

疑?不用懷疑,你可能很常看到這兩種 CSS 的選擇器。是的,他就是擬似元件。擬似元件中有一個屬性叫做 content,是專門用於產生擬似元件中的元素,但是,他只能是普通的字串。所以,我們就可以利用 ::before 來產生我們所需要的東西。

不要問我為什麼不用 ::after,如果你想把章節號放在章節名稱後面的話,你就用吧。

所以我們可以來看一個簡單的 TOC:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>CSS Counter</title>
        <style>
            body {
                font: 16px/1.55 serif;
            }
            .toc {
                counter-reset: chapter;
            }
            .toc > ul > li {
                counter-increment: chapter;
                counter-reset: section;
                margin-left: 1em;
            }
            .toc > ul > li::before {
                content: counter(chapter);
                margin-right: 0.5em;
            }
            .toc > ul > li > ul > li {
                counter-increment: section;
                margin-left: 1em;
            }
            .toc > ul > li > ul > li::before {
                content: counter(chapter) "." counter(section);
                margin-right: 0.5em;
            }
        </style>
    </head>
    <body>

        <div class="toc">
            <ul>
                <li>這是第x章,啦啦啦啦
                    <ul>
                        <li>這是第x節,啦啦啦啦啦啦</li>
                        <li>這是第x節,啦啦啦啦啦啦</li>
                        <li>這是第x節,啦啦啦啦啦啦</li>
                        <li>這是第x節,啦啦啦啦啦啦</li>
                        <li>這是第x節,啦啦啦啦啦啦</li>
                        <li>這是第x節,啦啦啦啦啦啦</li>
                        <li>這是第x節,啦啦啦啦啦啦</li>
                        <li>這是第x節,啦啦啦啦啦啦</li>
                    </ul>
                </li>
                <li>這是第x章,啦啦啦啦
                    <ul>
                        <li>這是第x節,啦啦啦啦啦啦</li>
                    </ul>
                </li>
                <li>這是第x章,啦啦啦啦
                    <ul>
                        <li>這是第x節,啦啦啦啦啦啦</li>
                    </ul>
                </li>
                <li>這是第x章,啦啦啦啦
                    <ul>
                        <li>這是第x節,啦啦啦啦啦啦</li>
                    </ul>
                </li>
                <li>這是第x章,啦啦啦啦
                    <ul>
                        <li>這是第x節,啦啦啦啦啦啦</li>
                    </ul>
                </li>
            </ul>
        </div>
    </body>
</html>

如果想看範例結果,可以連去這裡看看,記得 IE6/7/8 全部都不支援喔,啾咪

TOC 還有一個隱憂,就是頁碼計算。不過,由於我沒說 CSS 可以拿來寫書,所以頁碼還是交給專門的文件產出軟體吧。這個計數器功能,讓你在冗長文件目錄下,製作錨點時特別有幫助。畢竟,記得閱讀到什麼章節,數字或是代碼永遠比章節名稱要好記得多啊。