<progress>
öğesiyle uyarlanabilir ve erişilebilir bir yükleme çubuğunun nasıl oluşturulacağına dair temel bilgiler.
Bu yayında, <progress>
öğesiyle uyarlanabilir ve erişilebilir bir yükleme çubuğunun nasıl oluşturulacağıyla ilgili düşünceleri 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 tamamlanma hakkında görsel ve sesli geri bildirim sağlar. Bu görsel geri bildirim; formda ilerleme, bilgi indirme veya yükleme, hatta ilerleme miktarının bilinmediği halde işin hâlâ devam ettiğini gösterme gibi senaryolar için değerlidir.
Bu GUI Yarışması, erişilebilirlik konusunda biraz çaba sarf etmek için mevcut HTML <progress>
öğesiyle çalıştı. Renkler ve düzenler, bileşeni modernleştirmek ve tasarım sistemlerine daha iyi sığdırmak için yerleşik öğenin özelleştirme sınırlarını zorlar.
Markup
<progress>
öğesini bir <label>
içine sarmayı tercih ettim. Böylece açık ilişki özelliklerini atlayarak örtülü ilişkiye öncelik verebilirim.
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 belirsiz olur.
max
özelliği varsayılan olarak 1 değerine ayarlanır. Dolayısıyla ilerleme durumu 0 ile 1 arasındadır. Örneğin, max
değeri 100 olarak ayarlanırsa aralık 0-100 olarak ayarlanır. 0 ve 1 sınırları içinde kalmayı seçtim, ilerleme
değerlerini %0,5 veya %50’ye çevirdim.
Etiket sarmalama ilerleme durumu
Örtülü ilişkide, ilerleme öğesi şunun gibi bir etiketle sarmalanır:
<label>Loading progress<progress></progress></label>
Demomda, yalnızca ekran okuyucular için etiket eklemeyi seçtim.
Bu işlem, etiket metnini bir <span>
içine sarmalayarak ve etkili şekilde ekran dışında kalması için ona bazı stiller uygulanarak 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;
}
Alan, yükleme ilerleme durumundan etkileniyor
Sağlıklı bir görüşe sahipseniz, bir ilerleme göstergesini ilgili öğeler ve sayfa alanlarıyla ilişkilendirmek kolay olabilir, ancak görme engelli kullanıcılar için bu durum pek net değildir. Yükleme tamamlandığında değişecek olan en üstteki öğeye aria-busy
özelliğini atayarak bunu 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'ten, görevin başında aria-busy
öğesini true
, tamamlandığında da false
konumuna getirin.
Aria özelliği eklemeleri
<progress>
öğesinin örtülü rolü progressbar
olsa da bunu, bu dolaylı role sahip olmayan tarayıcılar için açık hale getirdim. Öğeyi açıkça bilinmeyen bir duruma sokmak için indeterminate
özelliğini de ekledim. Bu, öğenin value
ayarlanmamış olduğunu gözlemlemekten daha anlaşılırdır.
<label>
Loading
<progress
indeterminate
role="progressbar"
aria-describedby="loading-zone"
tabindex="-1"
>unknown</progress>
</label>
İlerleme öğesine JavaScript'ten odaklanılabilir hale getirmek için tabindex="-1"
kullanın. Bu, ekran okuyucu teknolojisi için önemlidir. Çünkü ilerleme durumu değiştikçe ilerlemeye odaklanmak, güncellenen ilerlemenin ne kadar ilerlediğini kullanıcıya bildirecektir.
Stiller
İlerleme öğesi, stil açısından biraz karmaşıktır. Yerleşik HTML öğelerinin seçilmesi zor olabilen özel gizli bölümleri vardır ve genellikle ayarlanacak sınırlı bir özellik grubu sunulur.
Düzen
Düzen stilleri, ilerleme öğesinin boyutunda ve etiket konumunda biraz esneklik sağlamak amacıyla tasarlanmıştır. Yararlı ama zorunlu olmayan bir ek görsel işaret olabilecek özel bir tamamlanma durumu eklenir.
<progress>
Düzeni
İlerleme öğesinin genişliğine dokunulmaz, böylece tasarımda gereken alanla birlikte küçülebilir ve büyüyebilir. appearance
ve border
, none
olarak ayarlanarak yerleşik stiller sadeleştirilir. Bu, her tarayıcının kendi öğesi 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 üzere bilimsel sayı gösterimini kullanır. Böylece border-radius
her zaman yuvarlanır. 1000px
işlevine eş değerdir. Bu yöntemi kullanmayı tercih ediyorum, çünkü bu değeri ayarlayıp unutabileceğim (ve yazması 1000px
değerinden daha kısa) kadar büyük bir değer olacak. Gerekirse değeri daha da büyütmek de çok kolay: 3 değerini 4 olarak değiştirmeniz yeterlidir. Bu durumda 1e4px
, 10000px
ile eşdeğerdir.
overflow: hidden
kullanılıyor ve tartışmalı bir tarz. border-radius
değerlerini kanala aktarma ve dolgu öğelerini izleme gibi birkaç işi kolaylaştırdı. Aynı zamanda, ilerlemenin hiçbir alt öğesinin öğenin dışında yaşayamayacağı anlamına da geliyordu. Bu özel ilerleme öğesinde bir başka yineleme overflow: hidden
olmadan yapılabilir ve bu da, animasyonlar veya daha iyi tamamlanma durumları için bazı fırsatlar sağlayabilir.
İşlem tamamlandı
Bu noktada CSS seçiciler, maksimum değer ile değeri karşılaştırarak işin zor kısmını yapar. Bu seçiciler eşleşiyorsa ilerleme tamamlanmış olur. İşlem tamamlandığında sözde öğe oluşturulur ve ilerleme öğesinin sonuna eklenir. Böylece, sonuna güzel bir ek görsel işaret sağlanır.
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 tek bir CSS özelliğiyle açık ve koyuya uyarlanabilir. Bu, tarayıcıya özgü bazı özel seçicilerle oluşturulabilir.
Açık ve koyu tarayıcı stilleri
Sitenizde koyu ve açık renkli uyarlanabilir <progress>
öğelerini etkinleştirmek için color-scheme
yeterlidir.
progress {
color-scheme: light dark;
}
Tek mülk ilerleme durumu doldurulmuş rengi
Bir <progress>
öğesinin renk tonunu ayarlamak için accent-color
öğesini kullanın.
progress {
accent-color: rebeccapurple;
}
accent-color
özelliğine bağlı olarak parkur arka plan renginin açıktan koyuya dönüştüğüne dikkat edin. Tarayıcı, uygun kontrastı sağlıyor: Oldukça düzenli.
Tamamen özel açık ve koyu renkler
<progress>
öğesinde, biri parkur rengi, diğeri de parkur ilerleme durumu rengi için olmak üzere iki özel özellik ayarlayın. prefers-color-scheme
medya sorgusunda, izleme ve izleme ilerleme durumu için yeni renk değerlerini girin.
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
Öğeye programlı bir şekilde odaklanabilmesi için negatif bir sekme dizini vermiştik. :focus-visible
kullanarak odağı özelleştirin ve daha akıllı odak halkası stilini etkinleştirin. Bu durumda, fare tıklaması ve odaklanması odak halkasını göstermez, ancak klavye tıklamalarını gösterir. Bu konuyu daha ayrıntılı bir şekilde ele alan YouTube videosunda incelemeye değer.
progress:focus-visible {
outline-color: var(--_progress);
outline-offset: 5px;
}
Tarayıcılar genelinde özel stiller
Her bir tarayıcının gösterdiği <progress>
öğesinin bölümlerini seçerek stilleri özelleştirin. İlerleme öğesi kullanımı tek bir etikettir ancak CSS sözde seçicileri aracılığıyla açığa çıkan birkaç alt öğeden oluşur. Ayarı etkinleştirirseniz Chrome Geliştirici Araçları size bu öğeleri gösterir:
- Sayfanızı sağ tıklayın ve Geliştirici Araçları'nı açmak için Öğeyi İncele'yi seçin.
- Geliştirici Araçları penceresinin sağ üst köşesindeki Ayarlar dişli simgesini tıklayın.
- Öğeler başlığı altında, Kullanıcı aracısı gölge DOM'sini 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 izin veren ::-webkit-progress-bar
ve ::-webkit-progress-value
öğelerini açığa çıkarır. Şimdilik, daha önce oluşturulan, açık ve koyuya uyum sağlayan özel özellikleri kullanarak background-color
değerini 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, <progress>
öğesinde yalnızca ::-moz-progress-bar
sözde seçiciyi gösterir. Bu aynı zamanda parçanın renk tonunu doğrudan belirleyemeyeceğimiz anlamına da gelir.
/* Firefox */
progress[value]::-moz-progress-bar {
background-color: var(--_progress);
}
Firefox'ta accent-color
olarak ayarlanmış parkur rengi, iOS Safari'de ise açık mavi renkli bir parkur rengi olduğuna dikkat edin. Koyu modda da aynısı geçerlidir: Firefox'un koyu renkli bir izi vardır
ancak bizim belirlediğimiz özel renge sahip değildir ve Webkit tabanlı tarayıcılarda çalışır.
Animasyonlar
Tarayıcının yerleşik sözde seçicileriyle çalışırken, bu genellikle sınırlı bir izin verilen CSS özelliği grubuyla yapılır.
Parçanın doldurulmasını gösteren animasyon
İlerleme öğesinin inline-size
öğesine geçiş eklemek Chromium'da işe yarar ancak Safari'de işe yaramaz. Firefox, ::-moz-progress-bar
öğesinde geçiş özelliği de kullanmaz.
/* Chromium Only 😢 */
progress[value]::-webkit-progress-value {
background-color: var(--_progress);
transition: inline-size .25s ease-out;
}
:indeterminate
durumu canlandırılıyor
Burada, bir animasyon sağlayabilmek için biraz daha yaratıcı olduğum oluyor. Chromium için sözde bir öğe oluşturulur ve üç tarayıcı için de ileri geri animasyonlu bir renk geçişi uygulanır.
Özel özellikler
Özel özellikler birçok amaçla kullanılabilir, ancak favorilerimden biri sihirli görünen bir CSS değerine ad vermek. Aşağıda, oldukça
karmaşık bir
linear-gradient
var, ancak güzel bir ad var. Özelliğin 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 birlikte gruplandıramadığımızdan, özel özellikler kodun DÜŞÜK kalmasına da yardımcı olur.
Animasyon kareleri
Amacınız, ileri geri hareket eden sonsuz bir animasyondur. Başlangıç ve bitiş animasyon kareleri
CSS'de ayarlanır. Başlangıcına tekrar tekrar geri dönen bir animasyon oluşturmak için yalnızca bir animasyon karesi (50%
konumundaki orta animasyon karesi) gerekir!
@keyframes progress-loading {
50% {
background-position: left;
}
}
Her bir tarayıcıyı hedefleme
Her tarayıcı, <progress>
öğesinin kendisinde sözde öğelerin oluşturulmasına veya ilerleme çubuğuna animasyon uygulanmasına izin vermez. Parça animasyonunu, sahte öğeden çok tarayıcı destekler; bu yüzden, yapay öğelerden temel olarak ve animasyon çubuklarına yükseltme yapıyorum.
Chromium sözde öğe
Chromium, sözde öğeye izin verir: ::after
, öğeyi örtecek bir konumla kullanılır. Belirsiz özel özellikler kullanılır ve ileri-geri animasyon ç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 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, özel özellikler ve bir animasyon da sözde öğe ilerleme çubuğuna 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>
öğesinde önemli bir rol oynar. Öğeye gönderilen değeri kontrol eder ve ekran okuyucular için belgede yeterli bilginin bulunmasını sağlar.
const state = {
val: null
}
Demoda, ilerleme durumunu kontrol etmek için düğmeler bulunur. Bu düğmeler state.val
öğesini günceller ve daha sonra,
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şlevde kullanıcı arayüzü/kullanıcı deneyimi düzenlenir. setProgress()
işlevi oluşturarak başlayın. state
nesnesine, ilerleme öğesine ve <main>
alt bölgesine erişimi olduğundan parametreye gerek yoktur.
const setProgress = () => {
}
<main>
alt bölgesinde yükleme durumunu ayarlama
İlerlemenin tamamlanıp tamamlanmadığına bağlı olarak, ilgili <main>
öğesinin aria-busy
özelliğinde güncellenmesi gerekir:
const setProgress = () => {
zone.setAttribute('aria-busy', state.val < 1)
}
Yükleme tutarı bilinmiyorsa özellikleri temizle
Değer bilinmiyorsa veya ayarlanmamışsa bu kullanımda null
, value
ve aria-valuenow
özelliklerini kaldırın. Bu işlem, <progress>
öğesini belirsiz hale getirecek.
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 sayılarla ilgili matematik sorunlarını düzeltme
Varsayılan ilerleme durumu (maksimum 1) olarak kalmayı seçtiğim için demo artış ve azaltma işlevleri ondalık matematiği kullanır. JavaScript ve diğer diller bu konuda her zaman mükemmel değildir.
Matematik sonucundaki fazlalığı kırpacak bir roundDecimals()
fonksiyonu aşağıda verilmiştir:
const roundDecimals = (val, places) =>
+(Math.round(val + "e+" + places) + "e-" + places)
Değeri sunulabilmesi ve okunabilmesi için 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 ayarlayın
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
}
İlerlemeye odaklanma
Değerler güncellendiğinde, gören kullanıcılar ilerlemenin değiştiğini görür, ancak ekran okuyucu kullanıcılarına henüz değişiklik duyurusu verilmez. <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ç
Nasıl yaptığımı artık bildiğine göre siz de nasıl yapardınız? 🙂
Bir şans daha verilirse kesinlikle yapmak istediğim birkaç değişiklik var. Bence mevcut bileşeni temizlemeniz ve <progress>
öğesinin sözde sınıf stil sınırlamaları olmadan bir tane derlemeyi denemeniz gerekiyor. Keşfetmeye değer!
Yaklaşımlarımızı çeşitlendirelim ve web'de geliştirme yapmanın tüm yollarını öğrenelim.
Bir demo oluşturun, bana tweet atın bağlantıları, aşağıdaki topluluk remiksleri bölümüne ekleyeceğim.