Элемент <progress> семантически представляет ход выполнения задачи, например скачивания или загрузки информации или завершения части многоэтапного процесса. Использование нативного элемента улучшает доступность, поскольку программы чтения с экрана имеют неявный role="progressbar" и могут озвучивать значения.
В этом руководстве показано, как реализовать горизонтальный индикатор выполнения с настроенными стилями.
Индикатор выполнения или кольцо прогресса?
- Если места мало или предпочтительно квадратное соотношение сторон, используйте круговой индикатор выполнения (кольцо прогресса): Кольцо прогресса.
- Для большинства сценариев с неопределенным прогрессом предпочтительнее использовать спиннеры (Индикатор загрузки). Используйте неопределенные индикаторы выполнения, когда неопределенное состояние является временным и вскоре будет заменено определенным индикатором выполнения (например, ожидание метаданных о загрузке, прежде чем можно будет показать процент выполнения).
Markup
- Используйте нативный элемент
<progress>. Он обеспечивает встроенные специальные возможности и согласованное поведение платформы. - Используйте свойство
max, если вам нужна шкала, отличная от стандартной (0–1). - Чтобы задать определенное значение прогресса, используйте атрибут
value. Опуститеvalueдля неопределенного состояния (например, до начала более конкретной обратной связи). - Чтобы связать элемент индикатора выполнения с ярлыком, используйте
<label for="...">,aria-labelledbyилиaria-label.
Какой тип настройки вам нужен?
Для ограниченного стиля достаточно следующих свойств:
accent-color, чтобы изменить цвет индикатора выполнения.width/inline-size– изменить ширину индикатора выполнения.height/block-sizeприменяется непоследовательно – сначала протестируйтеwriting-mode: vertical-lrдля вертикальных полос.- Эффекты, которые применяются после отрисовки:
opacity,filter,clip-path, маски, преобразования,box-shadowи т. д.
Если вам достаточно ограниченного набора стилей, пропустите следующий раздел.
ВНИМАНИЕ! Некоторые свойства (например, border-radius, background, border) отключают стиль индикатора выполнения по умолчанию без уведомления. Если вам нужен стиль интерфейса, выходящий за рамки указанных выше свойств, необходимо реализовать полностью собственный стиль, как описано в следующем разделе. НЕ ПРИМЕНЯЙТЕ более обширное форматирование "на всякий случай".
Полностью настраиваемый стиль
1. Базовая настройка
- ОБЯЗАТЕЛЬНО. Используйте
appearance: none, чтобы включить собственный стиль. - Сбросить границы UA с помощью
border: 0 solid - Чтобы обрезать активную полосу по радиусу границы элемента, используйте
overflow: clipИЛИ примените к полосе то же значениеborder-radius. НЕ используйтеborder-radius: inheritна панели, так как это зависит от конкретной структуры элементов в Shadow DOM.
progress {
/* Reset default browser styles */
appearance: none;
border: 0 solid;
/* Clip bar to element’s border-radius */
overflow: clip;
}
2. Стилизация
- Задайте стиль дорожки в самом элементе
progress. - Используйте псевдоэлемент, предназначенный для нужного браузера, чтобы настроить индикатор выполнения:
::-webkit-progress-valueдля WebKit/Blink и::-moz-progress-barдля Firefox. - ОБЯЗАТЕЛЬНО. Не группируйте псевдоэлементы
-webkit-и-moz-в одном правиле. Правило будет считаться недействительным и будет игнорироваться. Селекторы:is()и:where()в этом случае не помогут, поскольку они не поддерживают псевдоэлементы. - Каждый псевдоэлемент, предназначенный для браузера, должен появляться ровно один раз. Настройки, зависящие от состояния (например, неопределенный размер сегмента и анимация), должны передаваться через дополнительные параметры, заданные в самом элементе
progress. - Необязательно: настройте переход
inline-sizeдля заливки, чтобы изменения значений анимировались, а не происходили скачкообразно. Firefox определяет размер заливки в макете и игнорирует его, что не приводит к проблемам.
progress {
--progress-bar-radius: 1e5px;
border-radius: var(--progress-bar-radius);
/* Apply color for custom progress track (background) */
background: var(--progress-bar-track, var(--color-neutral-90));
/* Subtle depth on the empty part of the track */
box-shadow: inset 0 1px 2px rgb(0 0 0 / 0.1);
}
/* Let <progress> styling show through */
progress::-webkit-progress-bar {
background: transparent;
}
/* Webkit, Chrome */
progress::-webkit-progress-value {
background: var(--progress-bar-fill, var(--accent-color));
border-radius: var(--progress-bar-radius);
transition: inline-size 0.3s;
}
/* Firefox */
progress::-moz-progress-bar {
background: var(--progress-bar-fill, var(--accent-color));
border-radius: var(--progress-bar-radius);
transition: inline-size 0.3s;
}
3. Стилизация неопределенного состояния
Добавьте специальную анимацию для неопределенного состояния. Превратите псевдоэлемент заполнения в короткий сегмент и перемещайте его по дорожке.
- Стилизуйте саму заливку. НЕ воссоздавайте ее в качестве фона для
progress. - Неопределенное заполнение существует только за счет анимации: ключевые кадры задают его длину с помощью реального
inline-size(это превосходит встроенныйinline-sizeUA Chromium) и перемещают его с помощьюtranslate. НЕ используйтеscaleдля длины, так как это искажает узор заливки. - Проценты
translateрассчитываются относительно собственной ширины заливки, поэтому указывайте позиции в единицах дорожки: сделайтеprogressконтейнером встроенного размера и используйтеcqiв ключевых кадрах. Добавьтеmargin-right: autoвfrom, to, чтобы Chromium размещал заливку слева и при письме справа налево. - Для перемещения заливки используйте преобразования, а не поля.
- Преобразования сохраняют анимацию в компоновщике (если только
inline-sizeтакже не анимируется). - Поля в RTL-языках могут отображаться некорректно по двум причинам:
- Firefox позиционирует неопределенное заполнение, используя только физическое левое поле, поэтому
margin-inline-startне влияет на RTL, и заполнение никогда не перемещается. - В Chromium и WebKit, которые размещают заливку как обычный блок, как только поле выталкивает заливку за конец дорожки, поля в сумме превышают дорожку. Стандартный CSS решает эту проблему, игнорируя
margin-leftв RTL, поэтому сегмент переходит к краю, а не соскальзывает с него. translateприменяется после макета, поэтому ни одна из проблем не возникает.
- Преобразования сохраняют анимацию в компоновщике (если только
- Чтобы отразить движение в RTL (как это делает нативная панель Chrome), измените анимацию в
:dir(rtl):
progress:dir(rtl) {
--progress-bar-indeterminate-animation: progress-bar-indeterminate var(--progress-bar-indeterminate-animation-duration) infinite linear reverse;
}
- Определите общедоступные свойства
--progress-bar-indeterminate-*вprogress(их название уже ограничивает их областью видимости состояния), чтобы потребители могли переопределять их, не зная о:indeterminate. - Чтобы изменять длину сегмента (например, передний край уходит вперед, а задний его догоняет), задайте для
--progress-bar-indeterminate-animationдве параллельные анимации: одну, ключевые кадры которой анимируютtranslateвcqi(положение), и другую, ключевые кадры которой анимируютinline-size(длину). Таким образом, у каждой анимации будут свои ключевые кадры и замедление. НЕ пытайтесь задать форму для обоих краев в одном списке ключевых кадров. Значениеanimation-timing-functionдля каждого ключевого кадра применяется ко всем свойствам в этом кадре. --progress-bar-animationприменяется в обоих состояниях и может использоваться для таких эффектов, как мерцание.revert-ruleиспользуется для переопределения только в том случае, если он задан, чтобы максимизировать компонуемость.- Не отключайте анимацию неопределенного состояния (в Chromium
animation: noneоставляет заполнение нулевой ширины). Если вы хотите уменьшить движение, замедлите его.
progress {
/* Lets the fill position itself in track units (cqi) */
container-type: inline-size;
/* Segment length relative to the track */
--progress-bar-indeterminate-size: 30%;
--progress-bar-indeterminate-animation-duration: 1.5s;
/* Respect prefers-reduced-motion */
@media (prefers-reduced-motion: reduce) {
--progress-bar-indeterminate-animation-duration: 10s;
}
}
progress:indeterminate {
--progress-bar-animation: var(
--progress-bar-indeterminate-animation,
progress-bar-indeterminate var(--progress-bar-indeterminate-animation-duration) infinite linear
);
}
/* Add to the existing pseudo-element rules */
progress::-webkit-progress-value {
animation: var(--progress-bar-animation, revert-rule);
}
progress::-moz-progress-bar {
animation: var(--progress-bar-animation, revert-rule);
}
/* Physical: left to right regardless of direction (reverse under :dir(rtl) to mirror). */
@keyframes progress-bar-indeterminate {
from, to {
inline-size: var(--progress-bar-indeterminate-size);
/* Pin to the physical left; Chromium would otherwise lay the fill out at the inline start */
margin-right: auto;
}
from { translate: -100%; } /* Own width: fully outside the left edge */
to { translate: 100cqi; } /* Track width: fully outside the right edge */
}
Дополнительные соображения по поводу доступности
Помимо перечисленных выше рекомендаций, соблюдайте следующие правила:
- Сообщайте о завершении, не переключая фокус. Не устанавливайте
tabindexи не вызывайте.focus()для<progress>, так как этот элемент не является интерактивным и перемещение фокуса на него мешает пользователям, которые работают с клавиатурой. Чтобы сообщить о завершении фоновой задачи, обновите элемент статуса (role="status"илиaria-live="polite"). - Не добавляйте резервный текст в тег
<progress>. Современные браузеры игнорируют текст в теге<progress>, и он не используется технологиями специальных возможностей. - Не используйте
aria-busy+aria-describedbyдля неразмеченного общего элемента<div>. Программы чтения с экрана не всегда поддерживаютaria-busy, а технологии специальных возможностей игнорируютaria-describedbyв безымянном элементе<div>без роли. Если контент региона не готов во время загрузки, скройте его с помощьюhiddenилиaria-hidden="true". - РЕКОМЕНДУЕТСЯ обеспечить достаточный контраст между индикатором выполнения и дорожкой при добавлении собственных стилей.
- Рассмотрите альтернативные способы представления неопределенного состояния. Анимация индикатора выполнения, отображаемая параллельно с другим контентом, может отвлекать некоторых пользователей.
Резервные стратегии
Резервные варианты и поддержка свойства accent-color в браузерах
Свойство accent-color – это прогрессивное улучшение.
Браузеры, которые не поддерживают это свойство, будут игнорировать его и использовать цвета интерфейса по умолчанию.
Если accent-color не поддерживается, а вам нужно настроить индикатор выполнения, используйте метод собственного стиля.
Резервные объявления и поддержка браузеров для revert-rule
Если revert-rule не поддерживается, animation: var(--progress-bar-animation, revert-rule) возвращается к animation-name: revert-rule с длительностью 0s, когда --progress-bar-animation не задано. Это безвредная пустая операция, если @keyframes revert-rule не существует.