Ringkasan dasar tentang cara membangun status pemuatan yang adaptif warna dan dapat diakses dengan elemen <progress>
.
Dalam postingan ini saya ingin berbagi pemikiran tentang cara membangun warna yang adaptif dan
panel pemuatan yang dapat diakses dengan elemen <progress>
. Coba
demo dan lihat
sumber Google Cloud Anda.
Jika Anda lebih suka menonton video, berikut versi YouTube untuk postingan ini:
Ringkasan
Tujuan
<progress>
elemen menyediakan umpan balik visual dan
terdengar kepada pengguna tentang penyelesaian proyek. Ini
masukan visual penting untuk skenario seperti: kemajuan dalam melalui formulir,
menampilkan informasi download atau upload, atau bahkan menunjukkan bahwa
jumlah progres tidak diketahui tetapi pekerjaan masih aktif.
Tantangan GUI ini bekerja dengan
elemen <progress>
HTML yang ada untuk menghemat upaya aksesibilitas. Tujuan
warna dan tata letak mendorong batas-batas
penyesuaian untuk elemen bawaan, untuk
memodernisasi komponen dan membuatnya
lebih cocok dalam sistem desain.
Markup
Saya memilih untuk menggabungkan elemen <progress>
dalam
<label>
jadi
Saya dapat melewati atribut hubungan eksplisit dan menggantinya dengan
hubungan akun.
Saya juga telah memberi label elemen induk
yang terpengaruh oleh status pemuatan, jadi
teknologi pembaca dapat menyampaikan informasi itu kembali kepada pengguna.
<progress></progress>
Jika tidak ada value
, progres elemen akan
tidak tentu.
Atribut max
ditetapkan secara default ke 1, sehingga progresnya antara 0 dan 1. Menyetel max
ke 100, misalnya, akan menetapkan rentang ke 0-100. Saya memilih untuk
tetap berada di angka 0,
dan 1 batas, menerjemahkan nilai kemajuan menjadi 0,5 atau 50%.
Progres yang digabungkan dengan label
Dalam hubungan implisit, elemen progres digabungkan dengan label seperti ini:
<label>Loading progress<progress></progress></label>
Dalam demo saya, saya memilih untuk menyertakan label untuk pembaca layar
saja.
Hal ini dilakukan dengan menggabungkan teks label dalam <span>
dan menerapkan beberapa gaya
agar alat ini bisa benar-benar keluar dari layar:
<label>
<span class="sr-only">Loading progress</span>
<progress></progress>
</label>
Dengan CSS yang disertakan dari WebAIM berikut:
.sr-only {
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(50%);
height: 1px;
width: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
}
Area yang terpengaruh oleh progres pemuatan
Jika Anda memiliki penglihatan yang sehat, mudah untuk mengaitkan indikator kemajuan
dengan elemen dan area halaman terkait, namun untuk
pengguna penyandang gangguan penglihatan,
begitu jelas. Tingkatkan hal ini dengan menetapkan
aria-busy
ke elemen paling atas yang akan berubah saat pemuatan selesai.
Selain itu, tunjukkan hubungan antara progres dan zona pemuatan
dengan
aria-describedby
<main id="loading-zone" aria-busy="true">
…
<progress aria-describedby="loading-zone"></progress>
</main>
Dari JavaScript, alihkan aria-busy
ke true
di awal tugas, dan
false
setelah selesai.
Penambahan atribut Aria
Meskipun peran implisit elemen <progress>
adalah
progressbar
, saya telah membuatnya vulgar
bagi browser yang tidak
memiliki peran implisit tersebut. Saya juga telah
menambahkan atribut
indeterminate
untuk secara eksplisit menempatkan elemen ke dalam status tidak diketahui, yaitu
lebih jelas daripada mengamati elemen yang belum ditetapkan value
.
<label>
Loading
<progress
indeterminate
role="progressbar"
aria-describedby="loading-zone"
tabindex="-1"
>unknown</progress>
</label>
Gunakan
tabindex="-1"
untuk membuat elemen progres dapat difokuskan dari JavaScript. Hal ini penting bagi
teknologi {i>screen reader<i}, karena memberikan fokus pada kemajuan
ketika kemajuan berubah,
akan memberi tahu pengguna seberapa jauh progres yang telah diperbarui.
Gaya
Elemen progres agak rumit dalam hal penataan gaya. HTML Bawaan elemen memiliki bagian tersembunyi khusus yang mungkin sulit untuk dipilih dan sering hanya menawarkan serangkaian properti terbatas untuk ditetapkan.
Tata Letak
Gaya tata letak dimaksudkan untuk memberikan fleksibilitas dalam prosesnya ukuran dan posisi label elemen. Menambahkan status penyelesaian khusus yang dapat menjadi petunjuk visual tambahan yang berguna, tetapi tidak diperlukan.
Tata Letak <progress>
Lebar elemen progres tidak disentuh sehingga dapat menciut dan membesar
dengan ruang yang
dibutuhkan dalam desain. Gaya {i>built-in<i} dihilangkan oleh
menyetel appearance
dan border
ke none
. Hal ini dilakukan agar elemen dapat
dinormalkan di seluruh browser, karena setiap browser memiliki gaya sendiri untuk
.
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;
}
Nilai 1e3px
untuk _radius
menggunakan bilangan ilmiah
notasi untuk mengekspresikan
angka besar sehingga border-radius
selalu dibulatkan. Ini setara dengan
1000px
. Saya suka menggunakan ini karena tujuan saya adalah
menggunakan nilai yang cukup besar sehingga
Saya dapat menyetelnya dan melupakannya (dan penulisannya lebih pendek daripada 1000px
). Ini juga
mudah untuk membuatnya lebih besar lagi jika diperlukan: cukup ubah 3 menjadi 4, maka 1e4px
adalah
setara dengan 10000px
.
overflow: hidden
digunakan dan telah menjadi gaya yang bertentangan. Hal itu menghasilkan beberapa
hal-hal mudah, seperti tidak perlu meneruskan nilai border-radius
ke
melacak, dan melacak elemen isian; tapi itu juga berarti tidak ada anak-anak dari kemajuan
bisa hidup di luar elemen. Iterasi lain pada progres kustom ini
elemen dapat dilakukan tanpa overflow: hidden
dan mungkin membuka beberapa
peluang untuk menghasilkan animasi atau
status penyelesaian yang lebih baik.
Proses selesai
Pemilih CSS melakukan pekerjaan sulit di sini dengan membandingkan nilai maksimum dengan nilai, dan jika cocok, progres sudah selesai. Setelah selesai, elemen semu akan dibuat dan ditambahkan ke bagian akhir elemen progres, sehingga memberikan isyarat visual tambahan yang bagus untuk penyelesaian.
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);
}
Warna
Browser menghadirkan warnanya sendiri untuk elemen progres, dan adaptif untuk terang dan gelap hanya dengan satu properti CSS. Model ini dapat dikembangkan dengan beberapa {i>browser<i} khusus yang khusus digunakan.
Gaya browser terang dan gelap
Untuk mengikutsertakan situs Anda ke elemen <progress>
adaptif gelap dan terang,
Anda hanya perlu color-scheme
.
progress {
color-scheme: light dark;
}
Warna terisi progres properti tunggal
Untuk mewarnai elemen <progress>
, gunakan accent-color
.
progress {
accent-color: rebeccapurple;
}
Perhatikan bahwa warna latar belakang trek berubah dari terang ke gelap tergantung pada
accent-color
. Browser memastikan kontras yang tepat: cukup rapi.
Warna terang dan gelap yang sepenuhnya kustom
Tetapkan dua properti khusus pada elemen <progress>
, satu untuk warna trek
dan satu lagi untuk warna
kemajuan lintasan. Di dalam
prefers-color-scheme
kueri media, memberikan nilai warna baru untuk jalur dan melacak kemajuan.
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%);
}
}
Memfokuskan gaya
Sebelumnya, kita memberi elemen indeks tab negatif sehingga dapat digunakan secara terprogram
tetap fokus. Gunakan
:focus-visible
ke
sesuaikan fokus untuk memilih ikut serta dalam gaya lingkaran fokus yang lebih cerdas. Dengannya, mouse
klik dan fokus tidak akan menampilkan
cincin fokus, tetapi klik keyboard akan melakukannya. Tujuan
Video YouTube membahas hal ini secara lebih mendalam dan
layak untuk ditinjau.
progress:focus-visible {
outline-color: var(--_progress);
outline-offset: 5px;
}
Gaya kustom di seluruh browser
Sesuaikan gaya dengan memilih bagian dari elemen <progress>
yang masing-masing
ekspos browser. Menggunakan elemen progres adalah satu tag, tetapi terdiri dari
beberapa elemen turunan yang diekspos melalui pemilih pseudo CSS. DevTools Chrome
akan menampilkan elemen ini jika Anda mengaktifkan setelan:
- Klik kanan di halaman Anda dan pilih Periksa Elemen untuk membuka DevTools.
- Klik roda gigi Settings di sudut kanan atas jendela DevTools.
- Di bawah judul Elements, cari dan aktifkan Tampilkan bayangan agen pengguna DOM.
Gaya Safari dan Chromium
Browser berbasis WebKit seperti Safari dan Chromium mengekspos
::-webkit-progress-bar
dan ::-webkit-progress-value
, yang memungkinkan subset
CSS yang akan digunakan. Untuk saat ini, tetapkan background-color
menggunakan properti kustom
yang dibuat sebelumnya, yang
beradaptasi dengan terang dan gelap.
/* Safari/Chromium */
progress[value]::-webkit-progress-bar {
background-color: var(--_track);
}
progress[value]::-webkit-progress-value {
background-color: var(--_progress);
}
Gaya Firefox
Firefox hanya mengekspos pemilih pseudo ::-moz-progress-bar
pada
elemen <progress>
. Hal ini juga berarti kami tidak dapat memberi warna pada trek secara langsung.
/* Firefox */
progress[value]::-moz-progress-bar {
background-color: var(--_progress);
}
Perhatikan bahwa Firefox memiliki warna trek yang ditetapkan dari accent-color
saat iOS Safari
memiliki trek berwarna biru muda. Demikian juga dalam mode gelap: Firefox memiliki jalur gelap tetapi
bukan warna khusus yang telah kita tetapkan, dan
bekerja di {i>browser<i} berbasis Webkit.
Animasi
Saat bekerja dengan pemilih semu bawaan browser, biasanya dengan sekumpulan properti CSS yang diizinkan.
Menganimasikan trek yang terisi
Menambahkan transisi ke
inline-size
dari
elemen progres berfungsi untuk Chromium, tetapi tidak untuk Safari. Firefox juga melakukan
tidak menggunakan properti transisi pada ::-moz-progress-bar
-nya.
/* Chromium Only 😢 */
progress[value]::-webkit-progress-value {
background-color: var(--_progress);
transition: inline-size .25s ease-out;
}
Menganimasikan status :indeterminate
Di sini saya menjadi sedikit lebih kreatif sehingga saya dapat memberikan animasi. Elemen semu untuk Chromium dibuat dan gradien diterapkan dengan animasi kembali dan untuk ketiga browser.
Properti khusus
Properti khusus cocok untuk banyak hal, tetapi salah satu favorit saya adalah
memberi nama pada nilai CSS
yang tampak ajaib. Mengikuti adalah
kompleks
linear-gradient
,
tapi dengan nama yang bagus. Tujuan dan kasus penggunaannya dapat dipahami dengan jelas.
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;
}
Properti khusus juga akan membantu kode tetap KERAS karena sekali lagi, kita tidak dapat mengelompokkan pemilih khusus browser tersebut.
Keyframe
Tujuannya adalah animasi tanpa batas yang bolak-balik. Awal dan akhir
keyframe akan ditetapkan dalam CSS. Hanya satu keyframe yang diperlukan, keyframe tengah
di 50%
, untuk membuat animasi yang kembali ke tempat awal tersebut dimulai, berulang kali,
coba lagi!
@keyframes progress-loading {
50% {
background-position: left;
}
}
Menargetkan setiap browser
Tidak semua browser mengizinkan pembuatan elemen pseudo di <progress>
elemen itu sendiri atau memungkinkan
animasi bilah kemajuan. Dukungan browser lainnya
menganimasikan jalur daripada elemen
pseudo, jadi saya mengupgrade dari elemen
dasar dan berubah menjadi batang animasi.
Elemen semu Chromium
Chromium mengizinkan elemen pseudo: ::after
digunakan dengan posisi menutupi
elemen ini. Properti khusus yang tidak tentu digunakan, dan bagian belakang serta
animasi maju akan bekerja dengan sangat baik.
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);
}
Status progres Safari
Untuk Safari, properti khusus dan animasi diterapkan ke status progres elemen semu:
progress:indeterminate::-webkit-progress-bar {
background: var(--_indeterminate-track);
background-size: var(--_indeterminate-track-size);
background-position: right;
animation: var(--_indeterminate-track-animation);
}
Status progres Firefox
Untuk Firefox, properti khusus dan animasi juga diterapkan ke status progres elemen semu:
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 memainkan peran penting dengan elemen <progress>
. Mengontrol
nilai yang dikirim ke elemen dan memastikan informasi yang cukup ada dalam
untuk pembaca layar.
const state = {
val: null
}
Demo ini menawarkan tombol untuk mengontrol progres; mereka memperbarui state.val
dan kemudian memanggil fungsi untuk memperbarui
DOM.
document.querySelector('#complete').addEventListener('click', e => {
state.val = 1
setProgress()
})
setProgress()
Fungsi ini adalah tempat orkestrasi UI/UX terjadi. Mulai dengan membuat
Fungsi setProgress()
. Tidak ada parameter yang diperlukan karena memiliki akses ke
Objek state
, elemen progres, dan zona <main>
.
const setProgress = () => {
}
Menetapkan status pemuatan di zona <main>
Bergantung pada apakah progres selesai atau belum, <main>
yang terkait
membutuhkan pembaruan ke
aria-busy
:
const setProgress = () => {
zone.setAttribute('aria-busy', state.val < 1)
}
Hapus atribut jika jumlah pemuatan tidak diketahui
Jika nilai tidak diketahui atau tidak disetel, null
dalam penggunaan ini, hapus value
dan
Atribut aria-valuenow
. Tindakan ini akan mengubah <progress>
menjadi tidak tentu.
const setProgress = () => {
zone.setAttribute('aria-busy', state.val < 1)
if (state.val === null) {
progress.removeAttribute('aria-valuenow')
progress.removeAttribute('value')
progress.focus()
return
}
}
Memperbaiki masalah matematika desimal JavaScript
Karena saya memilih untuk tetap menggunakan {i>
default progres<i} maksimum 1, demo
fungsi pertambahan dan pengurangan menggunakan
matematika desimal. JavaScript, dan lainnya
bahasa, tidak selalu mahir dalam
itu.
Berikut adalah fungsi roundDecimals()
yang akan memangkas kelebihan perhitungan dari matematika
hasil:
const roundDecimals = (val, places) =>
+(Math.round(val + "e+" + places) + "e-" + places)
Bulatkan nilai agar dapat disajikan dan dapat dibaca:
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 + "%"
}
Menetapkan nilai untuk pembaca layar dan status browser
Nilai ini digunakan di tiga lokasi di DOM:
- Atribut
value
milik elemen<progress>
. - Atribut
aria-valuenow
. - Konten teks dalam
<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
}
Memberikan fokus pada progres
Dengan nilai yang diperbarui, pengguna yang normal akan melihat perubahan kemajuan, tetapi
pengguna pembaca belum diberi pengumuman perubahan. Fokus pada
Elemen <progress>
dan browser akan mengumumkan update!
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()
}
Kesimpulan
Sekarang setelah Anda tahu bagaimana saya melakukannya, bagaimana Anda akan 🙂
Tentu saja ada beberapa perubahan yang ingin saya lakukan jika diberi kesempatan lain. Menurut saya, ada ruang untuk membersihkan komponen saat ini, dan ada ruang untuk mencoba membuat komponen tanpa batasan gaya class semu elemen <progress>
. Menarik untuk dijelajahi!
Mari kita diversifikasi pendekatan kami dan mempelajari semua cara untuk membangun di web.
Buat demo, link tweet saya, dan saya akan menambahkannya ke bagian remix komunitas di bawah ini.