Das diferentes manerias de fazer barras de progresso circular, a que você conhecerá agora, usando somente CSS, com certeza vai surpreender!
Em desenvolvimento web, quase sempre é possível chegar a resultados semelhantes usando técnicas diferentes. O mesmo vale para fazer um componente de barra de progresso circular — ou circular progress bar, radial progress bar, circular loading, barra de porcentagem radial…
É possível fazer usando JavaScript, com imagens, imagens inline, SVGs, enfim, uma miríade de técnicas, das mais modernas às mais consagradas.
Mas essa daqui é diferente; a maneira como essas barras de progresso circular são feitas usando CSS puro (com uma mãozinha de Sass, para não cansar muito) é diferente de tudo o que você já viu.
As bases da técnica para a barra de progresso circular
Além de diferente, a técnica é simples.
A ideia é usar linear-gradient()
de maneira ixpertinha para conseguir resultados visuais angulados, conforme cada porcentagem necessária em um componente radial desta natureza.
Na camada de conteúdo, pode ser somente um elemento vazio, como uma div
, i
ou span
. Dando ênfase na metodologia BEM de nomenclatura, haverá um Modificador para cada grau de “loading” do círculo.
O HTML necessário
Para o exemplo, optemos por usar span
para o elemento:
1 |
<span class="c-circular-progress"></span> |
Então, conforme explicado, para conseguir a porcentagem que se queira, usa-se uma classe Modificadora com a porcentagem do loading que se quer:
1 |
<span class="c-circular-progress c-circular-progress--4"></span> |
Depois de feita a mágica com Sass, estarão disponíveis 100 classes Modificadoras para serem usadas, uma para cada grau de preenchimento da barra de progresso circular.
Sass/CSS para a estilização
A base para o visual do componente é o seguinte:
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 |
$component-name: "c-circular-progress"; .#{$component-name} { border-radius: 50%; display: block; height: rem(250); margin: $global-module-size auto; position: relative; width: rem(250); &::before { align-items: center; background-color: var(--color-webfatorial-white); border-radius: 50%; display: inline-flex; font-size: 500%; height: 100%; justify-content: center; left: 0; position: absolute; top: 0; transform: scale(0.8); width: 100%; } } |
Perceba que a aparência do ::before
foi estabelecida, mas a propriedade content
não está presente. Isso faz parte da técnica.
O conteúdo, o que será exibido textualmente, será o próprio valor da porcentagem atual, o que será alcançado dentro da geração automática das 100 classes com Sass.
Então, é hora de usar a diretiva @for
para ajudar a gerar essa centena de classes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
@for $i from 0 through 100 { $deg: 90deg + (3.6 * $i); &--#{$i} { $direction: if($i < 51, right, left); $color: if($i < 51, $color-background, $color-fill); background: linear-gradient( to #{$direction}, #{$color} 50%, transparent 50% ), linear-gradient( #{$deg}, $color-fill 50%, $color-background 50% ); &::before { content: quote("#{$i}"); } } } |
Vamos ao esclarecimento de alguns pontos (possivelmente) críticos.
$deg: 90deg + (3.6 * $i);
Essa continha pode parecer muito complexa, mas não é tanto.
90deg
refere-se ao valor-base adotado (uma divisão vertical no degradê para o início dos cálculos).
3.6
pode parecer um valor aleatório, mas trata-se do equivalente a 1° no círculo que mostra a porcentagem/loading atual.
Que é multiplicado por $i
, que é o valor atual do loop de Sass, com isso, gerando uma angulação apropriada, equivalente ao valor corrente usado no Modificador.
Por exemplo, quando o loop estiver em 10
, o cálculo será:
1 |
90 + (3.6 * 10) // 126deg |
Quando for 67
:
1 |
90 + (3.6 * 67) // 331.2deg |
E assim por diante, calculando os valores de ângulo/grau apropriados para cada uma das 100 classes geradas.
$direction: if($i < 51, right, left)
Desde Sass 3.3, é possível usar a função if()
com sintaxe aprimorada, tratando-se de um ternário com estrutura if(condition, result-when-true, result-when-false)
.
A partir do valor 51
, é preciso alternar a direção e cor do degradê para o visual fique correto. Para evitar duplicação de códigos, esse ternários vêm a calhar.
Ah, e viu lá no ::before
o content: quote("#{$i}");
? É o que foi comentado acima: cada Modificador dará o valor atual do número a ser exibido.
Resultado final da barra de progresso circular
Viu como, além de diferente — gerar barra de progresso circular usando background e linear-gradient() –, a técnica também é simples?
No final das contas, você vai conseguir gerar barra de porcentagem circular parecidas com:
Só de alterar a classe Modificadora, tanto posição do loading, quanto número, são atualizados automaticamente.
Intervenção mínima na camada de conteúdo, alteração máxima no componente na camada de apresentação.
Bônus: data-*
A técnica foi pensada com o uso de Modificadores BEM em mente. Entretanto, não é a única maneira de se alcançar o resultado final.
Se, por algum motivo, você não gosta muito da nomenclatura BEM (apesar de ela trazer muitas vantagens quando usada), também é possível usar atributos data-*
.
Dentro do @for
de Sass, quando da definição dos Modificadores, simplesmente altere o código para:
1 2 3 4 |
&--#{$i}, &[data-deg="#{$i}"] { // ... } |
Com isso, além de ser possível usar Modificadores, agora também será possível conseguir a barra circular de loading usando data-deg
(você pode usar algum outro nome de sua preferência, claro) e passando o valor que se quer.
Na prática, agora estes 2 códigos são equivalentes, gerando a mesma barrinha circular:
1 2 |
<span class="c-circular-progress c-circular-progress--33"></span> <span class="c-circular-progress" data-deg="33"></span> |
Como dizem, fica ao gosto do freguês. :)
Conclusão
É possível fazer essa barrinha de loading circular usando JavaScript, com imagens, imagens inline, SVGs, enfim, uma miríade de técnicas, das mais modernas às mais consagradas.
Inclusive, abundam soluções JavaScript solo e com bibliotecas e frameworks para gráficos (para a surpresa de ninguém).
Mas essa solução é diferenciada: ela prima pela simplicidade de recursos e facilidade de uso. É uma solução sem JavaScript, que provê um visual interessante e agradável para barras de progresso circular.
Para todos os passos de desenvolvimento da barra circular de progresso, assista ao vídeo no começo do artigo; para acessar o código completo, acesse o código completo no repo do projeto.
E aí, gostou do resultado final? Tem usado 2MB de JavaScript para chegar a esse mesmo resultado? Conta pra gente aí nos comentários.