Как стиль элемента прогресса 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 псевдо-элементов, в следующей иерархии enter image description here

в то время как геккон и трезубец используют один псевдо-элемент для баров заполнения прогресса, ::-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>

enter image description here

спасибо @G-Cyr, я использовал часть одного из его ответов (здесь) и смешал его с моим решением, чтобы сделать этот ответ быстрее.