İlerleme halkası

İlerleme halkası (veya dairesel ilerleme çubuğu), bir görevin durumu hakkında görsel geri bildirim sağlar. Doğrusal ilerleme çubuğunun aksine, dairesel şekli kontrol panelleri, kart bileşenleri veya alanın kısıtlı olduğu her yer için idealdir.

Bu kılavuzda, ilerleme halkası şu şekilde uygulanır:

  • Bileşenin ekran okuyucular ve klavye kullanıcıları tarafından hemen erişilebilir olmasını sağlamak için yerel <progress> öğesini semantik temel olarak kullanma.
  • Bileşeni conic-gradient() ve mask-image ile şekillendirerek SVG yolu manipülasyonunun karmaşıklığı olmadan tamamen duyarlı ve temalandırılabilir bir halka elde edebilirsiniz.
  • İlerleme dolgusunun sorunsuz, GPU hızlandırmalı geçişlerini etkinleştirmek için CSS özel özellikleri ve @property kullanılır.

Bu yaklaşım, ARIA yerine semantik <progress> öğesini kullandığı ve mevcut düzen, tasarım sistemleri ve tipografiyle daha kolay entegre olduğu için yalnızca SVG çözümlerine tercih edilir.

Belirsiz yükleme durumlarını yönetmek için Yükleme döner simgesi bölümüne bakın.

Uygulama

1. Brüt kar

Hem görsel halkayı hem de isteğe bağlı merkez içeriği tutmak için bir sarmalayıcı kullanın. <progress> öğesi, anlamsal doğruluk kaynağı olmaya devam eder. Yerel ilerleme çubuğunu görsel olarak gizlerken erişilebilir durumda tutmak için bir yardımcı sınıf kullanın.

<div class="ring-wrapper">
  <progress value="75" max="100" aria-label="Task progress" class="progress-ring"></progress>
  <!-- Optional: Content to display in the center -->
  <div class="ring-content">
    75%
  </div>
</div>

2. Stiller

Yerel kullanıcı arayüzünü gizleme

<progress> öğesini ilerleme halkası olarak biçimlendirmek için önce ilerleme çubuklarının varsayılan tarayıcı stilini gizleyin.

/* Hide native bars */
progress.loading-spinner:indeterminate::-webkit-progress-bar {
  display: none;
  background: none;
}
progress.loading-spinner:indeterminate::-webkit-progress-value {
  display: none;
  background: none;
}
progress.loading-spinner:indeterminate::-moz-progress-bar {
  display: none;
  background: none;
}
progress.loading-spinner:indeterminate::slider-fill {
  display: none;
  background: none;
}

Kapsayıcı ve halka

Sarmalayıcı, konumlandırma bağlamını sağlar. <progress> öğesi, görsel gradyanı işler.

.progress-ring-wrapper {
  position: relative;
  display: grid;
  place-items: center;
}

progress.progress-ring {
  --size: 150px;
  --thickness: 16px;
  --track-color: #f1f5f9;
  --fill-color: #3b82f6;
  --value: attr(value type(<number>));
  width: var(--size);
  height: var(--size);

  transition: --value 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  border-radius: 50%;

  background: conic-gradient(
    var(--fill-color) calc(var(--value) * 1%),
    var(--track-color) 0
  );

  /* MANDATORY: Clip the background to the border-area. */
  background-clip: border-area;
  border: var(--thickness) solid transparent;
  background-origin: border-box;
}

.progress-ring-content {
  /* Positioned in the center of the wrapper */
  position: absolute;
}

Yuvarlak uç kapakları oluşturmak için radial-gradient da kullanabilirsiniz.

@property ile sorunsuz geçişleri etkinleştirme

Değer değiştiğinde ilerleme halkasını sorunsuz bir şekilde canlandırmak için --value değerini sayısal bir özel nitelik olarak kaydedin.

Harekete duyarlı kullanıcılar, değerler arasındaki geçişi kafa karıştırıcı bulabilir. Varsayılan olarak 0 saniyelik (anında) bir süreye sahip olarak ve tercihi olmayan kullanıcılar için daha uzun bir süre ayarlayarak prefers-reduced-motion medya sorgusuna uyun.

@property --value {
  syntax: '<number>';
  inherits: true;
  initial-value: 0;
}

progress.progress-ring {
  transition: --value 0s ease-in-out;
  @media (prefers-reduced-motion: no-preference) {
    transition-duration: 0.4s;
  }
}

3. İlerleme Güncellemeleri

Değer her değiştiğinde <progress> öğesindeki value özelliğini ve .progress-ring-content öğesinin metin içeriğini (yüzde gösteriliyorsa) güncelleyin.

4. İsteğe Bağlı Başarı Durumu

Görev tamamlandığında halkanın görünümünü otomatik olarak güncellemek (ör. rengi yeşil olarak değiştirmek) için CSS özellik seçicisini kullanabilirsiniz.

/* Change the fill color to green when the progress reaches 100% */
progress.progress-ring[value="100"] {
  --fill-color: #10b981;
}

Yedek stratejiler

<progress> öğesinin içine yedek değer eklemeyin. Yardımcı teknolojiler tarafından kullanılmaz ve tüm modern tarayıcılar tarafından yoksayılır.

Yedek animasyon

@property desteklenmiyorsa halka, sorunsuz bir şekilde geçiş yapmak yerine anında yeni değere atlar. Çoğu durumda bu sorun teşkil etmez ve herhangi bir işlevi bozmaz.

Geçiş kesinlikle gerekliyse @property desteğini kontrol edebilir ve eski tarayıcılarda --value değerini interpolasyonla hesaplamak için requestAnimationFrame() döngüsü kullanabilirsiniz.

background-clip: border-area özelliğini henüz desteklemeyen tarayıcılar için <progress> öğesinin ortasını boşaltmak üzere mask-image özelliğini kullanın.

@supports not (background-clip: border-area) {
  mask-image: radial-gradient(
    transparent calc(50% - var(--thickness)),
    black calc(50% - var(--thickness) + 0.5px)
  );
  border: 0;
}

Herhangi bir özellik için attr() CSS işlevini desteklemeyen tarayıcılarda, value özelliğini --value özel nitelik ile otomatik olarak senkronize etmek için MutationObserver kullanın.

if (!CSS.supports("width: attr(value type(<number>))")) {
  const observer = new MutationObserver(() => {
    progress.style.setProperty("--value", progress.getAttribute("value"));
  });
  observer.observe(progress, {
    attributes: true,
    attributeFilter: ["value"],
  });
}