Comment styliser un élément de progrès HTML5 comme cercle / tarte avec CSS pur

HTML5 introduit un nouvel élément" progress " qui par défaut est rendu comme une barre de progression (thermomètre).

un exemple très simple est:

<progress max="100" value="85"></progress>

j'ai expérimenté avec une variété d'options de cercle de progrès en utilisant javascript, et j'ai également été vraiment impressionné par certaines approches CSS pur discuté ici: CSS Cercle de Progression

je suis intéressé de savoir si quelqu'un a appliqué avec succès CSS à l'élément" progress " pour fournir un rendu pie/clock/circle plutôt qu'un affichage linéaire?

EDIT/ADDENDUM: l'élément "meter" est également assez similaire à "progress" mais fournit une gamme faible / élevée...Je mentionne ceci plus pour tous ceux qui pourraient tomber sur ce poste dans le futur et veulent appliquer une technique similaire à l'élément de compteur HTML5.

20
demandé sur techtheatre 2015-05-14 08:39:35

3 réponses

essayer de le faire dans CSS pur est assez difficile, donc je ne pense pas que ce soit la bonne technique pour le faire.

de toute façon, juste comme un exercice technique, essayons-le. (Testé uniquement en Chrome !)

tout d'Abord la base. Nous allons diviser le cercle en 4 quadrants, et pour chacun, nous avons besoin d'un style différent. Ici nous avons les styles, montrant en couleur (vert, rouge, bleu, jaune) la gamme utile de l'élément de valeur de progrès. La zone grise représente le reste de l'élément inutilisé.

.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>

maintenant, montrons un truc pour créer les segments radiaux. Cela peut se faire en réglant un élément normal (à angle droit) à l'utilisateur, et en appliquant une certaine perspective:

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>

et maintenant, juste quelques sélecteurs ennuyeux (il est difficile de cibler des valeurs dans la gamme 20-29 et non cibler la valeur 2 en même temps).

un peu de JS, mais seulement pour contrôler la valeur de progression. Vous pouvez utiliser à la fois l'entrée et le curseur pour changer.

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>

il y a une difficulté dans le débordement: caché; et un bug dans Chrome. On ne s'attend pas à ce qu'il travaille sur le même élément où la perspective est appliquée, mais il devrait travailler appliqué au progrès lui-même. Il fonctionne la moitié du temps ...

aussi, une autre idée, le style est beaucoup plus simple, et je pourrais l'étendre à la gamme complète, mais de toute façon c'est un point de départ:

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>
13
répondu vals 2018-01-26 21:15:42

C'est un défi intéressant.

l'élément a tout à fait quelques styles par défaut appliqués à lui, par le navigateur et même le système D'exploitation.

<progress max="100" value="85"></progress>

donc tout d'abord, nous devrions nous débarrasser de le appearance propriété le réglage à aucun

progress {
   -webkit-appearance: none;
   -moz-appearance:    none;
   appearance:         none;
}
<progress max="100" value="85"></progress>

puis, des styles supplémentaires sont créés par le cumul de navigateur pseudo-éléments. Par exemple, si vous regardez cette réponse dans n'importe quel navigateur webkit, l'extrait ci-dessus montrera toujours une boîte plate avec un remplissage Vert représentant la progression.

ces pseudo-éléments peuvent aussi être traités dans CSS. chaque navigateur a ses pseudo-éléments spécifiques , ce qui complique davantage la question.

Webkit empile 3 pseudo-éléments, dans la hiérarchie suivante enter image description here

tandis que Gecko et Trident utilisent un seul pseudo-élément pour les barres de remplissage progressives, ::-moz-progress-bar et ::-ms-fill , respectivement.

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>

qui devrait nous laisser avec l'élément de progrès présenté comme un bon vieux div, que nous pouvons utiliser pour n'importe laquelle des méthodes de barre de progrès cercle liés ci-dessus, tout en étant génial à la sémantique. Nous pourrions même utiliser les pseudo-éléments supplémentaires par défaut et les coiffer comme nécessaire au lieu de créer des divs imbriquées et un tel charabia.

c'est, bien sûr, très expérimental et non standard, donc ne devrait pas être utilisé pour la production. Le soutien est un peu décent cependant, avec tous les joueurs majeurs obtenant une certaine forme de la propriété d'apparence , et les trois moteurs principaux soutenant le style des pseudo éléments... alors peut-être que je vais reprendre ma déclaration précédente et la changer pour un " juste doit être très prudent"

3
répondu Facundo Corradini 2018-01-25 05:53:09

Exécuter mon code et de voir le résultat

.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

merci à @g-Cyr , j'ai utilisé une partie de l'une de ses réponses ( ici ) et mélangé avec ma solution pour rendre cette réponse plus rapide.

3
répondu RAM 2018-01-26 22:26:05