Phần tử <progress> là cách ngữ nghĩa để thể hiện tiến trình hoàn thành của một tác vụ, chẳng hạn như tải thông tin xuống hoặc tải thông tin lên hoặc hoàn thành một phần của quy trình gồm nhiều bước. Việc sử dụng phần tử gốc giúp hỗ trợ tiếp cận, vì trình đọc màn hình có role="progressbar" ngầm ẩn và có thể thông báo các giá trị.
Hướng dẫn này triển khai một thanh tiến trình ngang được tạo kiểu đầy đủ với các tuỳ chỉnh kiểu.
Thanh tiến trình hay vòng tròn tiến trình?
- Nếu không gian bị hạn chế hoặc bạn muốn dùng tỷ lệ khung hình vuông, hãy cân nhắc sử dụng thanh tiến trình hình tròn (vòng tròn tiến trình): Vòng tròn tiến trình
- Ưu tiên vòng quay cho hầu hết các trường hợp tiến trình không xác định (Vòng quay đang tải). Sử dụng thanh tiến trình không xác định khi trạng thái không xác định chỉ là tạm thời và sẽ sớm được thay thế bằng thanh tiến trình xác định (ví dụ: chờ siêu dữ liệu về một tệp tải lên trước khi có thể hiển thị % tiến trình)
Markup (note: đây là tên ứng dụng)
- Sử dụng phần tử
<progress>gốc: Phần tử này cung cấp khả năng hỗ trợ tiếp cận tích hợp sẵn và hành vi nhất quán trên nền tảng. - Sử dụng
maxnếu cần thang điểm khác với thang điểm mặc định từ 0 đến 1. - Đối với một giá trị tiến trình cụ thể, hãy đặt thuộc tính
value. Bỏ quavaluecho trạng thái không xác định (ví dụ: trước khi bắt đầu phản hồi cụ thể hơn). - Sử dụng
<label for="...">,aria-labelledbyhoặcaria-labelđể liên kết phần tử tiến trình với một nhãn.
Bạn cần tuỳ chỉnh loại nào?
Để tạo kiểu cơ bản, bạn chỉ cần các thuộc tính sau:
accent-colorđể thay đổi màu của thanh tiến trìnhwidth/inline-sizeđể thay đổi chiều rộng của thanh tiến trìnhheight/block-sizeáp dụng không nhất quán — hãy thử nghiệm trướcwriting-mode: vertical-lrcho thanh dọc.- Hiệu ứng áp dụng sau khi vẽ:
opacity,filter,clip-path, mặt nạ, phép biến đổi,box-shadow, v.v.
Nếu bạn chỉ cần tạo kiểu ở mức hạn chế, hãy bỏ qua phần tiếp theo.
CẢNH BÁO: Một số thuộc tính nhất định (ví dụ: border-radius, background, border) sẽ tự động tắt kiểu thanh tiến trình mặc định. Nếu cần tạo kiểu ngoài các thuộc tính ở trên, bạn phải triển khai kiểu tuỳ chỉnh hoàn toàn như mô tả trong phần tiếp theo. KHÔNG áp dụng kiểu mở rộng hơn "chỉ trong trường hợp kiểu đó hoạt động".
Kiểu tuỳ chỉnh hoàn toàn
1. Quy trình thiết lập cơ bản
- BẮT BUỘC: Sử dụng
appearance: noneđể bật kiểu tuỳ chỉnh. - Đặt lại đường viền UA bằng
border: 0 solid - Để cắt thanh đang hoạt động theo bán kính đường viền của phần tử, hãy sử dụng
overflow: clipHOẶC áp dụng cùng mộtborder-radiuscho thanh. KHÔNG sử dụngborder-radius: inherittrên thanh, vì điều này phụ thuộc vào cấu trúc cụ thể của các phần tử trong DOM tối.
progress {
/* Reset default browser styles */
appearance: none;
border: 0 solid;
/* Clip bar to element’s border-radius */
overflow: clip;
}
2. Định kiểu
- Tạo kiểu cho dải trên chính phần tử
progress. - Sử dụng phần tử giả nhắm đến trình duyệt thích hợp để nhắm đến chính thanh tiến trình:
::-webkit-progress-valuecho WebKit/Blink và::-moz-progress-barcho Firefox. - BẮT BUỘC: KHÔNG nhóm các phần tử giả
-webkit-và-moz-trong cùng một quy tắc. Quy tắc này sẽ được coi là không hợp lệ và sẽ bị bỏ qua.:is()và:where()không giúp ích gì trong trường hợp này vì chúng không hỗ trợ phần tử giả. - Mỗi phần tử giả nhắm đến trình duyệt chỉ được xuất hiện một lần. Bạn nên định tuyến các tuỳ chỉnh theo trạng thái cụ thể (chẳng hạn như kích thước và ảnh động của phân đoạn không xác định) thông qua các thuộc tính tuỳ chỉnh được đặt trên chính phần tử
progress. - Không bắt buộc: Chuyển đổi
inline-sizetrên phần lấp đầy để các thay đổi về giá trị xác định sẽ tạo ảnh động thay vì nhảy. Firefox định kích thước cho phần lấp đầy trong bố cục và bỏ qua phần này, điều này không gây hại.
progress {
--progress-bar-radius: 1e5px;
border-radius: var(--progress-bar-radius);
/* Apply color for custom progress track (background) */
background: var(--progress-bar-track, var(--color-neutral-90));
/* Subtle depth on the empty part of the track */
box-shadow: inset 0 1px 2px rgb(0 0 0 / 0.1);
}
/* Let <progress> styling show through */
progress::-webkit-progress-bar {
background: transparent;
}
/* Webkit, Chrome */
progress::-webkit-progress-value {
background: var(--progress-bar-fill, var(--accent-color));
border-radius: var(--progress-bar-radius);
transition: inline-size 0.3s;
}
/* Firefox */
progress::-moz-progress-bar {
background: var(--progress-bar-fill, var(--accent-color));
border-radius: var(--progress-bar-radius);
transition: inline-size 0.3s;
}
3. Tạo kiểu cho trạng thái không xác định
Thêm ảnh động tuỳ chỉnh cho trạng thái không xác định: Biến phần tử giả lấp đầy thành một đoạn ngắn và trượt dọc theo dải.
- Tạo kiểu cho chính phần lấp đầy; KHÔNG tạo lại phần lấp đầy dưới dạng nền trên
progress. - Màu nền không xác định chỉ tồn tại thông qua ảnh động: khung hình chính đặt độ dài bằng
inline-sizethực (giá trị này vượt trội hơninline-sizecùng dòng của UA Chromium) và di chuyển màu nền bằngtranslate. KHÔNG sử dụngscalecho chiều dài; nó làm biến dạng bất kỳ mẫu nào được vẽ trên phần tô. - Tỷ lệ phần trăm
translatephân giải theo chiều rộng của chính phần lấp đầy, vì vậy, hãy biểu thị vị trí theo đơn vị theo dõi: đặtprogresslàm vùng chứa kích thước cùng dòng và sử dụngcqitrong khung hình chính. Thêmmargin-right: autovàofrom, tođể Chromium cũng bố trí phần lấp đầy ở bên trái thực tế trong RTL. - Sử dụng phép biến đổi, không phải lề, để di chuyển phần lấp đầy.
- Phép biến đổi giữ ảnh động trong trình kết hợp (trừ phi
inline-sizecũng đang được tạo ảnh động) - Lề bị hỏng trong RTL vì hai lý do riêng biệt:
- Firefox định vị phần lấp đầy không xác định chỉ bằng lề trái thực tế, vì vậy,
margin-inline-startkhông có hiệu lực trong RTL và phần lấp đầy không bao giờ di chuyển. - Trong Chromium và WebKit, vốn bố trí phần lấp đầy dưới dạng một khối thông thường, khi lề đẩy phần lấp đầy vượt quá điểm cuối của dải, lề sẽ cộng dồn nhiều hơn dải. CSS chuẩn giải quyết vấn đề đó bằng cách bỏ qua
margin-lefttrong RTL, vì vậy, phân đoạn sẽ nhảy đến cạnh thay vì trượt ra khỏi cạnh. translateđược áp dụng sau bố cục, nên cả hai vấn đề đều không xảy ra.
- Phép biến đổi giữ ảnh động trong trình kết hợp (trừ phi
- Để phản chiếu chuyển động trong RTL (như thanh gốc của Chrome), hãy đảo ngược ảnh động trong
:dir(rtl):
progress:dir(rtl) {
--progress-bar-indeterminate-animation: progress-bar-indeterminate var(--progress-bar-indeterminate-animation-duration) infinite linear reverse;
}
- Xác định các thuộc tính
--progress-bar-indeterminate-*công khai trênprogress(tên của các thuộc tính này đã xác định phạm vi của chúng cho trạng thái) để người dùng có thể ghi đè các thuộc tính đó mà không cần biết về:indeterminate. - Để thay đổi độ dài đoạn (ví dụ: cạnh trước chạy trước và cạnh sau bắt kịp), hãy đặt
--progress-bar-indeterminate-animationthành hai ảnh động đồng thời: một ảnh động có khung hình chính tạo ảnh độngtranslatetrongcqi(vị trí) và một ảnh động có khung hình chính tạo ảnh độnginline-size(độ dài), nhờ đó mỗi ảnh động có khung hình chính và hiệu ứng chuyển đổi riêng. ĐỪNG cố gắng định hình cả hai cạnh trong một danh sách khung hình chính;animation-timing-functioncho mỗi khung hình chính áp dụng cho mọi thuộc tính trong khung hình chính đó. --progress-bar-animationáp dụng cho cả hai trạng thái và có thể dùng cho các hiệu ứng như hiệu ứng lấp lánh xác định.revert-rulechỉ được dùng để ghi đè khi được đặt, nhằm tối đa hoá khả năng kết hợp.- Không bao giờ tắt ảnh động không xác định (
animation: noneđể lại một khoảng trống có chiều rộng bằng 0 trong Chromium). Để giảm chuyển động, hãy làm chậm chuyển động.
progress {
/* Lets the fill position itself in track units (cqi) */
container-type: inline-size;
/* Segment length relative to the track */
--progress-bar-indeterminate-size: 30%;
--progress-bar-indeterminate-animation-duration: 1.5s;
/* Respect prefers-reduced-motion */
@media (prefers-reduced-motion: reduce) {
--progress-bar-indeterminate-animation-duration: 10s;
}
}
progress:indeterminate {
--progress-bar-animation: var(
--progress-bar-indeterminate-animation,
progress-bar-indeterminate var(--progress-bar-indeterminate-animation-duration) infinite linear
);
}
/* Add to the existing pseudo-element rules */
progress::-webkit-progress-value {
animation: var(--progress-bar-animation, revert-rule);
}
progress::-moz-progress-bar {
animation: var(--progress-bar-animation, revert-rule);
}
/* Physical: left to right regardless of direction (reverse under :dir(rtl) to mirror). */
@keyframes progress-bar-indeterminate {
from, to {
inline-size: var(--progress-bar-indeterminate-size);
/* Pin to the physical left; Chromium would otherwise lay the fill out at the inline start */
margin-right: auto;
}
from { translate: -100%; } /* Own width: fully outside the left edge */
to { translate: 100cqi; } /* Track width: fully outside the right edge */
}
Các yếu tố khác cần cân nhắc về khả năng hỗ trợ tiếp cận
Ngoài các nguyên tắc nêu trên:
- Thông báo hoàn tất mà không làm mất tiêu điểm: Đừng đặt
tabindexhoặc gọi.focus()trên<progress>, vì đây là thành phần không tương tác và việc di chuyển tiêu điểm đến thành phần này sẽ làm gián đoạn người dùng bàn phím. Để thông báo khi một tác vụ trong nền hoàn tất, hãy cập nhật một phần tử trạng thái lịch sự (role="status"hoặcaria-live="polite"). - Không thêm văn bản dự phòng vào bên trong
<progress>: Văn bản bên trong<progress>bị các trình duyệt hiện đại bỏ qua và không được các công nghệ hỗ trợ sử dụng. - Tránh
aria-busy+aria-describedbytrên<div>chung chung không được gắn nhãn.aria-busycó khả năng hỗ trợ trình đọc màn hình không nhất quán vàaria-describedbytrên<div>không có tên và không có vai trò sẽ bị các công nghệ hỗ trợ bỏ qua. Nếu nội dung của một khu vực chưa sẵn sàng trong khi tải, hãy ẩn nội dung đó bằnghiddenhoặcaria-hidden="true". - NÊN đảm bảo độ tương phản phù hợp giữa thanh tiến trình và dải tiến trình khi thêm kiểu tuỳ chỉnh.
- Cân nhắc các phương án thay thế để thể hiện trạng thái không xác định: Ảnh động thanh tiến trình không xác định hiển thị song song với nội dung khác có thể khiến một số người dùng bị phân tâm.
Chiến lược dự phòng
Dự phòng và hỗ trợ trình duyệt cho màu nhấn
Thuộc tính accent-color là cải tiến tăng dần.
Những trình duyệt không hỗ trợ thuộc tính này sẽ bỏ qua thuộc tính này và sử dụng màu giao diện người dùng mặc định.
Nếu accent-color không được hỗ trợ và bạn cần tạo kiểu cho thanh tiến trình, hãy sử dụng phương thức tạo kiểu tuỳ chỉnh để áp dụng kiểu ưu tiên cho thanh tiến trình.
Phương án dự phòng và khả năng hỗ trợ của trình duyệt cho revert-rule
Nếu revert-rule không được hỗ trợ, animation: var(--progress-bar-animation, revert-rule) sẽ quay lại animation-name: revert-rule với thời lượng 0s khi --progress-bar-animation không được đặt, đây là một thao tác không gây hại khi không có @keyframes revert-rule.