Podstawowy przegląd tworzenia paska ładowania z dostępną kolorystyką za pomocą elementu <progress>
.
W tym poście chcę podzielić się z Wami sposobem na stworzenie paska wczytywania, który dostosowuje się do kolorów i jest dostępny dla osób z ograniczonymi możliwościami.<progress>
Wypróbuj wersję demonstracyjną i wyświetl kod źródłowy.
Jeśli wolisz film, oto wersja tego posta w YouTube:
Omówienie
Element <progress>
zapewnia użytkownikom wizualne i dźwiękowe informacje o ukończeniu. Takie wizualne informacje zwrotne są przydatne w różnych sytuacjach, np. podczas wypełniania formularza, wyświetlania informacji o pobieraniu lub przesyłaniu albo nawet informowania o tym, że postęp jest nieznany, ale praca nadal trwa.
W tym wyzwaniu dotyczącym interfejsu użytkownika wykorzystano istniejący element HTML <progress>
, aby zaoszczędzić czas na ułatwieniach dostępu. Kolory i układy przesuwają granice możliwości dostosowywania wbudowanego elementu, aby unowocześnić komponent i ułatwić jego dopasowanie do systemów projektowania.

Znacznik
Element <progress>
został zawinięty w element <label>
, aby można było pominąć jawne atrybuty relacji na rzecz niejawnej relacji.
Oznaczyłem też element nadrzędny, na który wpływa stan wczytywania, aby czytniki ekranu mogły przekazać te informacje użytkownikowi.
<progress></progress>
Jeśli nie ma elementu value
, postęp elementu jest nieokreślony.
Atrybut max
ma domyślną wartość 1, więc postęp mieści się w zakresie od 0 do 1. Ustawienie wartości max
na 100 ustawi zakres na 0–100. Zdecydowaliśmy się pozostać w zakresie 0–1, tłumacząc wartości postępu na 0,5 lub 50%.
Postęp w ramach etykiet
W przypadku relacji domyślnej element postępu jest otoczony etykietą w taki sposób:
<label>Loading progress<progress></progress></label>
W mojej wersji demonstracyjnej uwzględniono etykietę tylko dla czytników ekranu.
Aby to zrobić, użyj elementu <span>
i zastosuj do niego odpowiednie style, aby był niewidoczny na ekranie:
<label>
<span class="sr-only">Loading progress</span>
<progress></progress>
</label>
z usługą porównywania cen, która zawiera następujący kod CSS z WebAIM:
.sr-only {
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(50%);
height: 1px;
width: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
}
Obszar dotknięty przez postęp wczytywania
Jeśli masz dobry wzrok, możesz łatwo powiązać wskaźnik postępu z powiązanymi elementami i obszarami strony, ale użytkownicy niedowidzący nie mają tego komfortu. Aby to poprawić, przypisz atrybut aria-busy
do najwyższego elementu, który zmieni się po zakończeniu wczytywania.
Ponadto należy wskazać związek między postępem a strefą wczytywania za pomocą aria-describedby
.
<main id="loading-zone" aria-busy="true">
…
<progress aria-describedby="loading-zone"></progress>
</main>
W JavaScriptu przełącz opcję aria-busy
na true
na początku zadania, a na false
– po jego zakończeniu.
Dodawanie atrybutów ARIA
Chociaż domyślna rola elementu <progress>
to progressbar
, w przypadku przeglądarek, które nie mają tej domyślnej roli, dodałem ją wprost. Dodaliśmy też atrybut indeterminate
, aby wyraźnie ustawić stan elementu jako nieznany. Jest to wyraźniejsze niż obserwowanie, że element nie ma ustawionego atrybutu value
.
<label>
Loading
<progress
indeterminate
role="progressbar"
aria-describedby="loading-zone"
tabindex="-1"
>unknown</progress>
</label>
Użyj tabindex="-1"
, aby element postępu był możliwy do wybrania w JavaScript. Jest to ważne dla technologii czytników ekranu, ponieważ powiadomienie użytkownika o aktualnym postępie w wykonywaniu czynności pozwoli mu dowiedzieć się, jak daleko zaawansował.
Style
Element postępu jest nieco trudny do skonfigurowania pod względem stylizacji. Wbudowane elementy HTML mają specjalne ukryte części, które mogą być trudne do wybrania, i często oferują tylko ograniczony zestaw właściwości do ustawienia.
Układ
Style układu mają zapewnić pewną elastyczność w zakresie rozmiaru elementu postępu i pozycji etykiety. Dodano specjalny stan zakończenia, który może być przydatnym, ale nieobowiązkowym dodatkowym sygnałem wizualnym.
<progress>
Układ
Szerokość elementu postępu pozostaje niezmieniona, aby mogła się ona zmniejszać i zwiększać wraz z przestrzenią potrzebną w projektie. Wbudowane style są usuwane przez ustawienie appearance
i border
na none
. Dzięki temu element może być znormalizowany w różnych przeglądarkach, ponieważ każda przeglądarka ma własne style dla tego elementu.
progress {
--_track-size: min(10px, 1ex);
--_radius: 1e3px;
/* reset */
appearance: none;
border: none;
position: relative;
height: var(--_track-size);
border-radius: var(--_radius);
overflow: hidden;
}
Wartość 1e3px
dla _radius
jest wyrażona za pomocą notacji wykładniczej, aby przedstawić dużą liczbę, więc border-radius
jest zawsze zaokrąglana. To 1000px
. Lubię używać tej metody, ponieważ moim celem jest użycie wartości wystarczająco dużej, aby można ją było ustawić i zapomnieć (a dodatkowo jest ona krótsza do zapisania niż 1000px
). W razie potrzeby można ją też łatwo zwiększyć: wystarczy zmienić 3 na 4, a 1e4px
będzie się równać 10000px
.
overflow: hidden
jest używany i jest kontrowersyjnym stylem. Ułatwiło to kilka rzeczy, np. nie trzeba było przekazywać wartości border-radius
do ścieżki ani elementów wypełniania ścieżki. Oznaczało to jednak też, że żadne elementy potomne postępu nie mogły znajdować się poza elementem. Kolejną wersję tego elementu postępu niestandardowego można utworzyć bez overflow: hidden
. Może to stworzyć możliwości tworzenia animacji lub lepsze stany ukończenia.
Gotowe
Selektory CSS wykonują tu trudną pracę, porównując wartość maksymalną z wartością. Jeśli się zgadzają, proces jest zakończony. Po zakończeniu generowany jest pseudoelement, który jest dołączany na końcu elementu postępu, co stanowi dodatkową wizualną wskazówkę dla użytkownika.
progress:not([max])[value="1"]::before,
progress[max="100"][value="100"]::before {
content: "✓";
position: absolute;
inset-block: 0;
inset-inline: auto 0;
display: flex;
align-items: center;
padding-inline-end: max(calc(var(--_track-size) / 4), 3px);
color: white;
font-size: calc(var(--_track-size) / 1.25);
}
Kolor
Przeglądarka używa własnych kolorów dla elementu postępu i dostosowuje się do jasnych i ciemnych kolorów za pomocą tylko jednej właściwości CSS. Można to rozszerzyć o specjalne selektory dla poszczególnych przeglądarek.
Jasne i ciemne style przeglądarki
Aby włączyć w witrynie ciemny i jasny element <progress>
, wystarczy użyć tagu color-scheme
.
progress {
color-scheme: light dark;
}
Kolor wypełnienia paska postępu pojedynczej właściwości
Aby zastosować zabarwienie do elementu <progress>
, użyj accent-color
.
progress {
accent-color: rebeccapurple;
}
Zwróć uwagę, że kolor tła ścieżki zmienia się z jasnego na ciemny w zależności od accent-color
. Przeglądarka zapewnia odpowiedni kontrast: bardzo fajne.
Całkowicie niestandardowe kolory jasne i ciemne
Ustaw 2 właściwości niestandardowe w elemencie <progress>
: jedną dla koloru ścieżki, a drugą dla koloru postępu ścieżki. W zapytaniu o media prefers-color-scheme
podaj nowe wartości kolorów ścieżki i postępu ścieżki.
progress {
--_track: hsl(228 100% 90%);
--_progress: hsl(228 100% 50%);
}
@media (prefers-color-scheme: dark) {
progress {
--_track: hsl(228 20% 30%);
--_progress: hsl(228 100% 75%);
}
}
Style fokusu
Wcześniej nadaliśmy elementowi ujemny indeks tabulacji, aby można było go skupić programowo. Użyj opcji :focus-visible
, aby dostosować tryb pełnej koncentracji i wybrać inteligentniejszy styl pierścienia podświetlenia. W tym przypadku kliknięcie myszką i ustawienie punktu skupienia nie spowoduje wyświetlenia pierścienia, ale kliknięcia klawiaturą już tak. Film w YouTube zawiera więcej informacji na ten temat i warto go obejrzeć.
progress:focus-visible {
outline-color: var(--_progress);
outline-offset: 5px;
}
Style niestandardowe w różnych przeglądarkach
Dostosuj style, wybierając części elementu <progress>
, które są dostępne w danym przeglądarce. Użycie elementu postępu to pojedynczy tag, ale składa się on z kilku elementów podrzędnych, które są wyświetlane za pomocą pseudoselektorów CSS. Jeśli włączysz to ustawienie, Narzędzia programistyczne Chrome wyświetlą te elementy:
- Kliknij prawym przyciskiem myszy stronę i wybierz Zbadaj element, aby otworzyć Narzędzia deweloperskie.
- W prawym górnym rogu okna Narzędzia programistyczne kliknij ikonę koła zębatego Ustawienia.
- W sekcji Elementy znajdź i zaznacz pole wyboru Pokaż DOM w cieni klienta użytkownika.
stylów Safari i Chromium.
Przeglądarki oparte na WebKit, takie jak Safari i Chromium, udostępniają funkcje ::-webkit-progress-bar
i ::-webkit-progress-value
, które umożliwiają używanie podzbioru CSS. Na razie ustaw background-color
za pomocą właściwości niestandardowych utworzonych wcześniej, które dostosowują się do ciemnych i jasnych kolorów.
/* Safari/Chromium */
progress[value]::-webkit-progress-bar {
background-color: var(--_track);
}
progress[value]::-webkit-progress-value {
background-color: var(--_progress);
}
Style w Firefoksie
Firefox udostępnia tylko pseudoselektor ::-moz-progress-bar
dla elementu <progress>
. Oznacza to też, że nie możemy bezpośrednio przyciemnić ścieżki.
/* Firefox */
progress[value]::-moz-progress-bar {
background-color: var(--_progress);
}
Zwróć uwagę, że w Firefox kolor ścieżki jest ustawiony na accent-color
, a w Safari na iOS na jasnoniebieski. To samo w trybie ciemnym: Firefox ma ciemny ślad, ale nie ma niestandardowego koloru, który ustawiliśmy. Działa to w przeglądarkach opartych na Webkit.
Animacja
Podczas korzystania z wbudowanych w przeglądarkę pseudoselektorów często mamy do czynienia z ograniczonym zestawem dozwolonych właściwości CSS.
Animowanie wypełniania ścieżki
Dodanie przejścia doinline-size
elementu postępu działa w przypadku Chromium, ale nie Safari. Firefox nie używa też właściwości przejściowej w swoim ::-moz-progress-bar
.
/* Chromium Only 😢 */
progress[value]::-webkit-progress-value {
background-color: var(--_progress);
transition: inline-size .25s ease-out;
}
Animowanie stanu :indeterminate
Tutaj mogę trochę bardziej poszaleć, więc pokażę animację. Tworzony jest pseudoelement dla Chromium, a w przypadku wszystkich 3 przeglądarek stosowany jest gradient, który jest animowany w obrębie wszystkich 3 przeglądarek.
Właściwości niestandardowe
Właściwości niestandardowe są przydatne w wielu sytuacjach, ale jedną z moich ulubionych funkcji jest po prostu nadawanie nazw magicznie wyglądającym wartościom w CSS. Poniżej znajduje się dość skomplikowany linear-gradient
, ale ma ładną nazwę. jego cel i przypadki użycia są jasne;
progress {
--_indeterminate-track: linear-gradient(to right,
var(--_track) 45%,
var(--_progress) 0%,
var(--_progress) 55%,
var(--_track) 0%
);
--_indeterminate-track-size: 225% 100%;
--_indeterminate-track-animation: progress-loading 2s infinite ease;
}
Właściwości niestandardowe pomogą też zachować kod w czystej postaci, ponieważ nie możemy łączyć tych selektorów w grupy ze względu na przeglądarkę.
klatki kluczowe,
Celem jest nieskończona animacja, która odtwarza się w obie strony. Kluczowe klatki początkowe i końcowe zostaną ustawione w CSS. Aby utworzyć animację, która wraca do punktu początkowego, wystarczy użyć jednej klatki kluczowej, tej środkowej na poziomie 50%
.
@keyframes progress-loading {
50% {
background-position: left;
}
}
Kierowanie na poszczególne przeglądarki
Nie każda przeglądarka umożliwia tworzenie pseudoelementów w samym elemencie <progress>
lub animowanie paska postępu. Więcej przeglądarek obsługuje animację ścieżki niż pseudoelement, więc przekształcam pseudoelementy w animowane paski.
Pseudoelement Chromium
Chromium zezwala na użycie pseudoelementu ::after
z pozycją, aby objąć element. Używane są nieokreślone właściwości niestandardowe, a animacja w przód i w tył działa bardzo dobrze.
progress:indeterminate::after {
content: "";
inset: 0;
position: absolute;
background: var(--_indeterminate-track);
background-size: var(--_indeterminate-track-size);
background-position: right;
animation: var(--_indeterminate-track-animation);
}
Pasek postępu Safari
W przypadku Safari właściwości niestandardowe i animacja są stosowane do paska postępu pseudoelementu:
progress:indeterminate::-webkit-progress-bar {
background: var(--_indeterminate-track);
background-size: var(--_indeterminate-track-size);
background-position: right;
animation: var(--_indeterminate-track-animation);
}
Pasek postępu w Firefox
W przypadku Firefoksa właściwości niestandardowe i animacja są też stosowane do paska postępu pseudoelementu:
progress:indeterminate::-moz-progress-bar {
background: var(--_indeterminate-track);
background-size: var(--_indeterminate-track-size);
background-position: right;
animation: var(--_indeterminate-track-animation);
}
JavaScript
Kod JavaScript odgrywa ważną rolę w przypadku elementu <progress>
. Określa ona wartość wysyłaną do elementu i zapewnia, że w dokumencie jest wystarczająco dużo informacji dla czytników ekranu.
const state = {
val: null
}
Demonstracja zawiera przyciski do sterowania postępem. Aktualizują one state.val
, a potem wywołują funkcję aktualizującą DOM.
document.querySelector('#complete').addEventListener('click', e => {
state.val = 1
setProgress()
})
setProgress()
W tej funkcji odbywa się aranżowanie interfejsu użytkownika. Zacznij od utworzenia funkcji setProgress()
. Nie są wymagane żadne parametry, ponieważ ma on dostęp do obiektu state
, elementu postępu i strefy <main>
.
const setProgress = () => {
}
Ustawianie stanu wczytywania w strefie <main>
W zależności od tego, czy postępy są zakończone, powiązany element <main>
wymaga zaktualizowania atrybutu aria-busy
:
const setProgress = () => {
zone.setAttribute('aria-busy', state.val < 1)
}
Wyczyść atrybuty, jeśli ilość ładowania jest nieznana
Jeśli wartość jest nieznana lub nieskonfigurowana, null
w tym przypadku usuń atrybuty value
i aria-valuenow
. Spowoduje to, że wartość <progress>
stanie się nieokreślona.
const setProgress = () => {
zone.setAttribute('aria-busy', state.val < 1)
if (state.val === null) {
progress.removeAttribute('aria-valuenow')
progress.removeAttribute('value')
progress.focus()
return
}
}
Rozwiązywanie problemów z matematyką dziesiętną w JavaScriptzie
Ponieważ zdecydowałem się na domyślną maksymalną wartość postępu równą 1, w demo funkcje zwiększania i zmniejszania używają obliczeń dziesiętnych. Język JavaScript i inne języki nie zawsze się do tego nadają.
Oto funkcja roundDecimals()
, która przycina nadmiar wyników obliczeń:
const roundDecimals = (val, places) =>
+(Math.round(val + "e+" + places) + "e-" + places)
Zaokrąglaj wartość, aby była czytelna:
const setProgress = () => {
zone.setAttribute('aria-busy', state.val < 1)
if (state.val === null) {
progress.removeAttribute('aria-valuenow')
progress.removeAttribute('value')
progress.focus()
return
}
const val = roundDecimals(state.val, 2)
const valPercent = val * 100 + "%"
}
Ustawianie wartości dla czytników ekranu i stanu przeglądarki
Wartość jest używana w 3 miejscach w DOM:
- Atrybut
value
elementu<progress>
. - Atrybut
aria-valuenow
. - Treść wewnętrzna tagu
<progress>
.
const setProgress = () => {
zone.setAttribute('aria-busy', state.val < 1)
if (state.val === null) {
progress.removeAttribute('aria-valuenow')
progress.removeAttribute('value')
progress.focus()
return
}
const val = roundDecimals(state.val, 2)
const valPercent = val * 100 + "%"
progress.value = val
progress.setAttribute('aria-valuenow', valPercent)
progress.innerText = valPercent
}
Ustawienie fokusa na postępach
Po zaktualizowaniu wartości użytkownicy widzący zobaczą zmianę postępu, ale użytkownicy czytników nie otrzymają jeszcze powiadomienia o zmianie. Skoncentruj się na elemencie <progress>
, a przeglądarka poinformuje Cię o aktualizacji.
const setProgress = () => {
zone.setAttribute('aria-busy', state.val < 1)
if (state.val === null) {
progress.removeAttribute('aria-valuenow')
progress.removeAttribute('value')
progress.focus()
return
}
const val = roundDecimals(state.val, 2)
const valPercent = val * 100 + "%"
progress.value = val
progress.setAttribute('aria-valuenow', valPercent)
progress.innerText = valPercent
progress.focus()
}
Podsumowanie
Teraz, gdy już wiesz, jak to zrobić, jak Ty to zrobisz? 🙂
Z pewnością wprowadzę kilka zmian, jeśli tylko będę mieć taką możliwość. Myślę, że można uporządkować obecny komponent i spróbować stworzyć nowy bez ograniczeń stylu pseudoklasy elementu <progress>
. Warto je poznać.
Zróżnicujemy nasze podejścia i poznamy wszystkie sposoby tworzenia stron internetowych.
Utwórz wersję demonstracyjną, wyślij mi linki, a ja dodam je do sekcji z remiksami społeczności.