Conteúdo deste artigo
A matemática CSS não se trata apenas da aparência das coisas! Também pode ser usado para descobrir informações numéricas úteis. Por exemplo, você pode calcular e mostrar a porcentagem de tarefas concluídas em uma lista de tarefas com CSS, ajudando os usuários a acompanhar seu progresso. Não há necessidade de script ou computação de servidor. Sem latência. Não há uso de recursos adicionais do navegador.
Trabalhar com matemática ficou muito mais simples e flexível. Vou dar um exemplo usando CSS para calcular e exibir um preço com desconto sempre que você precisar, usando o preço base e o desconto fornecido. É o tipo de coisa que você vê com frequência em sites de comércio eletrônico, onde JavaScript pesado é usado para mostrar o preço total de um produto, o valor do desconto e o preço de venda.

Podemos fazer isso com certeza em CSS:
Ele depende de alguns recursos de ponta que estão esperando para obter mais suporte do navegador, mas acho que ainda é um bom exercício para descobrir como seremos capazes de colocar essas coisas em prática e, eventualmente, usá-las em nosso trabalho diário.
Veja como eu montei tudo.
A marcação inicial
A interface nesta demonstração específica exibe uma lista de serviços de streaming para o usuário escolher – Netflix, Disney+, HBO , HBO Now , HBO Go , HBO Max, etc. Há uma oferta de desconto para estudantes em cada assinatura que retira uma determinada porcentagem do preço total.
<li>
<!-- Service name, base price, and selection toggle -->
<label>
<span>Netflix</span>
<!-- data-price and data-discount store base price and discount offered -->
<div class="ott-price" data-price="7.99" data-discount="0.2">$7.99</div>
<!-- Checkbox to track if the user wants to add this service -->
<input type="checkbox" class="is-ott-selected">
</label>
<!-- Toggle for the student discount -->
<label>
<span>Apply Student Discount <br> 20%</span>
<input type="checkbox" class="is-ott-discounted">
</label>
</li>
<!-- etc. -->
O preço base e o desconto são incluídos como atributos <li>
<!-- Service name, base price, and selection toggle -->
<label>
<span>Netflix</span>
<!-- data-price and data-discount store base price and discount offered -->
<div class="ott-price" data-price="7.99" data-discount="0.2">$7.99</div>
<!-- Checkbox to track if the user wants to add this service -->
<input type="checkbox" class="is-ott-selected">
</label>
<!-- Toggle for the student discount -->
<label>
<span>Apply Student Discount <br> 20%</span>
<input type="checkbox" class="is-ott-discounted">
</label>
</li>
<!-- etc. --> no elemento que exibe o preço. Lembre-se de que o desconto só entra em vigor quando você seleciona “Aplicar desconto para estudante” e então você verá quanto é o preço após a aplicação do desconto.
Calculando a redução de preço
Quando o desconto entra em vigor, o primeiro passo é reduzir o preço base com uma linha atravessada.
/* When the discount toggle is checked inside the .ott container */
.ott:has(.is-ott-discounted:checked) {
/* Strike through the original price */
.ott-price {
text-decoration: line-through;
}
}
A seguir, vamos descobrir o novo preço com desconto usando os valores data-* e /* When the discount toggle is checked inside the .ott container */.
.ott:has(.is-ott-discounted:checked) {
/* Strike through the original price */
.ott-price {
text-decoration: line-through;
}
}
.ott:has(.is-ott-discounted:checked) {
.ott-price {
text-decoration: line-through;
/*
Calculate the new price from the data-* attributes:
Original Price * (1 - Discount Applied)
*/
--n: calc(attr(data-price number) * (1 - attr(data-discount number)));
}
}
A data-price sintaxe é relativamente nova. A função costumava funcionar apenas com a propriedade data-discount, mas agora suporta qualquer propriedade CSS… e analisa valores em uma variedade de tipos de dados, enquanto antes eles eram sempre analisados como strings.
Esses argumentos:
-
.ott:has(.is-ott-discounted:checked) {: Este é o nome do atributo HTML que queremos ver (como
.ott-price {
text-decoration: line-through;
/*
Calculate the new price from the data-* attributes:
Original Price * (1 - Discount Applied)
*/
--n: calc(attr(data-price number) * (1 - attr(data-discount number)));
}
}attr(<name> <type>),content, ou<name>). -
href: Isso diz ao CSS como “ler” o valor (como umdata-count, umtitleou um<type>). É a nova superpotência que torna possível o trabalho que estamos fazendo aqui.
Em nosso caso, estamos usando a função para analisar data-* e /* When the discount toggle is checked inside the .ott container */ em
.ott:has(.is-ott-discounted:checked) {
/* Strike through the original price */
.ott-price {
text-decoration: line-through;
}
}length, e então subtraímos o desconto do preço com matemática CSS.
O data-price atualizado é super legal, mas não é a linha de base enquanto escrevo isso, então fique de olho nele.
Mostrando o preço com desconto
Veja como exibimos o preço atualizado assim que o desconto for aplicado:
.ott:has(.is-ott-discounted:checked) {
.ott-price {
text-decoration: line-through;
--n: calc(attr(data-price number) * (1 - attr(data-discount number)));
&::after {
display: inline-block;
/* Splits the variable --n into two counters:
'a' for the whole number (in dollars) and 'b' for the decimals (in cents) */
counter-set: a calc(round(down, var(--n))) b calc((mod(var(--n), 1)) * 100);
/* Output: two spaces (2000), a dollar sign ($), the number, a dot, and the decimals */
content: "20002000$" counter(a) "." counter(b, decimal-leading-zero);
}
}
}
A função data-discount nos ajuda a transformar o valor numérico do numbers variável em uma data-discount string. Como os contadores CSS não podem lidar com decimais (eles arredondam o valor por padrão), tratamos os números antes e depois do decimal como contadores separados e depois os combinamos como strings, adicionando um ponto entre eles.
-
.ott:has(.is-ott-discounted:checked) {pega a variável
.ott-price {
text-decoration: line-through;
--n: calc(attr(data-price number) * (1 - attr(data-discount number)));&::after {
display: inline-block;
/* Splits the variable --n into two counters:
'a' for the whole number (in dollars) and 'b' for the decimals (in cents) */
counter-set: a calc(round(down, var(--n))) b calc((mod(var(--n), 1)) * 100);
/* Output: two spaces (2000), a dollar sign ($), the number, a dot, and the decimals */
content: "20002000$" counter(a) "." counter(b, decimal-leading-zero);
}
}
}numberse arredonda reduza-o para obter o valor total em dólares (armazenado como--n). -
contentusa o módulocalc(round(down, var(--n)))função para isolar a fração e, em seguida, multiplica-a por--npara obter os centavos (armazenados comocounter(a)). - A propriedade
data-discountinsere um cifrão antes dos dois contadores e depois os une com um ponto.
Sabemos que mod() tem bastante suporte para navegador. E adivinhe? A função calc(round(down, var(--n))) é nova linha de base!
Isso só se você precisar de decimais e tudo mais. Se você estiver arredondando os preços, isso seria suficiente:
counter-set: price calc(var(--n));
content: counter(price);
Aqui está a demonstração mais uma vez:
Concluindo
Então, aí está, uma combinação funcional de recursos CSS mais recentes (a função data-price atualizada), funções matemáticas CSS (calc(round(down, var(--n))), calc()) e contadores personalizados para definir algo que vemos em tantos sites, só que sem scripts. Quando o suporte de data-price para tipos de dados se tornar uma coisa em todos os navegadores, isso é algo que você pode usar em seu trabalho diário.
Calculando e exibindo preços com desconto em CSS originalmente escrito à mão e publicado com amor em CSS-Tricks . Você realmente deveria receber o boletim informativo também.
