Тег progress показывает, сколько работы уже сделано: загрузка файла, шаги анкеты, обработка заказа. Браузер рисует горизонтальную полосу, а доля заполнения задаётся атрибутами value и max. Закрывающий тег </progress> нужен, пропускать его нельзя.
Если задача выполняется и у неё есть конец, нужен progress. Если показывают значение в границах, например заряд батареи или заполненность диска, подходит meter: разница описана в уроке про индикаторы.
<progress value="70" max="100"></progress>
Готовая полоса, бегущая загрузка и полоса без значения.
В этой статье
- Тег progress в HTML: что это и когда нужен
- Атрибуты value и max: доля выполненной работы
- Неопределённое состояние: progress без value
- Неверные value и max: что делает браузер
- Название полосы: label, aria-label и текст внутри
- Стилизация тега progress: размер, цвет и вид
- Псевдоэлементы progress: ::-webkit-progress-bar и ::-webkit-progress-value
- Тег progress и JavaScript: value и position
- Доступность progress: роль progressbar
- Progress и форма: почему полоса не отправляется
- Атрибуты тега progress
- Вопросы про тег progress: процент рядом с полосой и замена div
- Частые ошибки с тегом progress
Тег progress в HTML: что это и когда нужен
Полоса показывает долю выполненной работы: чем больше значение, тем шире заполнение. Сам тег ничего не считает и не обновляется: значение меняет скрипт, а браузер перерисовывает полосу. Состояний у полосы два: определённое, когда доля известна, и неопределённое, когда её нет. Вычисленный display равен inline-block, поэтому полоса встаёт в строку рядом с текстом.
<label>Загрузка
<progress value="70" max="100"></progress>
</label>
Пример: progress и meter рядом
Процесс, ожидание и показание прибора.
Атрибуты value и max: доля выполненной работы
Атрибут max задаёт всю работу, а value уже сделанную. Если max не указан, он равен 1, и значение 0.3 означает 30%. Минимум всегда ноль, менять его нельзя. Доля равна value, делённому на max, её же отдаёт свойство position.
<progress value="4" max="10"></progress>
Пример: как записать долю
Четыре записи одной идеи.
Неопределённое состояние: progress без value
Если value нет, полоса считается неопределённой: браузер показывает бегущий индикатор, а position равен -1. Это подходит, когда время ожидания неизвестно. Это состояние выбирает псевдокласс :indeterminate. Атрибут value="0" неопределённости не даёт: полоса пустая, но доля известна. Переключают состояние скриптом: убирают атрибут через removeAttribute или записывают число в value.
<progress max="100"></progress>
Пример: когда полоса неопределённая
Нет значения, ноль, удаление и возврат.
Неверные value и max: что делает браузер
На неверные числа браузер не сообщает об ошибке, а подбирает значение сам. Лишнее обрезается: value больше max даёт полную полосу, а отрицательное становится нулём. Если value нельзя прочитать как число (пустая строка, abc, 20%), получится пустая полоса, а не неопределённая. Неверный max (ноль, отрицательный, не число) заменяется единицей. Проверка HTML считает такие записи ошибками, поэтому в коде пишут только допустимые числа.
<progress value="150" max="100"></progress>
Пример: что получается из неверных записей
Восемь неудачных записей и их результат.
Название полосы: label, aria-label и текст внутри
Полоса сама не говорит, что измеряется, поэтому ей нужно название: через тег label с атрибутом for, через обёртку label или атрибут aria-label. Текст между <progress> и </progress> на странице не виден и названием не служит: его писали для очень старых браузеров.
<label for="dl">Скачано</label>
<progress id="dl" value="3" max="10"></progress>
Пример: четыре способа дать название
Три рабочих способа и один нерабочий.
Стилизация тега progress: размер, цвет и вид
Размер задают обычными width и height. Цвет заполнения меняет accent-color, а color на полосу не действует. Свойство writing-mode с вертикальным значением поворачивает полосу. Есть ловушка: стоит задать background или border, и браузер отказывается от родного вида и рисует упрощённую полосу со своими цветами. Для полного контроля сначала снимают родной вид через appearance: none, об этом следующий раздел.
progress {
width: 100%;
height: 24px;
accent-color: #d94f4f;
}
Пример: размер, цвет и вид
Шесть правил для одной и той же полосы.
Псевдоэлементы progress: ::-webkit-progress-bar и ::-webkit-progress-value
После appearance: none полоса состоит из двух слоёв: трека и заполнения. Трек красят через ::-webkit-progress-bar, заполнение через ::-webkit-progress-value. В Firefox заполнение задаёт ::-moz-progress-bar. Каждый селектор пишут отдельным правилом: браузер, не знающий псевдоэлемент, отбрасывает правило целиком, а запятая объединила бы их. Скругление, градиент и transition: width на заполнении работают. В неопределённом состоянии заполнения нет, виден только трек.
progress {
appearance: none;
width: 100%;
height: 14px;
}
progress::-webkit-progress-bar {
background: #ddd;
border-radius: 7px;
}
progress::-webkit-progress-value {
background: #1c9e93;
border-radius: 7px;
}
Пример: слои полосы
Пять вариантов оформления.
Тег progress и JavaScript: value и position
Значение меняют свойством value, а долю читают через position: оно только для чтения. Если записать в value больше max, свойство вернёт зажатое число, а в атрибуте останется записанное. Присвоить max = 0 нельзя: атрибут станет единицей. Строка, которую нельзя прочитать как число, вызывает ошибку TypeError.
const bar = document.querySelector("progress");
bar.value = 80;
console.log(bar.position);
Пример: value, position и граничные случаи
Шесть операций над одной полосой.
Доступность progress: роль progressbar
У тега встроена роль progressbar, и менять её нельзя: проверка HTML отклоняет другие роли. Программа чтения получает название, текущее значение и максимум, а у неопределённой полосы числа нет. Атрибуты aria-valuenow и aria-valuemax перекрывают значения тега, а aria-valuetext добавляет словесное описание. Для региона, который загружается, можно задать aria-busy="true" и снять его после загрузки.
<label>Скачано
<progress value="3" max="10"
aria-valuetext="три из десяти"></progress>
</label>
Пример: что получает программа чтения
Роль, название и значение в пяти вариантах.
Progress и форма: почему полоса не отправляется
Полоса не относится к полям формы: она не входит в form.elements, не попадает в FormData, и у неё нет свойства form. Группа, которую создаёт тег fieldset, с disabled на неё не действует. Если число нужно отправить, его записывают в поле, например скрытое.
<form>
<input name="a" value="1">
<progress value="3" max="10"></progress>
</form>
Пример: что видит форма
Список элементов, данные, свойство и отключённая группа.
Атрибуты тега progress
Собственных атрибутов два: value и max. Остальные либо глобальные, либо здесь не работают. Легче всего перепутать min: у ползунка он есть, а у progress минимум всегда ноль.
| Атрибут | Статус | Что делает | Пример записи |
|---|---|---|---|
value | допускается | Выполненная работа: число от нуля до max | value="70" |
max | допускается | Вся работа: положительное число, по умолчанию 1 | max="100" |
id | глобальный | Идентификатор для label и скрипта | id="dl" |
class | глобальный | Класс для оформления | class="bar" |
title | глобальный | Всплывающая подсказка | title="70%" |
min | не существует | Минимум всегда ноль | min="0" |
name | не существует | Полоса не отправляется с формой | name="p" |
form | не существует | Полоса не привязывается к форме | form="f" |
disabled | не существует | Отключить полосу нельзя | disabled |
type | не существует | Вида у полосы нет | type="bar" |
role | не допускается | Роль встроена: role="none" проверка HTML отклоняет, а role="progressbar" считает лишним | role="none" |
Вопросы про тег progress: процент рядом с полосой и замена div
Рядом с полосой почти всегда хочется показать число, а самодельная полоса из блоков иногда кажется удобнее тега.
Как вывести процент текстом рядом с полосой?
Число записывают в отдельный элемент и обновляют вместе со значением полосы. Для этого подходит тег output: у него встроена роль status, и программа чтения сообщит об изменении. Обычный span тоже работает, но такого сообщения не даёт.
<progress id="bar" value="40" max="100"></progress>
<output id="pct" for="bar">40%</output>
Пример: span и output
Кнопка добавляет десять и обновляет оба элемента.
Чем progress лучше div с шириной в процентах?
У div нет роли и значения: для программы чтения это пустой блок. Роль можно добавить через role="progressbar" и три атрибута aria-value*, но их придётся обновлять вручную. Тег progress делает это сам.
<div class="track" role="progressbar"
aria-valuenow="60" aria-valuemin="0" aria-valuemax="100">
<div class="fill" style="width: 60%"></div>
</div>
Пример: тег и самодельная полоса
Три полосы, одинаковые на вид.
Частые ошибки с тегом progress
Одни ошибки связаны с неверными значениями, другие с оформлением, а незакрытый тег — одна из самых частых.
| Ошибка | Что происходит | Как исправить |
|---|---|---|
Не закрыть </progress> | Весь следующий текст оказывается внутри полосы и пропадает с экрана | Всегда писать закрывающий тег |
value больше max | Полоса полная, а лишнее значение отрезано | Следить, чтобы value не превышало max |
Писать value="20%" | Знак процента ломает число, получается пустая полоса | Записывать число без знака и задать max="100" |
Ждать неопределённости от value="0" | Полоса пустая, но определённая | Убрать атрибут value совсем |
Задать только background и ждать родной вид | Браузер рисует упрощённую полосу со своими цветами | Сначала appearance: none, затем псевдоэлементы |
Красить заполнение через color | Свойство на полосу не действует | Использовать accent-color или псевдоэлементы |
Объединять ::-webkit-progress-value и ::-moz-progress-bar запятой | Браузер отбрасывает правило целиком | Писать отдельное правило для каждого |
| Не дать полосе название | Программа чтения читает только роль и числа | Использовать label или aria-label |
Брать progress для показаний, например заряда | Роль полосы не подходит измерению | Использовать meter |