<progress>
öğesiyle renge uyarlanabilir ve erişilebilir bir yükleme çubuğu oluşturma hakkında temel bilgiler.
Bu yayında, <progress>
öğesiyle renge uyarlanabilir ve erişilebilir bir yükleme çubuğu oluşturma konusundaki düşüncelerimi paylaşmak istiyorum. Demoyu deneyin ve kaynağı görüntüleyin.
Video tercih ediyorsanız bu yayının YouTube versiyonunu aşağıda bulabilirsiniz:
Genel Bakış
<progress>
öğesi, kullanıcılara tamamlanma durumuyla ilgili görsel ve sesli geri bildirim sağlar. Bu görsel geri bildirim; formda ilerleme, indirme veya yükleme bilgilerini gösterme, hatta ilerleme miktarının bilinmediği ancak çalışmanın devam ettiği durumlar için değerlidir.
Bu GUI Challenge, erişilebilirlik konusunda biraz çaba sarf etmemek için mevcut HTML <progress>
öğesiyle birlikte çalıştı. Renkler ve düzenler, bileşeni modernleştirmek ve tasarım sistemlerine daha iyi uymasını sağlamak için yerleşik öğenin özelleştirme sınırlarını zorlar.

Brüt kar
<progress>
öğesini <label>
içine sarmayı tercih ettim. Böylece açık ilişki özelliklerini atlayıp örtülü bir ilişki kullanabildim.
Ayrıca, yükleme durumundan etkilenen bir üst öğeyi de etiketledim. Böylece ekran okuyucu teknolojileri bu bilgiyi kullanıcıya geri iletebilir.
<progress></progress>
value
yoksa öğenin ilerleme durumu belirsizdir.
max
özelliği varsayılan olarak 1'dir. Bu nedenle ilerleme durumu 0 ile 1 arasındadır. Örneğin, max
ayarını 100 olarak belirlemek aralığı 0-100 olarak ayarlar. 0 ile 1 arasındaki sınırları aşmamayı tercih ettim ve ilerleme değerlerini 0, 5 veya %50 olarak çevirdim.
Etiket sarmalanmış ilerleme durumu
Örtülü ilişkide, ilerleme öğesi şu şekilde bir etiketle sarmalanır:
<label>Loading progress<progress></progress></label>
Demomda etiketi yalnızca ekran okuyucular için eklemeyi seçtim.
Bu işlem, etiket metnini <span>
içine alarak ve ekranda görünmemesi için bazı stiller uygulayarak yapılır:
<label>
<span class="sr-only">Loading progress</span>
<progress></progress>
</label>
WebAIM'den aşağıdaki CSS ile birlikte:
.sr-only {
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(50%);
height: 1px;
width: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
}
Yükleme işleminden etkilenen alan
Görüşünüz sağlıklıysa ilerleme göstergesini ilgili öğeler ve sayfa alanlarıyla ilişkilendirmek kolay olabilir ancak görme engelli kullanıcılar için bu durum o kadar net değildir. Yükleme tamamlandığında değişecek en üstteki öğeye aria-busy
özelliğini atayarak bu sorunu düzeltebilirsiniz.
Ayrıca, ilerleme durumu ile yükleme alanı arasında aria-describedby
ile bir ilişki olduğunu belirtin.
<main id="loading-zone" aria-busy="true">
…
<progress aria-describedby="loading-zone"></progress>
</main>
JavaScript'te, görevin başında aria-busy
simgesini true
, tamamlandığında ise false
olarak değiştirin.
Aria özelliği eklemeleri
<progress>
öğesinin örtülü rolü progressbar
olsa da bu örtülü role sahip olmayan tarayıcılar için rolü açık hale getirdim. Ayrıca, öğeyi açıkça bilinmeyen bir duruma getirmek için indeterminate
özelliğini ekledim. Bu, öğede value
ayarlanmadığını gözlemlemekten daha net bir yöntemdir.
<label>
Loading
<progress
indeterminate
role="progressbar"
aria-describedby="loading-zone"
tabindex="-1"
>unknown</progress>
</label>
İlerleme öğesinin JavaScript'ten odaklanılabilir hale getirmek için
tabindex="-1"
kullanın. İlerleme durumu değiştikçe ilerleme durumuna odaklanmak, güncellenen ilerleme durumunun ne kadar ilerlediğini kullanıcıya bildireceğinden ekran okuyucu teknolojisi için önemlidir.
Stiller
İlerleme öğesinin stilini belirlemek biraz zordur. Yerleşik HTML öğelerinin, seçilmesi zor olabilen ve genellikle yalnızca sınırlı sayıda özelliğin ayarlanmasına olanak tanıyan özel gizli bölümleri vardır.
Düzen
Düzen stilleri, ilerleme öğesinin boyutu ve etiket konumunda bir miktar esneklik sağlamayı amaçlar. Faydalı olabilecek ancak zorunlu olmayan ek bir görsel ipucu olarak özel bir tamamlama durumu eklenir.
<progress>
Düzen
Tasarımda gereken alana göre küçülüp büyüyebilmesi için ilerleme öğesinin genişliğine dokunulmaz. Yerleşik stiller, appearance
ve border
değerleri none
olarak ayarlanarak kaldırılır. Bunun nedeni, her tarayıcının kendi öğesi için kendi stillerine sahip olmasıdır. Bu nedenle, öğenin tarayıcılarda normalleştirilmesi gerekir.
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;
}
_radius
için 1e3px
değeri, büyük bir sayıyı ifade etmek için bilimsel sayı gösterimini kullandığından border-radius
her zaman yuvarlanır. 1000px
ile eşdeğerdir. Bunu kullanmayı tercih ediyorum çünkü amacım, ayarlayıp unutabileceğim kadar büyük bir değer kullanmak (ve 1000px
değerinden daha kısa). Gerekirse değeri daha da büyütmek kolay: 3'ü 4 olarak değiştirmeniz yeterli. Bu durumda 1e4px
, 10000px
değerine eşit olur.
overflow: hidden
kullanılıyor ve tartışmalı bir stil oldu. Bu, border-radius
değerlerinin parçaya ve parça doldurma öğelerine aktarılmasına gerek olmaması gibi bazı şeyleri kolaylaştırdı ancak ilerleme öğesinin hiçbir alt öğesinin öğenin dışında bulunamayacağı anlamına da geliyordu. Bu özel ilerleme öğesinin başka bir yinelemesi overflow: hidden
olmadan yapılabilir ve animasyonlar veya daha iyi tamamlama durumları için bazı fırsatlar sunabilir.
İşlem tamamlandı
CSS seçiciler, maksimum değeri değerle karşılaştırarak zorlu işi yapar ve eşleşme olursa ilerleme tamamlanır. İşlem tamamlandığında, ilerleme öğesinin sonuna bir sözde öğe eklenir. Bu öğe, tamamlanma durumuyla ilgili güzel bir görsel ipucu sağlar.
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);
}
Renk
Tarayıcı, ilerleme öğesi için kendi renklerini kullanır ve yalnızca bir CSS özelliğiyle açık ve koyu temaya uyum sağlar. Bu, bazı özel tarayıcıya özgü seçicilerle geliştirilebilir.
Açık ve koyu tarayıcı stilleri
Sitenizi koyu ve açık renkli uyarlanabilir bir <progress>
öğesine kaydetmek için tek yapmanız gereken color-scheme
eklemektir.
progress {
color-scheme: light dark;
}
Tek mülk ilerleme durumu dolgu rengi
<progress>
öğesine renk tonu vermek için accent-color
kullanın.
progress {
accent-color: rebeccapurple;
}
accent-color
bağlı olarak parça arka plan renginin açıktan koyuya değiştiğini fark edin. Tarayıcı, uygun kontrastı sağlıyor.
Tamamen özel açık ve koyu renkler
<progress>
öğesinde iki özel özellik ayarlayın. Bunlardan biri parça rengi, diğeri ise parça ilerleme rengi için olmalıdır. prefers-color-scheme
medya sorgusunda, parça ve parça ilerleme durumu için yeni renk değerleri sağlayın.
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%);
}
}
Odaklanma stilleri
Daha önce, öğeye programatik olarak odaklanılabilmesi için negatif bir sekme dizini vermiştik. Daha akıllı odak halkası stilini etkinleştirmek için odaklamayı özelleştirmek üzere :focus-visible
simgesini kullanın. Bu ayar etkinleştirildiğinde, fare tıklaması ve odaklama işlemi odak halkasını göstermez ancak klavye tıklamaları gösterir. Bu konu, YouTube videosunda daha ayrıntılı olarak ele alınmaktadır ve incelenmesi önerilir.
progress:focus-visible {
outline-color: var(--_progress);
outline-offset: 5px;
}
Tarayıcılar genelinde özel stiller
Her tarayıcının gösterdiği <progress>
öğesinin bölümlerini seçerek stilleri özelleştirin. İlerleme öğesi tek bir etikettir ancak CSS sözde seçicileri aracılığıyla kullanıma sunulan birkaç alt öğeden oluşur. Chrome Geliştirici Araçları, ayarı etkinleştirirseniz bu öğeleri size gösterir:
- Sayfanızı sağ tıklayıp Öğeyi İncele'yi seçerek Geliştirici Araçları'nı açın.
- Geliştirici Araçları penceresinin sağ üst köşesindeki Ayarlar dişlisini tıklayın.
- Öğeler başlığı altında Kullanıcı aracısı gölge DOM'unu göster onay kutusunu bulun ve etkinleştirin.
Safari ve Chromium stilleri
Safari ve Chromium gibi WebKit tabanlı tarayıcılar, CSS'nin bir alt kümesinin kullanılmasına olanak tanıyan ::-webkit-progress-bar
ve ::-webkit-progress-value
özelliklerini kullanıma sunar. Şimdilik, açık ve koyu temaya uyum sağlayan, daha önce oluşturulmuş özel özellikleri kullanarak background-color
ayarlayın.
/* Safari/Chromium */
progress[value]::-webkit-progress-bar {
background-color: var(--_track);
}
progress[value]::-webkit-progress-value {
background-color: var(--_progress);
}
Firefox stilleri
Firefox, yalnızca ::-moz-progress-bar
sözde seçicisini <progress>
öğesinde kullanıma sunar. Bu, parçaya doğrudan renk tonu uygulayamayacağımız anlamına da gelir.
/* Firefox */
progress[value]::-moz-progress-bar {
background-color: var(--_progress);
}
Firefox'ta accent-color
renkli bir iz, iOS Safari'de ise açık mavi bir iz olduğunu fark edeceksiniz. Koyu modda da aynı durum söz konusudur: Firefox'ta koyu bir parça bulunur ancak ayarladığımız özel renk yoktur ve bu özellik Webkit tabanlı tarayıcılarda çalışır.
Animasyon
Tarayıcıda yerleşik sözde seçicilerle çalışırken genellikle izin verilen CSS özelliklerinin sınırlı bir kümesi kullanılır.
İzin dolmasını canlandırma
İlerleme öğesinin inline-size
kısmına geçiş eklemek Chromium'da çalışır ancak Safari'de çalışmaz. Firefox da ::-moz-progress-bar
üzerinde geçiş özelliği kullanmaz.
/* Chromium Only 😢 */
progress[value]::-webkit-progress-value {
background-color: var(--_progress);
transition: inline-size .25s ease-out;
}
:indeterminate
durumuna animasyon ekleme
Burada biraz daha yaratıcı davranarak animasyon ekleyebilirim. Chromium için bir sözde öğe oluşturulur ve üç tarayıcının tamamında ileri geri hareket eden bir gradyan uygulanır.
Özel özellikler
Özel özellikler birçok şey için harikadır ancak en sevdiğim kullanım alanlarından biri, aksi takdirde sihirli görünecek bir CSS değerine ad vermektir. Aşağıda, oldukça karmaşık olan ancak güzel bir ada sahip bir linear-gradient
gösterilmektedir. Amacı ve kullanım alanları net bir şekilde anlaşılabilir.
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;
}
Özel özellikler, tarayıcıya özgü bu seçicileri tekrar birlikte gruplandıramadığımız için kodun DRY kalmasına da yardımcı olur.
Animasyon kareleri
Amaç, ileri geri hareket eden sonsuz bir animasyon oluşturmaktır. Başlangıç ve bitiş anahtar kareleri CSS'de ayarlanır. Başladığı yere tekrar tekrar dönen bir animasyon oluşturmak için yalnızca bir animasyon karesi (50%
konumundaki orta animasyon karesi) yeterlidir.
@keyframes progress-loading {
50% {
background-position: left;
}
}
Her tarayıcıyı hedefleme
Her tarayıcı, <progress>
öğesinde sözde öğelerin oluşturulmasına veya ilerleme çubuğunun animasyonlandırılmasına izin vermez. Parçayı animasyonlu hale getirmeyi destekleyen tarayıcı sayısı, sözde öğeleri destekleyen tarayıcı sayısından daha fazla olduğundan temel olarak sözde öğelerden animasyonlu çubuklara geçiş yapıyorum.
Chromium sözde öğesi
Chromium, öğeyi kaplamak için konumla birlikte kullanılan ::after
sözde öğesine izin verir. Belirsiz özel özellikler kullanılır ve ileri geri animasyonu çok iyi çalışır.
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);
}
Safari ilerleme çubuğu
Safari'de özel özellikler ve animasyon, sözde öğe ilerleme çubuğuna uygulanır:
progress:indeterminate::-webkit-progress-bar {
background: var(--_indeterminate-track);
background-size: var(--_indeterminate-track-size);
background-position: right;
animation: var(--_indeterminate-track-animation);
}
Firefox ilerleme çubuğu
Firefox'ta özel özellikler ve animasyon, sözde öğe ilerleme çubuğuna da uygulanır:
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, <progress>
öğesiyle önemli bir rol oynar. Öğeye gönderilen değeri kontrol eder ve ekran okuyucular için dokümanda yeterli bilgi bulunduğundan emin olur.
const state = {
val: null
}
Demoda ilerlemeyi kontrol etmek için düğmeler bulunur. Bu düğmeler state.val
değerini günceller ve ardından DOM'u güncellemek için bir işlev çağırır.
document.querySelector('#complete').addEventListener('click', e => {
state.val = 1
setProgress()
})
setProgress()
Bu işlev, kullanıcı arayüzü/kullanıcı deneyimi düzenlemesinin gerçekleştiği yerdir. İşe bir işlev oluşturarak başlayın.setProgress()
state
nesnesine, ilerleme öğesine ve <main>
bölgesine erişebildiği için parametre gerekmez.
const setProgress = () => {
}
<main>
bölgesinde yükleme durumunu ayarlama
İlerlemenin tamamlanıp tamamlanmadığına bağlı olarak, ilgili <main>
öğesinin aria-busy
özelliğinin güncellenmesi gerekir:
const setProgress = () => {
zone.setAttribute('aria-busy', state.val < 1)
}
Yükleme tutarı bilinmiyorsa özellikleri temizleme
Değer bilinmiyorsa veya ayarlanmamışsa bu kullanımda null
, value
ve aria-valuenow
özelliklerini kaldırın. Bu işlem, <progress>
durumunu belirsiz hale getirir.
const setProgress = () => {
zone.setAttribute('aria-busy', state.val < 1)
if (state.val === null) {
progress.removeAttribute('aria-valuenow')
progress.removeAttribute('value')
progress.focus()
return
}
}
JavaScript ondalık matematik sorunlarını düzeltme
Varsayılan maksimum ilerleme değeri olan 1'i kullanmayı tercih ettiğim için demo
artırma ve azaltma işlevlerinde ondalık matematik kullanılır. JavaScript ve diğer diller bu konuda her zaman iyi değildir.
Matematik sonucundaki fazlalıkları kırpacak bir roundDecimals()
işlevi aşağıda verilmiştir:
const roundDecimals = (val, places) =>
+(Math.round(val + "e+" + places) + "e-" + places)
Değeri, sunulabilecek ve okunabilir olacak şekilde yuvarlayın:
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 + "%"
}
Ekran okuyucular ve tarayıcı durumu için değer ayarlama
Değer, DOM'da üç konumda kullanılır:
<progress>
öğesininvalue
özelliği.aria-valuenow
özelliği.<progress>
iç metin içeriği.
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
}
İlerleme durumuna odaklanma
Değerler güncellendiğinde görme engelli kullanıcılar ilerleme durumundaki değişikliği görür ancak ekran okuyucu kullanıcılarına henüz değişiklik duyurusu yapılmaz. <progress>
öğesine odaklanın. Tarayıcı, güncellemeyi duyurur.
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()
}
Sonuç
Bunu nasıl yaptığımı öğrendiğinize göre, siz nasıl yapardınız? 🙂
Başka bir şans verilirse kesinlikle yapmak istediğim birkaç değişiklik var. Mevcut bileşenin temizlenmesi ve <progress>
öğesinin sözde sınıf stili sınırlamaları olmadan bir bileşen oluşturulması gerektiğini düşünüyorum. Keşfetmeye değer!
Yaklaşımlarımızı çeşitlendirelim ve web'de içerik oluşturmanın tüm yollarını öğrenelim.
Bir demo oluşturun, bağlantıları bana tweet atın. Ben de bu bağlantıları aşağıdaki topluluk remiksleri bölümüne ekleyeyim.