Sobre conflitos Sass e recursos CSS relativamente novos

Mais recentemente, surgiram muitos recursos interessantes em CSS, como Variáveis ​​CSS e novos recursos . Embora tudo isso possa tornar a vida muito mais fácil para web designers, esses recursos podem interagir com pré-processadores CSS como o Sass de maneiras inesperadas. A autora do material, cuja tradução publicamos hoje, falará sobre os problemas que teve de enfrentar, como os enfrentou e por que acredita que ainda é impossível viver sem Sass.











Erros



Se você está experimentando com CSS-características min()e max(), em seguida, usando diferentes unidades de medida, podemos ser confrontados com mensagens de erro como este: Incompatible units: vh and em.





Mensagem de erro ao usar unidades diferentes nas funções min () e max ()



Esta mensagem é exibida porque o Sass tem sua própria funçãomin(). A função CSS émin()ignorada como resultado. Além disso, o Sass não pode realizar cálculos usando unidades que não tenham uma relação clara entre elas.



Por exemplo, a relação entre as unidades écmbemindefinida, então o Sass pode encontrar o resultado de uma funçãomin(20in, 50cm)e não lançará um erro se você usar algo assim em seu código.



A mesma coisa acontece com outras unidades de medida. Por exemplo, todas as unidades de canto estão interligados:1turn,1radou1gradsão sempre convertidos para os mesmos valores expressos em unidades deg. O mesmo é verdade, por exemplo, no caso em 1sque é sempre igual 1000ms. 1kHzsempre igual 1000Hz, 1dppxsempre igual 96dpi, 1insempre igual 96px. É por isso que o Sass pode converter valores expressos nessas unidades entre si e misturá-los em cálculos usados ​​em várias funções, como sua própria função min().



Mas tudo dá errado quando não há uma relação clara entre as unidades de medida (como, por exemplo, acima, y eme vh).



E isso não acontece apenas ao usar valores expressos em diferentes unidades de medida. Tentando usar uma função calc()internamentemin()também resulta em um erro. Se você tentar min(), colocar algo como calc(20em + 7px), ele exibe este erro: calc(20em + 7px) is not a number for min.





Mensagem de erro ocorre quando você tenta usar calc () in min ()



Outro problema ocorre em uma situação ao tentar usar o CSS-variável ou a saída de funções CSS-matemática (tais comocalc(),min(),max()) em CSS-like filtrosinvert().



Esta é a mensagem de erro que você pode ver em circunstâncias semelhantes:$color: 'var(--p, 0.85) is not a color for invert





Usando var () no filtro: invert () resulta em um erro



A mesma coisa acontece comgrayscale():$color: ‘calc(.2 + var(--d, .3))‘ is not a color for grayscale.





Usando o calc () no filtro: tons de cinza () resulta em um erro



de designfilter: opacity()também está sujeito a problemas semelhantes:$color: ‘var(--p, 0.8)‘ is not a color for opacity.





Usando var () no filtro: opacidade () resulta em um erro



, mas outras funções utilizadasfilter, incluindosepia(),blur(),drop-shadow(),brightness(),contrast()ehue-rotate(), trabalhando com as CSS-variáveis é perfeitamente normal!



Descobriu-se que a causa deste problema é semelhante à que afeta as funçõesmin()emax(). O Sass não é built-in funçõessepia(),blur(),drop-shadow(),brightness(),contrast(),hue-rotate(). Mas ele tem suas próprias funções grayscale () , invert () e opacity () . O primeiro argumento para essas funções é o valor$color. O erro aparece devido ao fato de que, ao usar construções problemáticas, Sass não encontra tal argumento.



Pelo mesmo motivo, surgem problemas ao usar variáveis ​​CSS que representam pelo menos dois hsl()ou hsla()-valores.





Erro ao usar var () em cores: hsl ()



Por outro lado, sem usar Sass, uma construçãocolor: hsl(9, var(--sl, 95%, 65%))é perfeitamente correta e CSS funcionando perfeitamente.



O mesmo é verdadeiro para funções comorgb()ergba():





Erro ao usar var () na cor: rgba ()



Além disso, se você importar o Compass e tentar usar uma variável CSS dentro dolinear-gradient()ouradial-gradient(), poderá encontrar outro erro. Mas, ao mesmo tempo,conic-gradient()você pode usar variáveisemvariáveis ​​sem problemas (é claro, se o navegador suportar essa função).





Erro ao usar var () em segundo plano: gradiente linear ()



O motivo do problema reside no fato de que o Compass tem seu próprio gradiente linear () eradial-gradient()funções, mas a funçãoconic-gradient()nunca existiu.



Em geral, todos esses problemas decorrem do fato de que Sass ou Compass têm funções próprias, cujos nomes são iguais aos do CSS. Tanto o Sass quanto o Compass, ao atender a essas funções, acreditam que vamos usar suas próprias implementações dessas funções, e não as padrão.



Aqui está uma emboscada!



Solução



Esse problema pode ser resolvido lembrando que o Sass diferencia maiúsculas de minúsculas, mas o CSS não.



Isso significa que você pode escrever algo assim Min(20em, 50vh)e o Sass não reconhece sua própria função nessa construção min(). Nenhum erro será gerado. Essa construção será um CSS bem formado que funciona exatamente como esperado. Da mesma forma, para se livrar de problemas com outras funções podem ser, forma não-padrão, escrevendo seus nomes: HSL(), HSLA(), RGB(), RGBA(), Invert().



Quando se trata de gradientes, geralmente uso esta forma: linear-Gradient()e radial-Gradient(). Faço isso porque essa notação é semelhante aos nomes usados ​​em SVG, mas nesta situação, qualquer outro nome semelhante que inclua pelo menos uma letra maiúscula funcionará.



Por que todas essas complicações?



Quase toda vez que eu tuíto algo sobre o Sass, recebo palestras sobre como, agora que você tem variáveis ​​CSS, não precisa mais usar o Sass. Decidi que deveria responder e explicar o motivo de minha discordância com essa ideia.



Em primeiro lugar, observarei que considero as Variáveis ​​CSS extremamente úteis e que as usei para uma variedade de tarefas nos últimos três anos. Mas suponho que você precise se lembrar que usá-los tem um impacto no desempenho. E a busca por um problema no labirinto de chamadascalc()pode ser a experiência mais desagradável. As ferramentas de desenvolvedor de navegador padrão ainda não são muito boas nisso. Procuro não me empolgar com o uso de variáveis ​​CSS, para não entrar em situações em que suas desvantagens se mostrem mais do que vantagens.





Não é fácil entender quais serão os resultados da avaliação dessas expressões calc (). Em



geral, se uma variável é usada como uma constante, ela não muda de elemento para elemento, ou de estado para estado (e em tais casos, as variáveis ​​CSS devem definitivamente usar necessário ), ou se a variável não reduzir a quantidade de CSS compilado (resolvendo o problema de repetição criado por prefixos), então usarei uma variável Sass.



Em segundo lugar, o suporte a variáveis ​​sempre foi um motivo muito menor entre os motivos pelos quais uso o Sass. Quando comecei a usar o Sass no segundo semestre de 2012, usei principalmente para loops. Para um recurso que ainda está faltando no CSS. Embora eu tenha movido parte da lógica de loop para o pré-processador HTML (já que isso reduz a quantidade de código gerado e evita a necessidade de modificar HTML e CSS), ainda uso loops Sass em muitos casos. Isso inclui a geração de listas de valores, criação de valores para ajustar gradientes, criação de listas de pontos ao trabalhar com uma função polygon(), criação de listas de transformações e assim por diante.



Abaixo está um exemplo do que eu teria feito antes ao criar alguns elementos HTML usando o pré-processador. Não importa qual pré-processador, mas escolhi Pug:



- let n = 12;

while n--
  .item


Então, eu criaria uma variável $nno Sass (e essa variável deve ter o mesmo valor que no HTML) e iniciaria um loop usando-a, no qual geraria as transformações usadas para posicionar cada um dos elementos:



$n: 12;
$ba: 360deg/$n;
$d: 2em;

.item {
  position: absolute;
  top: 50%; left: 50%;
  margin: -.5*$d;
  width: $d; height: $d;
  /*    */

  @for $i from 0 to $n {
    &:nth-child(#{$i + 1}) {
      transform: rotate($i*$ba) translate(2*$d) rotate(-$i*$ba);
      &::before { content: '#{$i}' }
    }
  }
}


A desvantagem disso é que eu teria que alterar os valores no código Pug e no código Sass caso o número de elementos mudasse. Além disso, há muita repetição no código.





Código CSS gerado a partir do código acima



Agora, usei uma abordagem diferente. Ou seja, usando Pug, eu gero índices como propriedades personalizadas e os uso na declaraçãotransform.



Este é o código que Pug está planejando fazer:



- let n = 12;

body(style=`--n: ${n}`)
  - for(let i = 0; i < n; i++)
    .item(style=`--i: ${i}`)


Aqui está o código Sass:



$d: 2em;

.item {
  position: absolute;
  top: 50%;
  left: 50%;
  margin: -.5*$d;
  width: $d;
  height: $d;
  /*    */
  --az: calc(var(--i)*1turn/var(--n));
  transform: rotate(var(--az)) translate(2*$d) rotate(calc(-1*var(--az)));
  counter-reset: i var(--i);

  &::before { content: counter(i) }
}


Você pode experimentar este código aqui.





Elementos gerados e estilizados usando loops O



uso dessa abordagem reduziu significativamente a quantidade de CSS gerado automaticamente.





CSS gerado a partir do código acima



Mas se você deseja criar algo como um arco-íris, você não pode fazer sem loops Sass.



@function get-rainbow($n: 12, $sat: 90%, $lum: 65%) {
  $unit: 360/$n;
  $s-list: ();

  @for $i from 0 through $n {
    $s-list: $s-list, hsl($i*$unit, $sat, $lum)
  }

  @return $s-list
}

html { background: linear-gradient(90deg, get-rainbow()) }


Aqui está uma versão funcional deste exemplo.





Plano de fundo multicolorido



Claro, isso pode ser gerado usando variáveis ​​Pug, mas essa abordagem não tem nenhuma vantagem sobre a natureza dinâmica das variáveis ​​CSS e não vai reduzir a quantidade de código passado para o navegador. Como resultado, não faz sentido para mim desistir do que estou acostumado.



Eu uso muito as funções matemáticas integradas do Sass (e do Compass), como funções trigonométricas. Atualmente, esses recursos fazem parte da especificação CSS , mas nem todos os navegadores os suportam ainda. O Sass não tem essas funções, mas o Compass tem, e é por isso que eu costumo usar o Compass.



E, claro, posso escrever minhas próprias funções desse tipo no Sass. Eu fiz isso bem no início, antes que o Compass tivesse suporte para funções trigonométricas inversas. Eu realmente preciso dessas funções, então eu mesmo as escrevi usando a série Taylor . Mas atualmente, esses recursos estão no Compass. Eles são melhores e mais produtivos do que aqueles que eu mesmo escrevi.



As funções matemáticas são muito importantes para mim porque sou um programador, não um artista. Os valores em meu CSS geralmente são gerados a partir de cálculos matemáticos. Estes não são alguns "números mágicos" ou algo que desempenha um papel puramente estético. Um exemplo de seu uso é a geração de uma lista de polígonos regulares ou quase regulares paraclip-path... Isso é usado, por exemplo, ao criar algo como avatares ou adesivos, cuja forma é diferente de retangular.



Considere um polígono regular cujos vértices estão em um círculo. Arrastar o controle deslizante no exemplo a seguir, que podemos experimentar aqui , nos permite ver onde os pontos são colocados para formas com diferentes números de vértices.





Uma forma com três vértices



Esta é a aparência do código Sass correspondente:



@mixin reg-poly($n: 3) {
  $ba: 360deg/$n; //  
  $p: (); //   ,  

  @for $i from 0 to $n {
    $ca: $i*$ba; //  
    $x: 50%*(1 + cos($ca)); //  x  
    $y: 50%*(1 + sin($ca)); //  y  
    $p: $p, $x $y //       
  }

  clip-path: polygon($p) //       clip-path 
}


Observe que estamos usando loops e outras construções aqui, que são muito inconvenientes para usar com CSS puro.



Uma versão um pouco mais avançada deste exemplo pode envolver girar o polígono adicionando o mesmo offset ( $oa) ao canto correspondente a cada vértice. Isso pode ser visto no exemplo a seguir . As estrelas são geradas aqui, que são organizadas de maneira semelhante, mas sempre têm um número par de vértices. Neste caso, cada vértice com índice ímpar está localizado em um círculo cujo raio é menor que o círculo principal ( $f*50%).





Estrela



Você pode fazerestrelas tão interessantes.





Estrelas



Você pode criar adesivos com bordas (border) criados usando modelos incomuns. No presente exemplo, a etiqueta é criado a partir de um único elemento HTML, e o modelo usado para personalizaçãoborderé criado usandoclip-pathloops de Sass e matemática. Na verdade, existem muitos cálculos aqui.





Adesivos com bordas complexas



Outro exemplo é como criar um fundo para cartões. Aqui, em um loop, usando o operador de módulo e funções exponenciais, um plano de fundo é criado com uma imitação do efeito de pontilhamento.





Efeito dithering



Aqui, também, as variáveis ​​CSS são muito usadas.



Em seguida, você pode pensar em usar mixins para evitar ter que escrever a mesma declaração repetidamente ao estilizar algo como controles deslizantes . Navegadores diferentes usam pseudoelementos diferentes para estilizar os componentes internos de tais controles, portanto, para cada componente, você precisa definir estilos que controlam sua aparência usando diferentes pseudoelementos.



Infelizmente, em CSS, por mais tentador que pareça, você não pode colocar algo como o seguinte código:



input::-webkit-slider-runnable-trackinput::-moz-range-trackinput::-ms-track { /*   */ }


Não vai funcionar. Todo este conjunto de regras é ignorado se pelo menos um seletor não for reconhecido. E, como nenhum navegador sabe da existência de todos os três seletores neste exemplo, esses estilos não serão aplicados em nenhum navegador.



Se você deseja que o estilo funcione, você precisará fazer algo assim:



input::-webkit-slider-runnable-track { /*   */ }
input::-moz-range-track { /*   */ }
input::-ms-track { /*   */ }


Mas isso pode fazer com que os mesmos estilos apareçam três vezes no código. E se você precisar, digamos, alterar uma trackpropriedade background, isso significará que você terá que editar os estilos em ::-webkit-slider-runnable-track, em ::-moz-range-tracke em ::-ms-track.



A única solução sensata para este problema é usar mixins. Os estilos se repetem no código compilado, já que não podemos prescindir dele, mas agora, pelo menos, não precisamos inserir o mesmo código três vezes no editor.



@mixin track() { /*   */ }

input {
  &::-webkit-slider-runnable-track { @include track }
  &::-moz-range-track { @include track }
  &::-ms-track { @include track }
}


Resultado



A principal conclusão que posso tirar é esta: Sass in é algo que não podemos fazer sem ainda.



Você usa Sass?






All Articles