Как стиль элемента прогресса HTML5 как круг / пирог с чистым CSS
HTML5 ввел новый элемент "прогресс", который по умолчанию отображается как индикатор выполнения (термометр).
очень простой пример:
<progress max="100" value="85"></progress>
я экспериментировал с различными вариантами круга прогресса, используя javascript, а также был действительно впечатлен некоторыми чистыми подходами CSS, обсуждаемыми здесь: CSS прогресс круг
Мне интересно узнать, кто-нибудь успешно применил CSS к элементу "прогресс" для обеспечить рендеринг pie/clock/circle, а не линейный дисплей?
EDIT / ADDENDUM: элемент " метр "также очень похож на" прогресс", но обеспечивает низкий/высокий диапазон...Я упоминаю об этом больше для тех, кто может наткнуться на этот пост в будущем и хочет применить аналогичную технику к элементу HTML5 meter.
3 ответов
пытаться сделать это в чистом CSS довольно сложно, поэтому я не думаю, что это правильная техника для этого.
в любом случае, как техническое упражнение, давайте попробуем. (Проверял только в Хроме !)
прежде всего, основа. Мы собираемся разделить круг на 4 квадранта, и для каждого из них нам потребуется различный тип. Здесь мы имеем стили, показывающие в цвете (зеленый, красный, синий, желтый) полезный диапазон элемента значения прогресса. Серая область-это остальная часть элемента не используется.
.test {
width: 100px;
height: 100px;
margin: 20px 10px 0px 20px;
border-radius: 50%;
background-image: radial-gradient(lightblue 62%, blue 40%);
position: relative;
display: inline-block;
}
.test div {
height: 30%;
transform-origin: left top;
position: absolute;
opacity: 0.5;
ackground-color: green;
}
.inner1 {
width: 25%;
left: 50%;
top: -20%;
background-color: green;
transform: rotate(45deg) scaleX(3.9598);
}
.inner2 {
width: 50%;
left: 190%;
top: -20%;
background-image: linear-gradient(to right,gray 50%, red 50%);
transform: rotate(135deg) scaleX(3.9598);
}
.inner3 {
width: 75%;
left: 190%;
top: 260%;
background-image: linear-gradient(to right,gray 66%, blue 66%);
transform: rotate(225deg) scaleX(3.9598);
}
.inner4 {
width: 100%;
left: -230%;
top: 260%;
background-image: linear-gradient(to right,gray 75%, yellow 66%);
transform: rotate(315deg) scaleX(3.9598);
}
<div class="test">
<div class="inner1"></div>
</div>
<div class="test">
<div class="inner2"></div>
</div>
<div class="test">
<div class="inner3"></div>
</div>
<div class="test">
<div class="inner4"></div>
</div>
теперь, давайте покажем трюк для создания радиальных сегментов. Это можно сделать, установив элемент нормально (под прямым углом) к пользователю и применив некоторую перспективу:
div {
width: 300px;
height: 300px;
position: relative;
}
.container {
perspective: 400px;
margin: 40px 200px;
border: solid 1px black;
}
.top {
position: absolute;
left: 0px;
top: -100%;
background-image: repeating-linear-gradient(to right, tomato 0px, white 20px);
transform: rotateX(90deg);
transform-origin: center bottom;
}
.right {
position: absolute;
left: 100%;
top: 0px;
background-image: repeating-linear-gradient( tomato 0px, white 20px);
transform: rotateY(90deg);
transform-origin: left center;
}
.bottom {
position: absolute;
left: 0px;
bottom: 0px;
background-image: repeating-linear-gradient(to right, tomato 0px, white 20px);
transform: rotateX(90deg);
transform-origin: center bottom;
}
.left {
position: absolute;
right: 100%;
top: 0px;
background-image: repeating-linear-gradient( tomato 0px, white 20px);
transform: rotateY(-90deg);
transform-origin: right center;
}
<div class="container">
<div class="top"></div>
<div class="right"></div>
<div class="bottom"></div>
<div class="left"></div>
</div>
и теперь, просто некоторые скучные селекторы (трудно ориентировать значения в диапазоне 20-29 и не нацеливать значение 2 одновременно).
A немного JS, но только для управления значением прогресса. Вы можете использовать как вход, так и ползунок, чтобы изменить его.
function change () {
var input = document.getElementById("input");
var progress = document.getElementById("test");
progress.value = input.value;
}
function changeNumber () {
var input = document.getElementById("number");
var progress = document.getElementById("test");
progress.value = input.value;
}
.container {
width: 500px;
height: 500px;
overflow: hidden;
margin: 10px;
}
.test {
width: 200px;
height: 200px;
margin: 10px 10px;
border-radius: 50%;
background-image: radial-gradient(lightblue 62%, transparent 40%);
box-shadow: 0px 0px 0px 500px lightblue, inset 0px 0px 0px 2px lightblue;
}
.test::-webkit-progress-bar {
background-color: transparent;
position: relative;
border-radius: 50%;
perspective: 100px;
z-index: -1;
background-repeat: no-repeat;
}
.test[value^="2"]::-webkit-progress-bar,
.test[value^="3"]::-webkit-progress-bar
{
background-image: linear-gradient(red, red);
background-size: 50% 50%;
background-position: right top;
}
.test[value^="4"]::-webkit-progress-bar,
.test[value^="5"]::-webkit-progress-bar
{
background-image: linear-gradient(purple, purple);
background-size: 50% 100%;
background-position: right top;
}
.test[value^="6"]::-webkit-progress-bar,
.test[value^="7"]::-webkit-progress-bar,
.test[value="80"]::-webkit-progress-bar
{
background-image: linear-gradient(blue, blue), linear-gradient(blue, blue);
background-size: 50% 100%, 50% 50%;
background-position: right top, left bottom;
}
.test::-webkit-progress-bar,
.test[value="2"]::-webkit-progress-bar,
.test[value="3"]::-webkit-progress-bar,
.test[value="4"]::-webkit-progress-bar,
.test[value="5"]::-webkit-progress-bar,
.test[value="6"]::-webkit-progress-bar,
.test[value="7"]::-webkit-progress-bar,
.test[value="8"]::-webkit-progress-bar {
background-image: none;
}
.test::-webkit-progress-value {
background-color: green;
height: 30%;
transform-origin: left top;
z-index: -1;
position: absolute;
}
.test[value^="2"]::-webkit-progress-value,
.test[value^="3"]::-webkit-progress-value {
background-color: red;
top: -20%;
left: 190%;
transform: rotate(135deg) rotateX(-90deg) scaleX(3.9598);
}
.test[value^="4"]::-webkit-progress-value,
.test[value^="5"]::-webkit-progress-value {
background-color: purple;
left: 190%;
top: 260%;
transform: rotate(225deg) rotateX(-90deg) scaleX(3.9598);
}
.test[value^="6"]::-webkit-progress-value,
.test[value^="7"]::-webkit-progress-value,
.test[value="80"]::-webkit-progress-value {
background-color: blue;
left: -230%;
top: 260%;
transform: rotate(315deg) rotateX(-90deg) scaleX(3.9598);
}
.test::-webkit-progress-value,
.test[value="2"]::-webkit-progress-value,
.test[value="3"]::-webkit-progress-value,
.test[value="4"]::-webkit-progress-value,
.test[value="5"]::-webkit-progress-value,
.test[value="6"]::-webkit-progress-value,
.test[value="7"]::-webkit-progress-value,
.test[value="8"]::-webkit-progress-value
{
background-color: green;
left: 50%;
top: -20%;
transform: rotate(45deg) rotateX(-90deg) scaleX(3.9598);
}
<input id="input" type="range" value="0" min="0" max="80" onchange="change()" oninput="change()"/>
<input id="number" type="number" value="0" min="0" max="80" step="1" oninput="changeNumber()"/>
<div class="container">
<progress class="test" id="test" max="80" value="0"></progress>
</div>
существует трудность в переполнение: скрытый; и ошибка в Chrome. Не ожидается, что он будет работать над тем же элементом, где применяется перспектива, но он должен работать применительно к самому прогрессу. Это работает только половину времени ...
кроме того, еще одна идея, стиль-это гораздо больше проще, и я мог бы расширить его до полного диапазона, но в любом случае это отправная точка:
function change () {
var input = document.getElementById("input");
var progress = document.getElementById("test");
progress.value = input.value;
}
function changeNumber () {
var input = document.getElementById("number");
var progress = document.getElementById("test");
progress.value = input.value;
}
.test {
width: 400px;
height: 200px;
margin: 10px 10px;
border-radius: 9999px 9999px 0px 0px;
border: solid 1px red;
ackground-image: radial-gradient(lightblue 62%, transparent 40%);
ox-shadow: 0px 0px 0px 500px lightblue;
overflow: hidden;
}
.test::-webkit-progress-bar {
background-color: transparent;
position: relative;
border-radius: 50%;
perspective: 100px;
perspective-origin: center 300px;
z-index: -1;
background-repeat: no-repeat;
}
.test::-webkit-progress-value {
height: 300%;
transform-origin: center bottom;
bottom: -20%;
z-index: -1;
position: absolute;
background-image: linear-gradient(270deg, red 2px, tomato 30px);
transform: rotateX(-90deg) scaleX(1);
}
<input id="input" type="range" value="0" min="0" max="80" onchange="change()" oninput="change()">
<input id="number" type="number" value="0" min="0" max="80" step="1" oninput="changeNumber()">
<progress class="test" id="test" max="80" value="20"></progress>
Ну, это интересная задача.
элемент имеет довольно некоторые стили по умолчанию, применяемые к нему браузером и даже ОС.
<progress max="100" value="85"></progress>
Итак, во-первых, мы должны избавиться от на appearance
свойства установка в none
progress {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
<progress max="100" value="85"></progress>
затем, дополнительные стили создаются браузером укладки псевдо-элементов. Например, если вы смотрите на этот ответ в любом браузер webkit, приведенный выше фрагмент по-прежнему будет показывать плоскую коробку с зеленой заливкой, представляющей прогресс.
эти псевдо-элементы также могут быть рассмотрены в CSS. каждый браузер имеет свои конкретные псевдо-элементы, что еще больше усложняет проблему.
Webkit стеки 3 псевдо-элементов, в следующей иерархии
в то время как геккон и трезубец используют один псевдо-элемент для баров заполнения прогресса, ::-moz-progress-bar
и ::-ms-fill
, соответственно.
progress {
/*gets rid of default appearance*/
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
/*styles as any good ol' div would */
border: 1px solid black;
display:block;
width:100px; height:100px;
background:chartreuse;
}
/* gets rid of default pseudo-elements */
::-webkit-progress-inner-element {display:none}
/*for some reason, Firefox won't let the display or the content of this pseudo-element
set to none, so height:0 should do the trick. Maybe visibility:hidden too.*/
::-moz-progress-bar{height: 0;}
::-ms-fill {display:none; }
<progress max="100" value="85"></progress>
это должно оставить нас с элементом прогресса, стилизованным как хороший ol ' div, который мы можем использовать для любого из методов прогресс-бара круга, связанных выше, будучи удивительным в семантике. Мы могли бы даже использовать дополнительные псевдо-элементы по умолчанию и стилизовать их по мере необходимости вместо создания вложенных divs и таких mumbo jumbo.
это, конечно, очень экспериментально и нестандартно, поэтому не должно быть используется для производства. Поддержка несколько приличная, хотя, со всеми основными игроками, получающими некоторая форма свойства внешнего вида, и три основных двигателя, поддерживающих стиль псевдо-элементов... поэтому, возможно, я возьму назад свое предыдущее заявление и изменю его на "просто нужно быть очень осторожным"
выполнить мой код и увидеть результат
.loader {
position: relative;
height: 100px;
width: 100px;
display: flex;
align-items: center;
justify-content: center;
color: red;
margin:30px 30px;
float:left;
}
.loader:before {
content: "";
background: white;
position:absolute;
z-index:100;
width:98px;
height:98px;
border-radius:50%;
margin:auto auto;
}
progress::-moz-progress-bar { background: transparent; }
progress::-webkit-progress-bar {background: transparent;}
progress::-moz-progress-value { background: red; }
progress::-webkit-progress-value { background: red; }
.circle {
border-radius: 100%;
overflow: hidden;
padding:0;
}
.spin {
animation: spin 2s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
html {
height: 100%;
display: flex;
}
body {
margin: auto;
}
<progress max="100" value="95" class="spin circle loader"></progress>
<progress max="100" value="50" class="spin circle loader"></progress>
<progress max="100" value="10" class="spin circle loader"></progress>
спасибо @G-Cyr, я использовал часть одного из его ответов (здесь) и смешал его с моим решением, чтобы сделать этот ответ быстрее.