درحال بار کردن گردونه

وقتی مدت زمان دقیق مشخص نیست، نشانگر بارگیری (یا نشانگر فعالیت) به کاربران اطلاع می‌دهد که فرایندی درحال انجام است. برخلاف حلقه پیشرفت، نشانگر چرخان «نامشخص» است و معمولاً از پویانمایی برای نشان دادن فعالیت استفاده می‌کند.

این راهنما یک اسپینر را با انجام موارد زیر پیاده‌سازی می‌کند:

  • استفاده از عنصر بومی <progress> به‌عنوان پایه معنایی. با حذف کردن مشخصه value، مرورگر آن را به‌عنوان نوار پیشرفت نامشخص درنظر می‌گیرد و از اعلام صحیح آن توسط فناوری‌های کمکی اطمینان حاصل می‌کند.
  • سبک‌دهی به مؤلفه با conic-gradient() برای ایجاد یک «مسیر» دیداری و background-clip: border-area برای توخالی کردن مرکز به شکل یک حلقه.
  • متحرک‌سازی کارآمد اسپینر بااستفاده از تبدیل‌های CSS و رعایت prefers-reduced-motion برای اطمینان از تجربه راحت برای همه کاربران.

برای رسیدگی به تکالیف مشخص با مدت‌زمان معلوم، حلقه پیشرفت را ببینید.

پیاده‌سازی

۱. نشانه‌گذاری

از عنصر <progress> بومی هم به‌عنوان منبع معنایی حقیقت و هم به‌عنوان مؤلفه دیداری استفاده کنید. بدون مشخصه value، به‌طور ضمنی نامشخص است.

<progress aria-label="Loading" class="loading-spinner"></progress>

۲. سبک‌ها

پنهان کردن واسط کاربر بومی

برای سبک‌دهی به عنصر <progress> به‌عنوان یک اسپینر، ابتدا سبک پیش‌فرض مرورگر را برای نوارهای پیشرفت نامشخص پنهان کنید.

/* 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;
}

حلقه و دنباله چرخان

این اسپینر از conic-gradient برای ایجاد دنباله بصری استفاده می‌کند.

@property --arc-start {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}
@property --arc-end {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}
/* Use a custom property to conditionally include the dash animation */
@property --progress-dash-animation {
  syntax: "*";
  inherits: false;
  initial-value: , progress-dash 3s ease-in-out infinite;
}

progress.loading-spinner:indeterminate {
  --_from: calc(90deg + var(--arc-start, 0deg));
  --_to: calc(90deg + var(--arc-end, 158deg));
  --size: 40px;
  --thickness: 2px;
  --spinner-color: #3b82f6;
  --track-color: #e2e5e7;
  --spinner-duration: 1.5s;
  --_used-spinner-duration: var(--spinner-duration);
  --spinner-timing: linear;

  position: relative;
  width: var(--size);
  height: var(--size);
  border-radius: 50%;
  appearance: none;

  /* Create the fading trail with dynamic angles */
  background: conic-gradient(
      from var(--_from),
      var(--spinner-color) calc(var(--_to) - var(--_from)),
      transparent 0
    )
    var(--track-color);

  @supports (background-clip: border-area) {
    background-clip: border-area;
    border: var(--thickness) solid transparent;
    background-origin: border-box;
  }

  /* ... fallback for background-clip: border-area ... */

  /* The dash animation is only included if @property is supported */
  animation:
    progress-spin var(--_used-spinner-duration) linear infinite
    var(--progress-dash-animation, );
}

@keyframes progress-spin {
  to {
    rotate: 1turn;
  }
}

@keyframes progress-dash {
  from {
    --arc-start: 0deg;
    --arc-end: 3deg;
  }
  50% {
    --arc-start: 100deg;
    --arc-end: 358deg;
  }
  to {
    --arc-start: 360deg;
    --arc-end: 363deg;
  }
}

رعایت اولویت‌های حرکتی

کاربرانی که به حرکت حساس هستند ممکن است عناصر با چرخش سریع را گیج‌کننده بدانند. همیشه به پُرسمان رسانه prefers-reduced-motion احترام بگذارید. مشخصه داخلی --_used-spinner-duration را برای لغو مقدار --spinner-duration کاربر تنظیم کنید.

@media (prefers-reduced-motion: reduce) {
  .loading-spinner {
    /* Slow down the animation significantly rather than stopping it entirely,
       so the user still knows that the process is active. */
    --_used-spinner-duration: 6s;
  }
}

راهبردهای جایگزین

اگر @property پشتیبانی شود، پویانمایی خط تیره به‌طور خودکار ازطریق initial-value ویژگی --progress-dash-animation اضافه می‌شود. در مرورگرهایی که از @property پشتیبانی نمی‌کنند، ثبت ویژگی نادیده گرفته می‌شود و پویانمایی به چرخش ساده برمی‌گردد. برای این بازگشت، به «جاوا اسکریپت» نیازی نیست.

برای مرورگرهایی که هنوز از background-clip: border-area پشتیبانی نمی‌کنند، به mask-image برگردید تا مرکز را خالی کنید.

/* Fallback: use mask-image to create the ring */
@supports not (background-clip: border-area) {
  --clip-boundary: calc(100% - var(--thickness));
  mask-image: radial-gradient(
    farthest-side,
    transparent var(--clip-boundary),
    black var(--clip-boundary)
  );
  border: 0;
}