A gente está acostumado a usar JavaScript para qualquer cálculo no front-end. Mas o CSS moderno está ficando poderoso demais! Com a evolução da função attr() e a chegada de funções matemáticas como calc(), mod() e round(), dá pra fazer coisas complexas direto no estilo. Vamos ver como calcular e mostrar um preço com desconto em um site de e-commerce, tudo isso sem script!

O HTML Inicial: Preparando o Terreno
Vamos criar um painel de preços de assinatura para um serviço de streaming. A estrutura usa atributos data-* para guardar o preço base e a porcentagem de desconto. Isso mantém o HTML limpo e os dados prontos para nossa lógica em CSS.
<div class="ott">
<input type="checkbox" id="desconto" class="is-ott-discounted">
<label for="desconto">Aplicar Desconto de Estudante</label>
<div class="ott-card">
<h3>Netflix</h3>
<p class="ott-price" data-price="7.99" data-discount="0.20">$7.99</p>
</div>
</div>
Calculando o Desconto: O Poder de attr() e calc()
Quando o usuário marca o desconto, a gente usa o seletor :has() para detectar a mudança e aplicar os cálculos. O segredo é a função attr() atualizada, que agora consegue interpretar valores como number.
/* Quando o toggle de desconto está marcado dentro do container .ott */
.ott:has(.is-ott-discounted:checked) {
/* Risca o preço original */
.ott-price {
text-decoration: line-through;
/*
Calcula o novo preço com os atributos data-*:
Preço Original * (1 - Desconto Aplicado)
*/
--n: calc(attr(data-price number) * (1 - attr(data-discount number)));
}
}
Nesse trecho, attr(data-price number) extrai o valor 7.99 como número, e attr(data-discount number) extrai 0.20. A função calc() faz a conta do preço com desconto. O resultado fica na variável --n.

Exibindo o Resultado: Separando Números com mod() e round()
Os contadores do CSS não lidam bem com decimais. Para mostrar o preço certinho (ex: $6.39), a gente separa a parte inteira da decimal. É aqui que as funções mod() e round() brilham.
.ott:has(.is-ott-discounted:checked) {
.ott-price {
/* ... estilos anteriores ... */
&::after {
display: inline-block;
/*
Divide a variável --n em dois contadores:
'a' para a parte inteira (em dólares) e 'b' para os centavos
*/
counter-set: a calc(round(down, var(--n))) b calc((mod(var(--n), 1)) * 100);
/* Saída: dois espaços (\2000), um cifrão ($), o número, um ponto e os centavos */
content: "\2000\2000quot; counter(a) "." counter(b, decimal-leading-zero);
}
}
}
Aqui, round(down, var(--n)) nos dá a parte inteira (ex: 6), e mod(var(--n), 1) isola a parte fracionária, que multiplicamos por 100 para achar os centavos (ex: 39). A propriedade content monta a string final com o cifrão e a vírgula.

Limitações e Pontos de Atenção
Apesar de ser uma demonstração incrível do poder do CSS moderno, precisamos ficar de olho nas limitações.
- Suporte dos Browsers: A função
attr()atualizada ainda não tem suporte amplo (não é Baseline). As funçõesmod()eround()são bem recentes. Sempre confira no caniuse.com os dados de suporte. - Acessibilidade: Os leitores de tela podem não interpretar o texto gerado pela propriedade
contentda mesma forma que o HTML real. Use essa técnica quando o resultado visual for o principal e mantenha o preço original no DOM para contexto. - Complexidade: Para lógicas de preço complexas (ex: descontos em cascata, cálculos de imposto), o JavaScript continua sendo a solução mais escalável e fácil de manter. Essa abordagem com CSS é ideal para cálculos simples e estáticos.
Próximos Passos para Aprender
Para aprofundar no que você aprendeu, explore:
- CSS Typed OM: O CSS Typed Object Model é a API que torna possível o novo comportamento da
attr(). Entender isso vai te ajudar a compreender melhor como os valores CSS funcionam. - Container Queries: Combine essas funções matemáticas com container queries para criar componentes verdadeiramente responsivos.
- Experimentação: Tente construir outros elementos, como uma barra de progresso que usa
mod()para criar um efeito listrado ou um sistema de avaliação dinâmico que usaround().