При создании веб-сайтов и веб-приложений периодически требуется показать пользователю информацию о ходе выполнения какого-либо запроса или задачи, будь то загрузка файла, воспроизведение видео или импорт данных.
Для этого в HTML5 был введен специальный элемент <progress>
, который призван упростить эту задачу для разработчиков. Его еще называют индикатором выполнения или прогресс-баром. Достаточно часто он используется не только с точки зрения html-разметки (она простая) или указания css-свойств, но и с точки зрения динамического управления отображением процесса выполнения задачи, который основан на JavaScript-коде.
В спецификации HTML5 поле деятельности элемента progress
определено так:
Элемент progress представляет собой индикатор прогресса выполнения задачи.
То есть вы можете выбрать любую задачу, которая требует определенного времени, и показать пользователю процесс ее прохождения с помощью элемента progress
. Например, это может быть изменение времени на прохождение теста, прогресс в чтении статьи или книги по отношению к ее объему.
Краткое содержание статьи:
- Атрибуты тега <progress>
- Поддержка браузерами
- Стили CSS
- Замена элемента progress
- Примеры использования
Атрибуты тега <progress>
Для тега<progress>
в спецификации указаны такие атрибуты: max
и value
. Использование элемента progress
несколько различается в зависимости от того, какие из атрибутов в нем указаны:
- Если указан атрибут
value
, то элемент<progress>
считается определенным, или determinate (т.е. имеет точные пределы). В противном случае он считается неопределенным (indeterminate). В зависимости от наличия этого атрибута разные браузеры по-разному стилизуют прогресс-бар. - Если атрибут
max
не добавлен в тег, то допустимым диапазоном элемента<progress>
по умолчанию является от 0,0 до 1,0 включительно. - Рекомендуется всегда добавлять атрибуты
value
(текущее значение) иmax
(максимальное значение) между тегами в элемент<progress>
, чтобы информация по-прежнему была видна пользователям старых браузеров.
Возможные атрибуты тега <progress>
:
max
- максимальное значение прогресса. Значение по умолчанию - 1.0 (коэффициент, соответствующий 100% выполненной задачи).value
- текущее значение прогресса. Его значение должно быть >= 0 и <= 1 (по умолчанию, т.е. некий коэффициент, соответствующий прогрессу выполнения задачи от 0 до 100%) или значению атрибутаmax
, если он указан.
Поддержка браузерами
Вы можете убедиться в хорошей поддержке элемента <progress>
на сайте caniuse.com. Проблемы есть только в мобильных версиях Safari для iOs, Android 2.1-4.3, а также 6-9 версий Internet Explorer. То есть практически все современные браузеры поддерживают использование этого элемента.
Стили CSS
Со стилизацией все обстоит несколько сложней, т.к. все браузеры имеют свой собственный стиль для элемента <progress>
. Однако вы можете переопределить стили в CSS, используя ряд стандартных свойств и ряд псевдоэлементов с вендорными префиксами. И тут есть несколько особенностей:
- Следует отметить, что элемент
progress
по умолчанию имеет стильdisplay: inline-block
, поэтому, если вам необходимо изменить его размер в соответствии с размерами какого-либо родительского элемента, можно задать ему свойствоdisplay: block
. - Стили необходимо задавать по-разному для элементов
progress
с установленным атрибутомvalue
и без него. - Для браузеров на различных платформах (webkit или moz), правила для псевдоэлементов нужно указывать отдельно.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | progress { display: block; } /* css-правила для определенного (determinate) элемента progress с атрибутом value */ progress[value] { /* css-правила */ } progress[value]::-webkit-progress-bar { /* css-правила */ } progress[value]::-webkit-progress-value { /* css-правила */ } progress[value]::-moz-progress-bar { /* css-правила */ } /* css-правила для неопределенного (indeterminate) элемента progress без атрибута value */ progress:not([value]) { /* css-правила */ } progress:not([value])::-webkit-progress-bar { /* css-правила */ } progress:not([value])::-webkit-progress-value { /* css-правила */ } progress:not([value])::-moz-progress-bar { /* css-правила */ } |
Давайте посмотрим, как выглядит элемент progress
в вашем браузере.
В Инспекторе свойств (F12) браузера вы увидите следующие стили.
Теперь воспользуемся подсказкой, указанной выше, и стилизуем наш прогресс-бар:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <style> progress.styled { display: block; border-radius: 6px; width: 80%; height: 22px; border: 1px solid #e8c00e; } progress.styled::-webkit-progress-bar { background-color: beige; border-radius: 6px; } progress.styled::-webkit-progress-value { background-color: green; background-image: linear-gradient(green, lime); border-radius: 6px; } progress.styled::-moz-progress-bar { background-color: green; background-image: linear-gradient(green, lime); border-radius: 6px; } </style> <body> <p>Определенный (Determinate) прогресс-бар с атрибутами value="50" и max="100":</p> <progress value="50" max="100" class="styled">Determinate</progress> <p>Неопределенный (Indeterminate) прогресс-бар без атрибутов:</p> <progress class="styled">Indeterminate</progress> </body> |
Стилизация элемента progress
Стилизация элемента progress
Определенный (Determinate) прогресс-бар с атрибутами value="50" и max="100":
Неопределенный (Indeterminate) прогресс-бар без атрибутов:
Особенности стилизации <progress>
в Chrome, Safari и Firefox
Обратите внимание, что для браузеров Chrome и Safari нам нужно использовать 2 разных псевдоэлемента:
progress::-webkit-progress-value
, чтобы указать цвет индикатора выполнения;progress::-webkit-progress-bar
, чтобы указать цвет фона самого элемента<progress>
:
1 2 | progress::-webkit-progress-bar { background: #fff; } progress::-webkit-progress-value { background: green; } |
Для Firefox нужно указывать все свойства в псевдоэлементе -moz-progress-bar
.
Для того чтобы все браузеры отображали ваши стили одинаково, вы можете также добавить такие css-правила:
1 2 3 4 5 | progress { -webkit-appearance: none; -moz-appearance: none; appearance: none; } |
Для Firefox можно также записать строку -moz-orient: vertical
и получить вертикальный прогресс-бар.
Замена элемента progress
Элемент progress можно заменить набором div-ов, применяя внутри него разнообразную анимацию. Один из таких примеров вы найдете ниже.
See the Pen fancy progress bar by Sebastian Schepis (@sschepis) on CodePen.
Примеры использования элемента progress
Давайте теперь рассмотрим, как мы можем использовать элемент <progress>
на страницах, управляя им с помощью JavaScript-кода.
Неопределенный прогресс-бар для отображения процесса загрузки изображения
Загрузку изображений будем выполнять из внешнего источника - сайта unsplash.com, чтобы процесс загрузки был подольше, хотя это весьма условное утверждение при нынешней скорости Интернет-соединений даже на мобильных устройствах. Тег img
будем создавать в коде JavaScript.
Для того чтобы протестировать несколько раз загрузку и отображение ее прогресса в элементе <progress>
, создадим функцию, которая будет вызываться каждый раз при клике на кнопку "Загрузить изображение". В самой же функции будем отображать спрятанный изначально с помощью атрибута hidden
прогресс-бар с id="imgProgress"
. Изображения будем формировать с помощью ссылки, позволяющей загрузить фото с определенным id и размером с unsplash.com. Соберем несколько таких фото в массив imgArr
, указав в качестве его элементов только их id.
При клике на кнопке "Загрузить изображение" мы будем показывать прогресс-бар и сообщение о том, что идет загрузка, а по окончании загрузки (событие img.onload
) мы будем их прятать с помощью свойства hidden
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <div class="text-center"> <p><button class="button" onclick="showRandomImg()">Загрузить изображение</button></p> <progress id="imgProgress" hidden></progress> <p id="info"></p> <div id="imgHolder"></div> </div> <script> const imgArr = ['MxjSV_INz_k', 'PufbmRPIEw8', 'TFSIzT_d83U','IjJUjKQi45M', '9L4K-MH51us', '6pZ1CR95-LE', 'IgdTFo4XkPs', 'SMseye8-nCE','Y0nU6dqDCbY', 'whqZ_UvmWN8', 'h34h7Jco7Kc', 'eHOZjZEx7u8', '8esvJeVUdes']; let img = new Image(800, 1000); img.alt = "Random Unsplash.com Photo"; function showRandomImg() { imgProgress.hidden = false; info.textContent = 'Идет загрузка изображения ...'; let imgId = imgArr[Math.floor(Math.random() * imgArr.length)]; img.src = 'https://source.unsplash.com/' + imgId + '/800x1000'; imgHolder.append(img); img.onload = function() { info.textContent = 'Загрузка завершена'; imgProgress.hidden = true; } } </script> |
Нам не нужно в элементе progress
указывать атрибут value
, т.к. процес загрузки достаточно быстрый.
Попробуйте пример в действии (открыть в новой вкладке):
Увеличение значения определенного прогресс-бара
В примере ниже мы будем увеличивать значение атрибута value
определенного прогресс-бара.
1 2 3 | <progress value="0" max="200" id="my-progress-bar"></progress> <label for="my-progress-bar" id="progress-label">0%</label> <p><button class="button" onclick="increaseProgress()">Увеличить значение</button></p> |
Код JavaScript, который управляет элементом <progress>
:
1 2 3 4 5 6 7 | var myBar = document.getElementById('my-progress-bar'), labelBar = document.getElementById('progress-label'); let increaseProgress = function() { myBar.value += 10; myBar.innerHTML = myBar.value/2+'%'; myBar.value < 200 ? labelBar.innerHTML = myBar.value/2+'%': (labelBar.innerHTML = '100%. Максимум.', increaseBtn.hidden = true ); } |
Поскольку максимальное значение нашего прогресс-бара max="200", то в функции для получения процентного соотношения мы делим value
прогресс-бара на 2.
Пример "вживую":
Используем элемент <progress>
при воспроизведении видео
Как правило, в тег <video>
в HTML5 добавляют атрибут controls
для управления его воспроизведением. Однако у вас может быть видео, которое не имеет такого атрибута, а процесс воспроизведения, тем не менее, хочется отобразить. Вот тут и пригодится элемент <progress>
. Его атрибуты value
и max
будут иметь значения 0 и 100, соответственно, и это мы потом используем в скрипте.
Для всех элементов в разметке мы используем атрибут id
для простого обращения к нм в коде JavaScript:
1 2 3 | <progress value="0" max="100" id="video-progress"></progress> <label for="video-progress" id="video-label">0%</label> <p><video src="video/hamster.mp4" id="my-video" controls></video></p> |
Код JavaScript:
1 2 3 4 5 6 7 8 | let videoProgress = document.getElementById('video-progress'), labelVideo = document.getElementById('video-label'), video = document.getElementById('my-video'); video.addEventListener('timeupdate', function() { var percent = Math.floor((100 / video.duration) * video.currentTime); videoProgress.value = percent; labelVideo.textContent = percent +'%'; }); |
В JavaScript мы обрабатываем событие timeupdate
, которое постоянно запускается во время воспроизведения видео. В нем мы рассчитываем процентное значение, используя всю продолжительности видео (video.duration
) и video.currentTime
(текущее время проигрывания видео).
Давайте посмотрим забавное видео и пронаблюдаем за прогрессом его воспроизведения. Заметьте, что когда вы перемещаете ползунок воспроизведения видео, прогресс также увеличивается.
Используем элемент <progress>
для загрузки файла с помощью File API
Этот пример связан с использованием элемента<progress>
для загрузки файлов, основанной на File API. Вариант кода вы можете посмотреть в спецификации.
Разметка примера:
1 2 3 | <p><progress value="0" max="100" id="progress-file"></progress></p> <form name="fileUploadForm"><input type="file" name="file-input" id="file-input"></form> <div id="file-output"></div> |
Как вы видите, мы используем input type="file"
для загрузки txt-файла. Кстати, в js-коде мы будем это проверять.
JavaScript-код примера:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | let barFile = document.getElementById('progress-file'), fileInput = document.getElementById('file-input'), fileOutput = document.getElementById('file-output'); fileInput.onchange = startRead; function startRead() { // получаем информацию о загруженном в input файле var file = fileInput.files[0]; //проверяем, чтобы расширение файла было txt if (file.name.slice(file.name.lastIndexOf('.') + 1) != 'txt') { fileOutput.innerHTML = '<span style="color: red">Допустимо загружать только .txt-файлы!!!</span>'; return false; } else fileOutput.innerHTML = ''; if (file) { barFile.value = 0; getAsText(file); } } function getAsText(readFile) { //создаем переменную-экземпляр класса var reader = new FileReader(); // считываем файл в память в кодировке UTF-8 reader.readAsText(readFile, "UTF-8"); reader.onprogress = updateProgress; reader.onload = loaded; reader.onerror = errorHandler; } function updateProgress(evt) { //имитируем процесс загрузки файла if (evt.lengthComputable) { let i = 0; let progressId = setInterval(function() { i++; barFile.value = i * 10; if (i > 10) clearInterval(progressId); }, evt.total / 300000); } } function loaded(evt) { // Получаем данные из txt-файла var fileString = evt.target.result; //преобразуем переносы строк в txt в перенос строк в html-разметке в виде тега <br> var fileStringChange = fileString.replace(/\r*\n+/g, '<br>'); fileOutput.innerHTML = fileStringChange; } function errorHandler(evt) { if (evt.target.error.name == "NotReadableError") alert('Невозможно прочитать содержимое файла!'); } |
В приведенном коде событие progress
используется для обновления атрибута value
элемента <progress>
, а событие load
- для отображения результата чтения данных из txt-файла.
Тестируем пример:
Элемент progress для отображения прогресса чтения статьи
Еще один вариант использования прогресс-бара на странице сайта - это отображение прогресса чтения статьи. Как правило, элемент <progress>
в этом случае располагается вверху страницы, обычно до или после меню (он даже может быть добавлен непосредственно в скрипте, как в примере ниже). Когда пользователь читает текст статьи, значение атрибута value
увеличивается, и прогресс-бар медлено растет слева направо в виде сплошной полосы нужного вам цвета, который назначается в стилях.
CSS-стили для примера:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | .progress-reading { display: block; position: fixed; left: 0; top: 0; width: 100%; height: 5px; z-index: 9999; -webkit-appearance: none; -moz-appearance: none; appearance: none; border: none; background-color: transparent; } .progress-reading::-webkit-progress-bar { background-color: #fff; } .progress-reading::-webkit-progress-value{ background-color: #2a7fa3; } .progress-reading::-moz-progress-bar { background-color: #2a7fa3; } |
JavaScript-код
Код этого примера написан с использованием jQuery. Вам сначала нужно будет подключить эту библиотеку, указав к ней путь из локальной папки или с CDN, а затем использовать такой код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <script src="js/jquery.js"></script> <script> (function($) { $('body').prepend('<progress class="progress-reading" value="0"></progress>'); let winHeight = $(window).height(), docHeight = $(document).height(); let max = docHeight - winHeight; $('.progress-reading').attr('max', max); // начальное значение фтрибута value прогресс-бара var value = $(window).scrollTop(); $('.progress-reading').attr('value', value); // обновляем значение value в зависимости от положения прокрутки $(document).on('scroll', function() { value = $(window).scrollTop(); $('.progress-reading').attr('value', value); }); })( jQuery ); </script> |
Пример этого прогресс-бара вы увидите в процессе чтения статьи. Надеюсь, что читая эти строки, вы видите, как элемент <progress>
приблизился к правому краю вашего браузера.
Имитация progress bar при чтении статьи
Элемент progress
можно имитировать, использовав для этого либо разметку в виде div
, либо даже с помощью псевдоэлементов ::before
и ::after
на чистом CSS. Последний пример вы найдете ниже. В любом случае выбор способа решения задачи остается всегда за вами.
See the Pen Reading Progess Bar CSS only by Elen (@ambassador) on CodePen.
Резюме
Элемент <progress>
можно и нужно использовать для отображения процесса загрузки картинок, чтения статьи, времени решения задачи или загрузки файлов на сервер. Его можно стилизовать, используя псевдоэлементы, и управлять им из JavaScript-кода.
Информация - супер! Огромная благодарность.