Tạo danh sách đánh số tự động bằng CSS Counter

Nói đến danh sách đánh số, trong HTML, bạn có thể nghĩ ngay đến phần tử ol. Tuy nhiên, bài này không nói đến danh sách dạng đó, mà nói đến những danh sách không thể tạo bằng ol.

Giả sử bài viết của bạn có nhiều phần, mỗi phần là một đề mục định bằng header hx (h1h6). Trong mỗi phần có nhiều đoạn văn nội dung. Như ví dụ hình minh họa dưới đây, lấy từ một bài viết khác của mình:

css-counter-demo

Cắt, sao chép, dánChụp ảnh màn hình; Các phím tắt khởi động là một danh sách có 3 đề mục, mà trong ví dụ trên, mình không đánh số.

Điều gì xảy ra nếu muốn đánh số thứ tự chúng? Rõ ràng, đây là một danh sách không thể tạo bằng ol. Cách đơn giản nhất trường hợp này là đánh số bằng tay. Nhưng đánh số bằng tay có nhược điểm, bạn sẽ không nhớ mình đang đánh đến số mấy, và nếu thay đổi, thêm bớt mục thì sẽ phải đánh số lại, rất mất thời gian.

CSS 2.1 trở lên có cung cấp một tính năng đánh số tự động là CSS counter. Bài này giới thiệu bạn về cách sử dụng tính năng này. Lưu ý: tính năng này không hỗ trợ trên IE 7 trở xuống (nhưng bạn có thể yên tâm, rồi sẽ không ai còn dùng các bản IE cũ).

Căn bản CSS Counter

Để sử dụng CSS counter, chúng ta quan tâm đến các thành phần CSS sau:

  • counter-reset: dùng để tạo hoặc đặt lại một hoặc nhiều bộ đếm (counters), giá trị mặc định của bộ đếm sẽ là 0, trừ khi bạn định rõ. Ví dụ:
    counter-reset: de-muc-cha

    Câu mã trên có nghĩa: tạo ra hoặc đặt lại bộ đếm có tên de-muc-cha, giá trị ban đầu là 0

    counter-reset: de-muc-con 1

    Câu mã trên có nghĩa: tạo ra hoặc đặt lại bộ đến có tên de-muc-con, giá trị ban đầu là 1

  • counter-increment: tăng giá trị cho bộ đếm
  • Hàm CSS counter(): lấy giá trị hiện tại của bộ đếm

Chi tiết về cú pháp và ý nghĩa của các thành phần trên, bạn xem thêm ở đây nếu cần thiết:

Tạo CSS Counter đơn giản

Ví dụ, giả sử mình sẽ tạo 3 đề mục như trong hình minh họa:

Minh họa CSS Counter 1

Mã HTML của chúng như sau:

<h3>Cắt, sao chép, dán</h3>
<h3>Chụp ảnh màn hình</h3>
<h3>Các phím tắt khởi động</h3>

Mình mong muốn tạo ra đề mục đánh số như dưới đây:

Minh họa CSS Counter 2

Để làm được việc này, bạn hãy thêm đoạn mã CSS sau vào tài liệu HTML:

body {
   counter-reset: de-muc;
}
h3 {
   counter-increment: de-muc;
}
h3:before {
   content:counter(de-muc) '. ';
}

Trong đoạn mã trên:

  1. Tại phần định kiểu cho body, tạo ra một bộ đếm counter mới tên là de-muc. Mặc định, giá trị counter bắt đầu từ 0
  2. Kế đến, cứ mỗi phần tử h3, tăng counter de-muc lên 1. 1 là giá trị tăng mặc định, bạn không cần phải ghi rõ. Nếu bạn muốn tăng 2 chẳng hạn (số sẽ đánh là 1, 3, 5…) thì bạn sẽ ghi:
    counter-increment: de-muc 2
    
  3. Sau đó, ở mỗi phần tử h3, ngay trước nội dung đang có của chúng (bạn có thể tìm hiểu thêm về ::before và ::after trong CSS), thêm vào giá trị counter hiện hành (và dấu chấm phân cách).

Dùng CSS Counter cho mục cha, con

Giả sử ta muốn tạo một danh sách cha con như minh họa sau:

css-counter-demo-3

Trong minh họa trên, mục 1 có 3 mục con là 1.1, 1.2, 1.3, mục 2 có 2 mục con là 2.1, 2.2. Số đếm trong mục con phải được đặt lại từ đầu chứ không đánh tiếp theo mục con trước.

Mã HTML cho minh họa trên:

<h2>Mục cha</h2>
<h3>Cắt, sao chép, dán</h3>
<h3>Chụp ảnh màn hình</h3>
<h3>Các phím tắt khởi động</h3>

<h2>Mục cha</h2>
<h3>Cắt, sao chép, dán</h3>
<h3>Chụp ảnh màn hình</h3>

Mã CSS:

body {
   counter-reset: muc-cha;
}
h2 {
   counter-increment: muc-cha;
   counter-reset: muc-con;
}
h2:before {
   content: counter(muc-cha) '. ';
}
h3:before {
   content: counter(muc-cha) '.' counter(muc-con) '. ';
}
h3:before {
   counter-increment: muc-con;
}

Bộ đếm lồng nhau (nested counter)

Tình huống nếu sử dụng một danh sách ol, hầu hết, chúng ta ít khi dùng đến CSS counter. Tuy nhiên, nếu danh sách của chúng ta lồng nhau nhiều cấp, chỉ sử dụng ol có thể sẽ khiến việc đánh số không theo ý muốn. Ví dụ, nếu chúng ta có đoạn mã HTML:

<ol>
   <li>Item 1
      <ol>
         <li>Sub item 1
            <ol>
              <li>Sub-sub item 1</li>
              <li>Sub-sub item 2</li>
              <li>Sub-sub item 3</li>
           </ol>
         </li>
         <li>Sub item 2</li>
     </ol>
   </li>
   <li>Item 2</li>
</ol>

Hiển thị trong trình duyệt sẽ là:

css-counter-demo-4

Giả sử cách đánh số mặc định trên không đúng ý muốn, và mình mong muốn đánh số kiểu này:

css-counter-demo-5

Chúng ta sẽ cần sử dụng đoạn mã CSS sau:

ol {
   counter-reset: de-muc;
   list-style-type: none;
}
ol li {
   counter-increment: de-muc;
}
ol li:before {
   content: counters(de-muc, '.') '. ';
}

Để ý, ở đây, chúng ta không dùng hàm counter() mà là counters() (có thêm s) để lấy giá trị bộ đếm. counters() cho phép gọi mọi bộ đếm có cùng tên trong cùng phạm vi hiệu lực (de-muc ở 1.1 có thể truy xuất ở 1.1.1, giống ở nhiều ngôn ngữ lập trình, hàm có thể truy xuất biến của lớp chứa chúng)

Định kiểu cho bộ đếm

Để ý phần mã:

ol li:before {
   content: counters(de-muc, '.') '. ';
}

Bạn hãy thử sử dụng một số đoạn mã sau thay thế và xem thử kết quả:

ol li:before {
   content: counter(de-muc, decimal-leading-zero) ') ';
}

Kết quả:

css-counter-demo-6

ol li:before {
   content: counter(de-muc, upper-roman) " - ";
}

Kết quả:

css-counter-demo-7

Hầu hết các giá trị cho thuộc tính CSS list-style-type đều có thể sử dụng cho counter().

Nguồn tham khảo:

One Comment

Bình luận

Bình luận Facebook

lời bình luận