À propos des conflits Sass et des fonctionnalités CSS relativement nouvelles

Plus récemment, il y a eu de nombreuses fonctionnalités intéressantes dans CSS, telles que les variables CSS et de nouvelles fonctionnalités . Bien que tout cela puisse rendre la vie beaucoup plus facile pour les concepteurs Web, ces fonctionnalités peuvent interagir avec les préprocesseurs CSS comme Sass de manière inattendue. L'auteur du matériel, dont nous publions aujourd'hui la traduction, parlera des problèmes auxquels elle a dû faire face, de la façon dont elle les a traités et des raisons pour lesquelles elle pense que Sass est toujours impossible de se passer.











les erreurs



Si vous expérimentez avec CSS-fonctions min()et max()puis en utilisant différentes unités de mesure, nous pourrions être confrontés à des messages d'erreur comme ceci: Incompatible units: vh and em.





Message d'erreur lors de l'utilisation d'unités différentes dans les fonctions min () et max ()



Ce message s'affiche car Sass a sa propre fonctionmin(). La fonction CSS est doncmin()ignorée. De plus, Sass ne peut pas effectuer de calculs en utilisant des unités qui n'ont pas de relation claire entre elles.



Par exemple, la relation des unités estcmbienindéfinie, de sorte que Sass peut trouver le résultat d'une fonctionmin(20in, 50cm)et ne renvoie pas d'erreur si vous utilisez quelque chose comme ça dans votre code.



La même chose se produit avec d'autres unités de mesure. Par exemple, toutesunités d'angle sont reliés entre eux:1turn,1radou1gradsont toujours convertis aux mêmes valeurs exprimées en unités deg. Il en est de même, par exemple, dans le cas où 1sil est toujours égal 1000ms. 1kHztoujours égal 1000Hz, 1dppxtoujours égal 96dpi, 1intoujours égal 96px. C'est pourquoi Sass peut convertir les valeurs exprimées dans ces unités entre elles et les mélanger dans des calculs utilisés dans diverses fonctions, comme sa propre fonction min().



Mais tout va mal lorsqu'il n'y a pas de relation claire entre les unités de mesure (comme, par exemple, ci-dessus, y emet vh).



Et cela ne se produit pas seulement lors de l'utilisation de valeurs exprimées dans différentes unités de mesure. Essayer d'utiliser une fonction en calc()internemin()entraîne également une erreur. Si vous essayez de min(), mettre quelque chose comme calc(20em + 7px), il affiche cette erreur: calc(20em + 7px) is not a number for min.





Message d'erreur se produit lorsque vous essayez d'utiliser calc () en min ()



Un autre problème se produit dans une situation en essayant d'utiliser la variable CSS ou la sortie des fonctions CSS-mathématiques (exemplecalc(),min(),max()) en CSS commefiltresinvert().



Voici le message d'erreur que vous pourriez voir dans des circonstances similaires:$color: 'var(--p, 0.85) is not a color for invert





En utilisant var () dans le filtre: inverti () provoque une erreur



La même chose se produit avecgrayscale():$color: ‘calc(.2 + var(--d, .3))‘ is not a color for grayscale.





Utilisation de la calc () dans le filtre: résultats en niveaux de gris () une erreur



de conceptionfilter: opacity()est également soumise àproblèmes similaires:$color: ‘var(--p, 0.8)‘ is not a color for opacity.





En utilisant var () dans le filtre: l' opacité () provoque une erreur



, maisautres fonctions utiliséesfilter, y comprissepia(),blur(),drop-shadow(),brightness(),contrast()ethue-rotate(),collaboration avec les variables CSS-est toutfait normal!



Il s'est avéré que la cause de ce problème est similaire à celle qui affecte les fonctionsmin()etmax(). Le Sass est pas intégré dansfonctionssepia(),blur(),drop-shadow(),brightness(),contrast(),hue-rotate(). Mais il a ses propres fonctions en niveaux de gris () , invert () et opacity () . Le premier argument de ces fonctions est la valeur$color. L'erreur apparaît en raison du fait que lors de l'utilisation de constructions problématiques, Sass ne trouve pas un tel argument.



Pour la même raison, des problèmes surviennent lors de l'utilisation de variables CSS qui représentent au moins deux hsl()ou des hsla()valeurs.





Erreur lors de l'utilisation de var () en couleur: hsl ()



D'un autre côté, sans utiliser Sass, une constructioncolor: hsl(9, var(--sl, 95%, 65%))est parfaitement correcte et fonctionne parfaitement en CSS.



Il en va de même pour des fonctions telles quergb()etrgba():





Erreur lors de l'utilisation de var () dans la couleur: rgba ()



De plus, si vous importez Compass et essayez d'utiliser une variable CSS à l'intérieur delinear-gradient()ouradial-gradient(), vous pourriez rencontrer une autre erreur. Mais, en même temps,conic-gradient()vous pouvez utiliser des variables sans aucun problème (bien sûr, si le navigateur prend en charge cette fonction).





Erreur lors de l'utilisation de var () en arrière-plan: linear-gradient ()



La raison du problème réside dans le fait que Compass a son propre gradient linéaire () etses propresradial-gradient()fonctions, mais la fonctionconic-gradient()n'y était jamais.



En général, tous ces problèmes proviennent du fait que Sass ou Compass ont leurs propres fonctions, dont les noms sont les mêmes que ceux en CSS. Sass et Compass, lorsqu'ils remplissent ces fonctions, pensent que nous allons utiliser leurs propres implémentations de ces fonctions, et non celles standard.



Voici une embuscade!



Solution



Ce problème peut être résolu en se rappelant que Sass est sensible à la casse mais que CSS ne l'est pas.



Cela signifie que vous pouvez écrire quelque chose comme ceci Min(20em, 50vh)et que Sass ne reconnaît pas sa propre fonction dans cette construction min(). Aucune erreur ne sera générée. Cette construction sera un CSS bien formé qui fonctionne exactement comme prévu. De même, pour se débarrasser des problèmes avec d' autres fonctions peuvent être, de façon non standard en écrivant leur nom: HSL(), HSLA(), RGB(), RGBA(), Invert().



Quand il s'agit de dégradés, j'utilise généralement cette forme: linear-Gradient()et radial-Gradient(). Je fais cela parce que cette notation est proche des noms utilisés en SVG, mais dans cette situation, tout autre nom similaire comprenant au moins une majuscule fonctionnera.



Pourquoi toutes ces complications?



Presque chaque fois que je tweet quelque chose à propos de Sass, on me dit que maintenant que vous avez des variables CSS, vous n'avez plus besoin d'utiliser Sass. J'ai décidé que je devais répondre à cela et expliquer la raison de mon désaccord avec cette idée.



Tout d'abord, je noterai que je trouve les variables CSS extrêmement utiles et que je les ai utilisées pour diverses tâches au cours des trois dernières années. Mais je suppose que vous devez garder à l'esprit que leur utilisation a un impact sur les performances. Et la recherche d'un problème dans le labyrinthe des appelscalc()peut être l'expérience la plus désagréable. Les outils de développement de navigateur standard ne sont pas encore très bons pour cela. J'essaye de ne pas me laisser emporter par l'utilisation des variables CSS, pour ne pas entrer dans des situations où leurs inconvénients se manifestent plus que leurs avantages.





Il n'est pas facile de comprendre quels seront les résultats de l'évaluation de ces expressions calc () En



général, si une variable est utilisée comme constante, elle ne change pas d'élément en élément, ou d'état en état (et dans de tels cas, les variables CSS devraient certainement utiliser nécessaire ), ou si la variable ne réduit pas la quantité de CSS compilée (résolution du problème de répétition créé par les préfixes), alors j'utiliserai une variable Sass.



Deuxièmement, le support variable a toujours été une raison assez mineure parmi les raisons pour lesquelles j'utilise Sass. Quand j'ai commencé à utiliser Sass au second semestre 2012, je l'ai fait principalement pour les boucles. Pour une fonctionnalité qui manque encore au CSS. Bien que j'aie déplacé une partie de la logique de boucle dans le préprocesseur HTML (car cela réduit la quantité de code généré et évite d'avoir à modifier à la fois HTML et CSS), j'utilise toujours des boucles Sass dans de nombreux cas. Celles-ci incluent la génération de listes de valeurs, la création de valeurs pour ajuster les dégradés, la création de listes de points lors de l'utilisation d'une fonction polygon(), la création de listes de transformations, etc.



Voici un exemple de ce que j'aurais fait plus tôt lors de la création de certains éléments HTML à l'aide du préprocesseur. De quel préprocesseur il s'agit n'a pas vraiment d'importance, mais j'ai choisi Pug:



- let n = 12;

while n--
  .item


Ensuite, je créerais une variable $ndans Sass (et cette variable devrait avoir la même valeur qu'en HTML) et commencerais une boucle en l'utilisant, dans laquelle je générerais les transformations utilisées pour positionner chacun des éléments:



$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}' }
    }
  }
}


L'inconvénient est que je devrais changer les valeurs dans le code Pug et le code Sass dans le cas où le nombre d'éléments changerait. De plus, il y a beaucoup de répétition dans le code.





CSS généré à partir du code ci-dessus



J'ai maintenant adopté une approche différente. À savoir, en utilisant Pug, je génère des index en tant que propriétés personnalisées, puis je les utilise dans la déclarationtransform.



Voici le code que Pug prévoit de faire:



- let n = 12;

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


Voici le code 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) }
}


Vous pouvez tester ce code ici.





Éléments générés et stylisés à l'aide de boucles



Cette approche a considérablement réduit la quantité de CSS généré automatiquement.





CSS généré à partir du code ci-dessus



Mais si vous voulez créer quelque chose comme un arc-en-ciel, vous ne pouvez pas vous passer des boucles 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()) }


Voici une version fonctionnelle de cet exemple.





Arrière-plan multicolore



Bien sûr, cela peut être généré à l'aide de variables Pug, mais cette approche n'a aucun avantage sur la nature dynamique des variables CSS et ne réduira pas la quantité de code transmise au navigateur. En conséquence, cela n'a aucun sens pour moi d'abandonner ce à quoi je suis habitué.



J'utilise beaucoup les fonctions mathématiques intégrées de Sass (et Compass), telles que les fonctions trigonométriques. De nos jours, ces fonctionnalités font partie de la spécification CSS , mais tous les navigateurs ne les prennent pas encore en charge. Sass n'a pas ces fonctions, mais Compass en a, c'est pourquoi j'utilise souvent Compass.



Et bien sûr, je peux écrire mes propres fonctions de ce genre dans Sass. Je l'ai fait au tout début, avant que Compass ne prenne en charge les fonctions trigonométriques inverses. J'ai vraiment besoin de ces fonctions, alors je les ai écrites moi-même en utilisant la série Taylor . Mais ces jours-ci, ces fonctionnalités sont dans Compass. Ils sont meilleurs et plus productifs que ceux que j'ai écrits moi-même.



Les fonctions mathématiques sont très importantes pour moi parce que je suis programmeur, pas artiste. Les valeurs de mon CSS sont généralement générées à partir de calculs mathématiques. Ce ne sont pas des "nombres magiques", ou quelque chose qui joue un rôle purement esthétique. Un exemple de leur utilisation est de générer une liste de polygones réguliers ou quasi-réguliers pourclip-path... Ceci est utilisé, par exemple, lors de la création de quelque chose comme des avatars ou des autocollants, dont la forme est différente de rectangulaire.



Considérons un polygone régulier dont les sommets se trouvent sur un cercle. Faire glisser le curseur dans l'exemple suivant, que nous pouvons expérimenter ici , nous permet de voir où sont placés les points pour les formes avec différents nombres de sommets.





Une forme à trois sommets



Voici à quoi ressemble le code Sass correspondant:



@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 
}


Veuillez noter que nous utilisons ici des boucles et d'autres constructions, qui sont très peu pratiques à utiliser avec du CSS pur.



Une version légèrement plus avancée de cet exemple pourrait impliquer la rotation du polygone en ajoutant le même décalage ( $oa) au coin correspondant à chaque sommet. Cela peut être vu dans l' exemple suivant . Les étoiles sont générées ici, qui sont disposées de la même manière, mais ont toujours un nombre pair de sommets. Dans ce cas, chaque sommet d'indice impair est situé sur un cercle dont le rayon est inférieur au cercle principal ( $f*50%).





Étoiles



Vous pouvez faire ces étoiles intéressantes.





Étoiles



Vous pouvez créer des autocollants avec des bordures (border), créés à l'aide de modèles inhabituels. Dans cet exemple, l'autocollant est créé à partir d'un seul élément HTML et le modèle utilisé pour la personnalisationborderest créé à l'aide declip-pathboucles Sass et de mathématiques. En fait, il y a beaucoup de calculs ici.





Autocollants avec des bordures complexes



Un autre exemple est la création d'un arrière-plan pour les cartes. Ici, dans une boucle, à l'aide de l' opérateur de module et des fonctions exponentielles, un arrière-plan est créé avec une imitation de l'effet de tramage.





Effet de Dithering



Ici aussi, les Variables CSS sont très utilisées.



Ensuite, vous pouvez penser à utiliser des mixins pour éviter d'avoir à écrire la même déclaration encore et encore lorsque vous stylisez quelque chose comme des curseurs . Différents navigateurs utilisent différents pseudo-éléments pour styliser les composants internes de ces contrôles. Par conséquent, pour chaque composant, vous devez définir des styles qui contrôlent leur apparence à l'aide de différents pseudo-éléments.



Malheureusement, en CSS, aussi tentant que cela puisse paraître, vous ne pouvez pas mettre quelque chose comme le code suivant:



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


Ça ne marchera pas. Cet ensemble complet de règles est ignoré si au moins un sélecteur n'est pas reconnu. Et, étant donné qu'aucun navigateur ne connaît l'existence des trois sélecteurs dans cet exemple, ces styles ne seront appliqués dans aucun navigateur.



Si vous voulez que le style fonctionne, vous devrez faire quelque chose comme ceci:



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


Mais cela peut faire apparaître les mêmes styles trois fois dans le code. Et si vous avez besoin, par exemple, de modifier une trackpropriété background, cela signifie que vous devez modifier les styles dans ::-webkit-slider-runnable-track, dans ::-moz-range-tracket dans ::-ms-track.



La seule solution sensée à ce problème est d'utiliser des mixins. Les styles sont répétés dans le code compilé, car il n'y a aucun moyen de s'en passer, mais maintenant, au moins, nous n'avons pas à saisir le même code trois fois dans l'éditeur.



@mixin track() { /*   */ }

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


Résultat



La principale conclusion que je peux tirer est la suivante: Sass in est quelque chose dont nous ne pouvons pas encore nous passer.



Utilisez-vous Sass?






All Articles