Tworzenie komponentu paska wczytywania

Podstawowe omówienie sposobu tworzenia kolorowego, adaptacyjnego i łatwo dostępnego paska wczytywania za pomocą elementu <progress>.

W tym poście opowiem, jak stworzyć dostępny pasek wczytywania z elementem <progress>. Wypróbuj w wersji demonstracyjnej i obejrzyj !

W Chrome prezentowano jasne i ciemne, nieokreślone, rosnące i pełne możliwości.

Jeśli wolisz film, oto wersja tego posta w YouTube:

Omówienie

<progress> dostarcza użytkownikom wizualną i dźwiękową informację o ukończeniu zadania. Ten opinie wizualne są przydatne w przypadku takich scenariuszy, jak: postęp w wypełnianiu formularza, wyświetlanie informacji o pobieraniu lub przesyłaniu, a nawet pokazywanie, wielkość postępu jest nieznana, ale prace wciąż trwają.

To Wyzwanie GUI pracowało z istniejącego elementu HTML <progress>, aby zaoszczędzić trochę wysiłku związanych z ułatwieniami dostępu. kolory i układy zwiększają możliwości dostosowania do wbudowanego elementu zmodernizować komponent i lepiej dopasować go do systemów projektowania.

Jasne i ciemne karty w każdej przeglądarce zawierają 
    Omówienie ikony adaptacyjnej od góry do dołu: 
    Safari, Firefox, Chrome.
Wersja demonstracyjna dostępna w przeglądarkach Firefox, Safari, iOS Safari, Chrome i Chrome na Androida w ciemnych i jasnych schematach.

Markup

Element <progress> chcę umieścić w nagłówku <label> tak Mogę pominąć atrybuty jawne w relacjach na rzecz niejawnego . Oznaczyłem też element nadrzędny, na który wpływa stan wczytywania, więc dzięki technologiom do odczytywania danych użytkownikowi.

<progress></progress>

Jeśli brak wartości value, postęp elementu jest taki jak nieokreślone. Atrybut max przyjmuje domyślnie wartość 1, więc postęp mieści się w zakresie od 0 do 1. Ustawiam max na przykład jako 100 ustawi zakres od 0 do 100. Zdecydowałem się zmieścić w zakresie 0 i 1, co przełoży się na postęp na 0,5 lub 50%.

Postęp dodawania etykiet

W relacji niejawnej element postępu jest opakowany w taki sposób:

<label>Loading progress<progress></progress></label>

W mojej wersji demonstracyjnej dodaję etykietę dla czytników ekranu . Można to zrobić, zawijając tekst etykiety do obszaru <span> i stosując kilka stylów. aby usunąć go z ekranu:

<label>
  <span class="sr-only">Loading progress</span>
  <progress></progress>
</label>

Za pomocą tej usługi porównywania cen 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;
}

Zrzut ekranu przedstawiający narzędzia deweloperskie z elementem tylko na ekranie.

Obszar, na który wpływa postęp wczytywania

Jeśli masz zdrowy wzrok, możesz łatwo powiązać wskaźnik postępu z powiązanymi elementami i obszarami strony, ale użytkownicy niedowidzący mogą mieć tak jasne. Możesz to poprawić, przypisując parametr aria-busy do elementu najwyższego poziomu, który zmieni się po zakończeniu wczytywania. Ponadto wskaż zależność między postępem a strefą ładowania. z aria-describedby

<main id="loading-zone" aria-busy="true">
  …
  <progress aria-describedby="loading-zone"></progress>
</main>

Z języka JavaScript przełącz ustawienie aria-busy na true na początku zadania i na false po zakończeniu.

Dodania atrybutów Aria

Pośrednią rolą elementu <progress> jest progressbar, nazwa została ustawiona dla pełnoletnich w przypadku przeglądarek, które nie mają takiej roli. Dodałem też atrybut indeterminate, aby jednoznacznie ustawić element w stanie nieznanym, czyli jest bardziej zrozumiały niż obserwacja elementu, dla którego nie ustawiono elementu value.

<label>
  Loading 
  <progress 
    indeterminate 
    role="progressbar" 
    aria-describedby="loading-zone"
    tabindex="-1"
  >unknown</progress>
</label>

Używaj tabindex="-1" , by możliwe było zaznaczenie elementu postępu w JavaScripcie. To ważne w przypadku: czytnika ekranu, ponieważ skupienie się na postępach poinformuje użytkownika o tym, jak daleko zaszedł aktualizowany postęp.

Style

Element postępu nie jest łatwy, jeśli chodzi o stylizację. Wbudowany kod HTML elementy zawierają specjalne ukryte części, które może być trudno wybrać i często pozwalają skonfigurować tylko ograniczony zestaw właściwości.

Układ

Style układu mają dawać pewne możliwości elastyczności w procesie tworzenia nowego układu. rozmiaru i pozycji etykiety. Dodano specjalny stan ukończenia, który może może być przydatnym, ale niewymaganym, dodatkowym elementem wizualnym.

Układ <progress>

Szerokość elementu postępu pozostaje nienaruszona, dzięki czemu może się zmniejszać i powiększać. z ilością potrzebnej przestrzeni w projekcie. Style wbudowane są pomijane przez Ustawianie wartości appearance i border na none. Dzięki temu element może być znormalizowane w różnych przeglądarkach, ponieważ każda przeglądarka ma własne style .

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 wykorzystuje liczbę naukową duża liczba, więc border-radius jest zawsze zaokrąglany. Jest to odpowiednik 1000px Zależy mi na tym, aby użyć dostatecznie dużej wartości, Mogę go ustawić i zapomnieć go (i napis jest krótszy niż 1000px). Jest także w razie potrzeby można go jeszcze bardziej powiększyć: wystarczy zmienić 3 na 4, a 1e4px odpowiednik 10000px.

Styl overflow: hidden jest używany i jest spornym. Dzięki temu udało mu się dużo łatwiejsze, na przykład nie trzeba przekazywać wartości border-radius do funkcji śledzenie i śledzenie elementów wypełnienia; ale też nie oznaczał dla dzieci postępów mogą znajdować się poza granicami tego elementu. Kolejna iteracja tego niestandardowego postępu można wykonać bez użycia funkcji overflow: hidden. Może on otworzyć i lepszy stan ukończenia.

Gotowe

Selektory CSS wykonują tu najtrudniejszą pracę, porównując wartość maksymalną z wartością. Jeśli się zgadzają, kończy się proces. Gdy to zrobisz, zostanie wygenerowany pseudoelement, który zostanie dołączony na końcu elementu postępu, co stanowi dodatkowy wizualny sygnał potwierdzający zakończenie.

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);
}

Zrzut ekranu pokazujący pasek wczytywania w 100% i znacznik wyboru na końcu.

Kolor

Przeglądarka ma własne kolory dla elementu postępu i dostosowuje się jasne i ciemne za pomocą tylko jednej właściwości CSS. Można go opracować przy użyciu specjalne selektory dla konkretnej przeglądarki.

Jasne i ciemne style przeglądarki

Aby włączyć na stronie ciemny i jasny adaptacyjny element <progress>: Wystarczy color-scheme.

progress {
  color-scheme: light dark;
}

Kolor wypełnienia pojedynczej usługi

Aby zmienić odcień 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: całkiem schludnie.

W pełni niestandardowe jasne i ciemne kolory

Ustaw 2 właściwości niestandardowe elementu <progress>, jedną dla koloru ścieżki a drugi – kolor postępu ścieżki. Wewnątrz prefers-color-scheme zapytania o media, podaj nowe wartości kolorów dla ścieżki i śledź postęp.

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%);
  }
}

Zaznacz style

Wcześniej przypisaliśmy temu elementowi ujemny indeks tabulacji, dzięki czemu można go automatycznie skupieni. Używaj :focus-visible do Dostosuj ostrość, aby korzystać z inteligentniejszego pierścienia. Dzięki temu pierścień zaznaczenia nie pojawi się, ale za pomocą klawiatury. Więcej informacji jest dostępnych w filmie w YouTube. warto się z nim zapoznać.

progress:focus-visible {
  outline-color: var(--_progress);
  outline-offset: 5px;
}

Zrzut ekranu przedstawiający pasek wczytywania z pierścieniem regulacji ostrości. Wszystkie kolory się zgadzają.

Style niestandardowe w różnych przeglądarkach

Dostosuj style, wybierając elementy elementu <progress>, z których każdy co pokazuje przeglądarka. Użycie elementu postępu to pojedynczy tag, a składa się z elementów podrzędnych, które są wyświetlane przez pseudoselektory CSS. Narzędzia deweloperskie w Chrome spowoduje wyświetlenie następujących elementów, jeśli włączysz to ustawienie:

  1. Kliknij stronę prawym przyciskiem myszy i wybierz Zbadaj element, aby wyświetlić Narzędzia deweloperskie.
  2. Kliknij koło zębate ustawień w prawym górnym rogu okna Narzędzia deweloperskie.
  3. W nagłówku Elements znajdź i włącz opcję Pokaż cień klienta użytkownika. DOM.

Zrzut ekranu pokazujący miejsce w Narzędziach deweloperskich, które umożliwia ujawnienie modelu shadow DOM klienta użytkownika.

Style w Safari i Chromium

Przeglądarki oparte na silnikach WebKit, takie jak Safari i Chromium, ujawniają ::-webkit-progress-bar i ::-webkit-progress-value, które zezwalają na podzbiór CSS, który ma być używany. Na razie ustaw background-color za pomocą właściwości niestandardowych które dostosowują się do oświetlenia i ciemności.

/*  Safari/Chromium  */
progress[value]::-webkit-progress-bar {
  background-color: var(--_track);
}

progress[value]::-webkit-progress-value {
  background-color: var(--_progress);
}

Zrzut ekranu przedstawiający wewnętrzne elementy elementu postępu.

Style w przeglądarce Firefox

Firefox wyświetla pseudoselektor ::-moz-progress-bar tylko na stronie <progress>. Oznacza to również, że nie możemy zmienić zabarwienia ścieżki bezpośrednio.

/*  Firefox  */
progress[value]::-moz-progress-bar {
  background-color: var(--_progress);
}

Zrzut ekranu przeglądarki Firefox z informacją, gdzie można znaleźć elementy dotyczące postępu.

zrzut ekranu obszaru Debugging Corner, w którym Safari, iOS Safari 
  W przeglądarkach Firefox, Chrome i Chrome na urządzeniach z Androidem pasek wczytywania działa.

Zwróć uwagę, że kolor ścieżki w przeglądarce Firefox został ustawiony na accent-color, a w iOS Safari. ma jasnoniebieską ścieżkę. Tak samo jest w trybie ciemnym: Firefox ma ciemną ścieżkę, ale jest inny niż ustawiony przez nas kolor niestandardowy i działa w przeglądarkach opartych na pakiecie WebKit.

Animacja

Podczas pracy z wbudowanymi pseudoselektorami w przeglądarce często używa się dopuszczalnych właściwości CSS.

Animacja wypełniania ścieżki

Dodaję przejście do inline-size z element postępu działa w Chromium, ale nie w Safari. Firefox też nie używaj właściwości przejścia w jego zmiennej ::-moz-progress-bar.

/*  Chromium Only 😢  */
progress[value]::-webkit-progress-value {
  background-color: var(--_progress);
  transition: inline-size .25s ease-out;
}

Animowanie stanu :indeterminate

Teraz zrobię się nieco bardziej kreatywnie, więc mogę utworzyć animację. Pseudoelement dla Chromium i zostaje zastosowany gradient, dla wszystkich trzech przeglądarek.

Właściwości niestandardowe

Niestandardowe właściwości świetnie sprawdzają się w różnych zastosowaniach, ale jedną z moich ulubionych jest po prostu nadanie nazwy wartości CSS, która ma inny wygląd. Dalej to już dość Złożone linear-gradient ale z ładną nazwą. Jej 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ą również w pozostawieniu kodu DRY, bo po raz kolejny nie możemy pogrupować selektory właściwe dla danej przeglądarki.

Klatki kluczowe

Celem jest uzyskanie nieskończonej animacji, która pojawia się w tę i z powrotem. początek i koniec. klatki kluczowe zostaną ustawione w CSS. Potrzebna jest tylko 1 klatka kluczowa – środkowa klatka kluczowa. w 50%, by utworzyć animację, która wróci do miejsca, w którym się rozpoczęła, znowu!

@keyframes progress-loading {
  50% {
    background-position: left; 
  }
}

Kierowanie na każdą przeglądarkę

Nie każda przeglądarka umożliwia tworzenie pseudoelementów w <progress>. lub animowanie paska postępu. Więcej przeglądarek obsługuje animowanie ścieżki niż pseudoelement, więc uaktualniam pseudoelementy jako na bazie animacji.

Pseudoelement Chrome

Chromium zezwala na pseudoelement: ::after używany z pozycją zasłonięcia elementu. Używane są nieokreślone właściwości niestandardowe, a że czwarta animacja 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 w Safari

W przeglądarce Safari właściwości niestandardowe i animacja są stosowane do obiektu pseudoelementowy pasek postępu:

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 przeglądarki Firefox

W przeglądarce Firefox właściwości niestandardowe i animacja są również stosowane do elementu pseudoelementowy pasek postępu:

progress:indeterminate::-moz-progress-bar {
  background: var(--_indeterminate-track);
  background-size: var(--_indeterminate-track-size);
  background-position: right; 
  animation: var(--_indeterminate-track-animation);
}

JavaScript

JavaScript odgrywa ważną rolę z elementem <progress>. Kontroluje to wysyłaną do elementu wartość i zapewnia, że w parametrze do czytników ekranu.

const state = {
  val: null
}

W wersji demonstracyjnej dostępne są przyciski do kontrolowania postępu. aktualizowanie: state.val a potem wywołaj funkcję aktualizacji DOM.

document.querySelector('#complete').addEventListener('click', e => {
  state.val = 1
  setProgress()
})

setProgress()

Ta funkcja służy do administrowania UI/UX. Zacznij od utworzenia setProgress(). Parametry nie są potrzebne, ponieważ ma on dostęp do Obiekt state, element postępu i strefa <main>.

const setProgress = () => {
  
}

Ustawiam stan wczytywania w strefie <main>

W zależności od tego, czy przetwarzanie został ukończony, czy nie, powiązane <main> wymaga aktualizacji aria-busy. :

const setProgress = () => {
  zone.setAttribute('aria-busy', state.val < 1)
}

Wyczyść atrybuty, jeśli ilość wczytywania jest nieznana

Jeśli wartość jest nieznana lub nieskonfigurowana, null w przypadku tego zastosowania usuń value i Atrybuty: aria-valuenow. Spowoduje to zmianę stanu <progress> na nieokreślony.

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ą liczb dziesiętnych w JavaScripcie

Zdecydowałam się zachować domyślne maksimum postępu, czyli 1, dlatego wersja demonstracyjna Funkcje zwiększania i zmniejszania liczby używają wartości dziesiętnych. JavaScript i inne ale nie zawsze są też świetne . Oto funkcja roundDecimals(), która pozwoli uniknąć nadmiaru informacji matematycznych wynik:

const roundDecimals = (val, places) =>
  +(Math.round(val + "e+" + places)  + "e-" + places)

Zaokrąglaj wartość, aby była widoczna i 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 + "%"
}

Ustaw wartość czytników ekranu i stanu przeglądarki

Wartość jest używana w 3 miejscach w modelu DOM:

  1. Atrybut value elementu <progress>.
  2. Atrybut aria-valuenow.
  3. Wewnętrzna zawartość tekstowa w <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
}

Koncentracja na postępach

Po zaktualizowaniu wartości widzący użytkownicy zobaczą zmianę postępu, ale na ekranie czytelnicy nie otrzymali jeszcze ogłoszenia o zmianie. Zaznacz <progress>, a przeglądarka poinformuje 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()
}

Zrzut ekranu aplikacji Voice Over w systemie macOS 
  odczytywanie przez użytkownika postępu wczytywania paska wczytywania.

Podsumowanie

Wiesz już, jak to zrobiłem. Jak Ty? 🙂

Z pewnością chcę wprowadzić kilka zmian, jeśli mam jeszcze szansę. Myślę, że jest miejsce na uporządkowanie bieżącego komponentu i stworzenie takiego elementu bez ograniczeń pseudoklasowych elementów <progress>. Warto się tego przyjrzeć!

Stosujmy różne podejścia i poznajmy sposoby budowania obecności w internecie.

Utwórz wersję demonstracyjną, a potem dodaj linki do funkcji tweetuj mi. znajdziesz poniżej w sekcji z remiksami na karcie Społeczność.

Remiksy utworzone przez społeczność