<progress>
öğesi ile renk uyarlamalı ve erişilebilir bir yükleme çubuğu oluşturma hakkında temel bilgiler.
Bu yayında, <progress>
öğesini kullanarak renk uyumlu ve erişilebilir bir yükleme çubuğu oluşturma konusundaki düşüncelerimi paylaşmak istiyorum. Demoyu deneyin ve kaynağı görüntüleyin.
Videoyu tercih ediyorsanız bu yayının YouTube sürümünü burada bulabilirsiniz:
Genel Bakış
<progress>
öğesi, kullanıcılara tamamlama hakkında görsel ve işitsel geri bildirim sağlar. Bu görsel geri bildirim, formdaki ilerleme durumu, indirme veya yükleme bilgilerinin gösterilmesi ya da ilerleme miktarının bilinmediği ancak çalışmanın devam ettiği durumların gösterilmesi gibi senaryolar için değerlidir.
Bu GUI Challenge, erişilebilirlik konusunda biraz çabadan tasarruf etmek için mevcut HTML <progress>
öğesiyle çalıştı. Renkler ve düzenler, bileşeni modernize etmek ve tasarım sistemlerine daha iyi sığdırmak için yerleşik öğenin özelleştirme sınırlarını zorlar.
Brüt kar
<progress>
öğesini bir <label>
içine sarmayı tercih ettim. Böylece dolaylı bir ilişkinin lehine olan açık ilişki özelliklerini atlayabilirim.
Ayrıca, yükleme durumundan etkilenen bir üst öğeyi de etiketledim. Böylece ekran okuyucu teknolojileri bu bilgileri kullanıcıya geri iletebilir.
<progress></progress>
value
yoksa öğenin ilerleme durumu belirsizdir.
max
özelliği varsayılan olarak 1 değerine ayarlanır. Bu nedenle ilerleme 0 ile 1 arasındadır. Örneğin, max
değerini 100 olarak ayarlamak aralığı 0-100 olarak ayarlar. 0 ile 1 sınırları arasında kalmayı tercih ederek ilerleme değerlerini 0,5 veya %50 olarak çevirdim.
Etiket sarmalanmış ilerleme durumu
Dolaylı bir ilişkide, ilerleme öğesi şuna benzer 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 metninin bir <span>
içine sarmalanması ve etkili bir şekilde ekran dışında kalması için metne bazı stiller uygulanmasıyla yapılır:
<label>
<span class="sr-only">Loading progress</span>
<progress></progress>
</label>
WebAIM'den aşağıdaki CSS ile:
.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 ilerleme durumundan etkilenen alan
İyi bir görüşünüz varsa ilerleme göstergelerini ilgili öğelerle 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 durumu iyileştirin.
Ayrıca, aria-describedby
ile ilerleme durumu ve yükleme bölgesi arasındaki ilişkiyi belirtin.
<main id="loading-zone" aria-busy="true">
…
<progress aria-describedby="loading-zone"></progress>
</main>
JavaScript'de, görevin başında aria-busy
'ü true
'e, bittikten sonra false
'e getirin.
Aria özelliği eklemeleri
Bir <progress>
öğesinin örtülü rolü progressbar
olsa da, bu örtülü role sahip olmayan tarayıcılar için bunu açıkça belirttim. Ayrıca, öğeyi bilinmeyen bir duruma açıkça yerleştirmek için indeterminate
özelliğini de ekledim. Bu, öğenin value
değerinin ayarlanmadığını gözlemlemekten daha net bir durumdur.
<label>
Loading
<progress
indeterminate
role="progressbar"
aria-describedby="loading-zone"
tabindex="-1"
>unknown</progress>
</label>
İlerleme öğesini JavaScript'den odaklanılabilir hale getirmek için tabindex="-1"
değerini kullanın. İlerleme değiştikçe ilerleme durumuna odaklanmak, kullanıcıya güncellenmiş ilerlemenin ne kadar ilerlediğini bildireceği için ekran okuyucu teknolojisi açısından önemlidir.
Stiller
İlerleme öğesi, stillendirme açısından biraz karmaşıktır. Yerleşik HTML öğelerinin seçilmesi zor olabilen özel gizli bölümleri vardır ve genellikle yalnızca sınırlı sayıda özellik ayarlanır.
Düzen
Düzen stilleri, ilerleme öğesinin boyutunda ve etiket konumunda bir miktar esneklik sağlamak amacıyla tasarlanmıştır. Yararlı ancak gerekli olmayan ek bir görsel ipucu olabilecek özel bir tamamlama durumu eklenir.
<progress>
Düzen
İlerleme öğesinin genişliği, tasarımda gereken alanla birlikte küçülebileceği ve büyüyebileceği için değiştirilmez. Yerleşik stiller, appearance
ve border
değerleri none
olarak ayarlanarak kaldırılır. Bu, her tarayıcıda öğe için kendi stilleri olduğundan öğenin tarayıcılar arasında normalleştirilebilmesi için yapılır.
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österimi kullandığından border-radius
her zaman yuvarlanır. 1000px
değerine eş değer. Ayarlayıp unutabileceğim kadar büyük bir değer kullanmak istediğim için bunu kullanmayı tercih ediyorum (ayrıca 1000px
'ten daha kısa yazılıyor). Gerekirse daha da büyütmek de kolaydır: 3'ü 4'e değiştirdiğinizde 1e4px
, 10000px
ile eşdeğer olur.
overflow: hidden
kullanılıyor ve tartışmalı bir stil. Bu, border-radius
değerlerini parçaya ve parça doldurma öğelerine aktarmak gerekmemesi gibi bazı şeyleri kolaylaştırdı ancak ilerlemenin hiçbir alt öğesinin öğenin dışında bulunamayacağı anlamına da geliyordu. Bu özel ilerleme öğesindeki başka bir iterasyon, overflow: hidden
olmadan da yapılabilir ve animasyonlar ya da daha iyi tamamlanma durumları için bazı fırsatlar sunabilir.
İşlem tamamlandı
CSS seçiciler, buradaki işin zor kısmını, maksimum değeri değerle karşılaştırarak yapar ve eşleşirse ilerleme tamamlanır. İşlem tamamlandığında, bir sözde öğe oluşturulur ve ilerleme öğesinin sonuna eklenir. Bu öğe, işlemin tamamlandığına dair güzel bir ek 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 getirir ve yalnızca bir CSS özelliğiyle açık ve koyu modlara uyum sağlar. Tarayıcıya özgü bazı özel seçiciler, bunu temel alabilir.
Açık ve koyu tarayıcı stilleri
Sitenizde koyu ve açık renkli uyarlanabilir <progress>
öğesini etkinleştirmek için color-scheme
yeterlidir.
progress {
color-scheme: light dark;
}
Tek tesis ilerleme dolgu rengi
Bir <progress>
öğesinin tonunu ayarlamak için accent-color
işlevini kullanın.
progress {
accent-color: rebeccapurple;
}
Parçanın arka plan renginin, accent-color
değerine bağlı olarak açıktan koyuya değiştiğini fark edin. Tarayıcı, doğru kontrastı sağlıyor: Oldukça şık.
Tamamen özel açık ve koyu renkler
<progress>
öğesinde biri parça rengi, diğeri parça ilerleme rengi olmak üzere iki özel özellik ayarlayın. 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, programatik olarak odaklanabilmesi için öğeye negatif sekme dizini vermiştik. Daha akıllı odak halkası stilini etkinleştirmek için odağı özelleştirmek üzere :focus-visible
simgesini kullanın. Bu durumda, fare tıklaması ve odaklanma odak halkasını göstermez ancak klavye tıklamaları gösterir. Bu konuyu daha ayrıntılı olarak ele alan YouTube videosunu incelemenizi öneririz.
progress:focus-visible {
outline-color: var(--_progress);
outline-offset: 5px;
}
Tarayıcılarda özel stiller
<progress>
öğesinin her tarayıcının gösterdiği bölümlerini seçerek stilleri özelleştirin. İlerleme öğesi tek bir etikettir, ancak sözde CSS seçicileri aracılığıyla gösterilen birkaç alt öğeden oluşur. Chrome Geliştirici Araçları, ayarı etkinleştirirseniz aşağıdaki öğeleri gösterir:
- Sayfanızı sağ tıklayın ve Öğeyi İncele'yi seçerek Geliştirici Araçları'nı açın.
- DevTools penceresinin sağ üst köşesindeki Ayarlar dişli simgesini tıklayın.
- Öğeler başlığı altında Kullanıcı aracısı gölge DOM'unu göster onay kutusunu bulup 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
öğelerini gösterir. Şimdilik, daha önce oluşturulan ve açık ve koyuya uyum sağlayan ö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 <progress>
öğesinde ::-moz-progress-bar
sözde seçicisini gösterir. Bu aynı zamanda parçanın tonunu doğrudan ayarlayamadığımız anlamına da gelir.
/* Firefox */
progress[value]::-moz-progress-bar {
background-color: var(--_progress);
}
Firefox'un accent-color
olarak ayarlanmış bir kanal rengine sahipken iOS Safari'nin açık mavi bir kanal rengine sahip olduğunu unutmayın. Koyu modda da aynıdır: Firefox'ta koyu bir parça vardır ancak belirlediğimiz özel renk değil ve Webkit tabanlı tarayıcılarda çalışır.
Animasyon
Tarayıcı yerleşik sözde seçicileriyle çalışırken genellikle izin verilen CSS özelliklerinin sınırlı bir kümesiyle çalışırsınız.
Parçanın dolmasını animasyonlu olarak gösterme
İlerleme öğesinin inline-size
öğesine geçiş eklemek Chromium'da işe yarar ancak Safari'de geçerli olmaz. Firefox, ::-moz-progress-bar
özelliğinde geçiş özelliği de kullanmaz.
/* Chromium Only 😢 */
progress[value]::-webkit-progress-value {
background-color: var(--_progress);
transition: inline-size .25s ease-out;
}
:indeterminate
durumuna animasyon ekleme
Burada, animasyon oluşturmak için biraz daha yaratıcı oluyorum. Chromium için bir sözde öğe oluşturulur ve üç tarayıcıda da ileri geri animasyonlu bir degrade uygulanır.
Özel özellikler
Özel özellikler birçok şey için mükemmeldir ancak en sevdiğim özelliklerinden biri, büyülü görünen bir CSS değerine isim vermektir. Aşağıda, oldukça karmaşık 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;
}
Tarayıcıya özgü bu seçicileri bir kez daha gruplandıramayacağımız için özel özellikler de kodun DURDUR durumda kalmasına yardımcı olur.
Animasyon kareleri
Amaç, ileri geri giden sonsuz bir animasyon oluşturmaktır. Başlangıç ve bitiş ana kareleri CSS'de ayarlanır. Başlangıç noktasına tekrar tekrar dönen bir animasyon oluşturmak için yalnızca bir animasyon karesi (50%
'teki orta animasyon karesi) gerekir.
@keyframes progress-loading {
50% {
background-position: left;
}
}
Her tarayıcıyı hedefleme
Bazı tarayıcılar, <progress>
öğesinin kendisinde sözde öğe oluşturmaya veya ilerleme çubuğunun animasyonlu olmasına izin vermez. Parçanın animasyonunu sanal öğeden çok daha fazla tarayıcı desteklediğinden, temel olarak gerçek olmayan öğelerden ve animasyon çubuklarına geçiş yapıyorum.
Chromium sözde öğesi
Chromium, öğeyi kapsayacak şekilde konumla birlikte kullanılan ::after
sözde öğesine izin verir. Belirsiz özel özellikler kullanılıyor ve ileri geri animasyon çok iyi çalışıyor.
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 bir 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, sözde öğe ilerleme çubuğuna özel özellikler ve bir animasyon 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 ilgili önemli bir rol oynar. Öğeye gönderilen değeri kontrol eder ve belgede ekran okuyucular için yeterli bilginin bulunduğundan emin olur.
const state = {
val: null
}
Demoda, ilerlemeyi kontrol etmek için düğmeler sunulur. Bu düğmeler state.val
öğesini 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()
Kullanıcı arayüzü/kullanıcı deneyimi koordinasyonunun gerçekleştiği yer bu işlevdir. setProgress()
işlevi oluşturarak başlayın. state
nesnesine, ilerleme öğesine ve <main>
bölgesine erişimi olduğundan parametreye gerek yoktur.
const setProgress = () => {
}
<main>
bölgesindeki yükleme durumunu ayarlama
İlerleme durumunun tamamlanıp tamamlanmadığına bağlı olarak, ilgili <main>
öğesinin aria-busy
özelliğinde güncelleme yapılması gerekir:
const setProgress = () => {
zone.setAttribute('aria-busy', state.val < 1)
}
Yükleme miktarı 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>
değerini belirsiz olarak değiştirir.
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
İlerleme durumunun varsayılan maksimum değerini 1 olarak kullanmayı tercih ettiğim için demo artma ve eksiltme işlevleri ondalık matematik kullanır. JavaScript ve diğer diller bu konuda her zaman iyi değildir.
Aşağıda, matematik sonucunun fazlalıklarını kırpacak bir roundDecimals()
işlevi verilmiştir:
const roundDecimals = (val, places) =>
+(Math.round(val + "e+" + places) + "e-" + places)
Değeri yuvarlayın, böylece sunulması ve okunaklı olması için:
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'de üç 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
}
İlerlemeye odaklanma
Değerler güncellendikten sonra, göreceli kullanıcılar ilerlemedeki 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 ne yapardınız? 🙂
Tekrar şansım olsaydı kesinlikle birkaç değişiklik yapmak isterdim. Mevcut bileşeni temizlemek ve <progress>
öğesinin sözde sınıf stili sınırlamaları olmadan bir bileşen oluşturmaya çalışmak için yer olduğunu düşünüyorum. Bu konuyu incelemeye değer.
Gelin, yaklaşımlarımızı çeşitlendirelim ve web'de içerik geliştirmenin tüm yollarını öğrenelim.
Bir demo oluşturun, bağlantılarını bana tweetleyin. Ardından, aşağıdaki topluluk remiksleri bölümüne ekleyeceğim.