Abri um tópico no frontendbr/forum#2248 sobre o assunto e até consegui uma breve explicação do criador do tailwindcss.
Mas ficou no ar a tarefa de testar o que Adam disse para ver como realmente funciona e é isso que vou fazer abaixo.
Como o tailwindcss define custom properties
Ao abrir o código final do tailwindcss você verá as custom properties definidas no seletor * asterisco, que tem uma especifidade baixa, mas maior que :root e tem efeito sobre todos os elementos de uma página.
*,:after,:before { /* <-- por que não usam :root aqui? */
--tw-translate-x: 0;
--tw-translate-y: 0;
--tw-rotate: 0;
--tw-skew-x: 0;
--tw-skew-y: 0;
--tw-scale-x: 1;
--tw-scale-y: 1;
--tw-pan-x: ;
--tw-pan-y: ;
--tw-pinch-zoom: ;
--tw-scroll-snap-strictness: proximity;
--tw-ordinal: ;
--tw-slashed-zero: ;
--tw-numeric-figure: ;
--tw-numeric-spacing: ;
--tw-numeric-fraction: ;
--tw-ring-inset: ;
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-color: #3b82f680;
--tw-ring-offset-shadow: 0 0 #0000;
--tw-ring-shadow: 0 0 #0000;
--tw-shadow: 0 0 #0000;
--tw-shadow-colored: 0 0 #0000;
--tw-blur: ;
--tw-brightness: ;
--tw-contrast: ;
--tw-grayscale: ;
--tw-hue-rotate: ;
--tw-invert: ;
--tw-saturate: ;
--tw-sepia: ;
--tw-drop-shadow: ;
--tw-backdrop-blur: ;
--tw-backdrop-brightness: ;
--tw-backdrop-contrast: ;
--tw-backdrop-grayscale: ;
--tw-backdrop-hue-rotate: ;
--tw-backdrop-invert: ;
--tw-backdrop-opacity: ;
--tw-backdrop-saturate: ;
--tw-backdrop-sepia:
}
O que me chamou a atenção foi o seletor usado *,:after,:before porque não usar :root?
A natureza das propriedades definidas
Notei que todas as propriedades como –tw-scale-x, –tw-rotate, –tw-translate-x são usadas em propriedades de CSS que tem multiplos valores ou funções aplicáveis em uma só propriedade.
Por exemplo, a propriedade transform é usada com 1 ou mais funções como valor:
.transform {
transform: scale(1.5) rotate(45deg) translateX(10px);
}
Veja abaixo, como a classe .rotate-45 é definida no tailwindcss:
.rotate-45
--tw-rotate: 45deg;
transform: translate(var(--tw-translate-x), var(--tw-translate-y))
rotate(var(--tw-rotate))
skewX(var(--tw-skew-x))
skewY(var(--tw-skew-y))
scaleX(var(--tw-scale-x))
scaleY(var(--tw-scale-y));
}
Separei o valor do transform linha a linha para ficar mais fácil de ver.
Pois essa funcionalidade do CSS de aceitar multiplas funções como valor de uma só propriedade é a razão pela qual o tailwindcss decidiu usar o seletor *,*:before,*:after para como o author explicou no tweet para garantir que a custom property seja redefinida em cada elemento e que não sejam herdadas.
Reproduzindo o problema que ele resolve
Como a classe .rotate-45 altera o valor da custom property –rotate e no CSS as variáveis são herdadas pelos elementos filhos, o exemplo abaixo pode ser um cenário válido para reproduzir o problema que o tailwindcss resolveu.
:root { /*<-- note que usei :root e não * */
--rotate: 0;
}
.rotate-45 {
--rotate: 45deg;
transform: rotate(var(--rotate));
}
.rotate {
transform: rotate(var(--rotate));
}
<div class="rotate-45">
........45deg
<div class="rotate">
........90deg
<div class="rotate">
........135deg
</div>
</div>
</div>
Demonstração abaixo:
Qual é o problema?
Faz sentido que cada elemento rode 45 graus, porém como cada classe do tailwindcss irá aplicar todas as variáveis de transform, os valores das custom properties precisam ser redefinidas.
Caso contrário, o elemento pai tem um rotate de 45 graus um dentro do outro indo para 90 graus e 135 graus.
Porém, se o elemento filho tiver apenas um scale de 1.5 sem rotação, por causa que a classe rotate-45 muda o valor da custom property que será herdada pelos filhos, o elemento filho também terá uma rotação de 45 graus “indesejada” junto com o scale desejado.
Solucionando o problema
Usar o seletor asterisco para redefinir o valor da custom property em cada elemento filho.
Usando o mesmo HTML anterior, porém com este CSS:
* { /*<-- note que usei * e não :root*/
--rotate: 0;
}
.rotate-45 {
--rotate: 45deg;
transform: rotate(var(--rotate));
}
.rotate {
transform: rotate(var(--rotate));
}
Temos a demonstração abaixo:
Conclusão
TailwindCSS tem um desafio que é “como criar classes atômicas de CSS para afetar a propriedade transform” e a solução altural faz uso extensivo de variáveis/custom properties.
De tal forma que alguns tipos de custom propriedades precisam ser definidas no seletor asterisco, para de certa forma burlar a herança de variáveis que é uma funcionalidade do CSS.
Quem quiser discutir sobre o assunto, por favor deixe um comentário lá no fórum frontendbr/forum#2248 onde a discussão começou.