关于Sass冲突和相对较新的CSS功能

最近,CSS中有许多有趣的功能,例如CSS Variables和new features尽管所有这些都可以使Web设计人员的工作变得更加轻松,但是这些功能可以以意想不到的方式与CSS预处理程序(如Sass)进行交互。 该材料的作者(我们今天将发表其翻译)将谈论她必须面对的问题,如何处理这些问题,以及为什么她认为Sass仍然是不可能做到的。











失误



如果您正在尝试CSS功能min()max()然后使用不同的度量单位,我们可能会遇到如下错误消息:Incompatible units: vh and em





在min()和max()函数中使用不同单位时的错误消息,



因为Sass具有其自身的功能,所以显示此消息min()min()结果,忽略CSS函数。此外,Sass无法使用彼此之间没有明确关系的单位执行计算。



例如,单位的关系定义得cm很好in,因此,min(20in, 50cm)如果在代码中使用类似的内容,那么Sass可以找到函数的结果,并且不会引发错误。



其他度量单位也会发生相同的情况。例如,所有的角落单位相互关联的:1turn1rad1grad始终转换为以单位表示的相同值deg。例如,在1s始终等于的情况下也是如此1000ms1kHz永远平等1000Hz1dppx永远平等96dpi1in永远平等96px。这就是为什么Sass可以将以这些单位表示的值相互转换,并将其混合在各种函数(例如其自身函数)中使用的计算中min()



但是,如果度量单位之间没有明确的关系(例如,上面的yemvh,则一切都会出错



这不仅发生在使用以不同度量单位表示的值时。尝试在calc()内部使用功能min()也会导致错误。如果尝试min()这样做calc(20em + 7px),则会显示以下错误:calc(20em + 7px) is not a number for min





当试图使用计算值()的分钟()时发生错误消息



发生的另一个问题的状况下试图使用CSS-变量或CSS-数学函数的输出(例如,当calc()min()max()在)CSS状滤波器invert()



这是在类似情况下可能会看到的错误消息:$color: 'var(--p, 0.85) is not a color for invert





在过滤器中使用VAR():反转()导致错误



发生同样的事情有grayscale()$color: ‘calc(.2 + var(--d, .3))‘ is not a color for grayscale





在过滤器中使用calc():grayscale()会导致错误



设计filter: opacity(),但也会遇到类似的问题:$color: ‘var(--p, 0.8)‘ is not a color for opacity





在过滤器中使用VAR():不透明度()导致错误



,但使用其他功能filter,包括sepia()blur()drop-shadow()brightness()contrast()hue-rotate(),与CSS-变量的工作是完全正常的!



事实证明,此问题的原因与影响功能min()的原因类似max()。该萨斯是没有内置功能sepia()blur()drop-shadow()brightness()contrast()hue-rotate()。但是它具有自己的功能grayscale() invert()opacity()。这些函数的第一个参数是value$color。出现该错误是由于以下事实:使用有问题的构造时,Sass找不到这样的论点。



出于相同的原因,使用代表至少两个hsl()hsla()-values的CSS变量时会出现问题





在颜色中使用var()时出错:hsl()



另一方面,如果不使用Sass,则构造color: hsl(9, var(--sl, 95%, 65%))是完全正确且可以正常工作的CSS。



这同样适用于功能,如真rgb()rgba()





在颜色中使用var()时出错:rgba()



另外,如果导入Compass并尝试在linear-gradient()或中使用CSS变量radial-gradient(),则可能会遇到另一个错误。但是,与此同时,conic-gradient()您可以毫无问题地使用变量(当然,如果浏览器支持此功能)。





在后台使用var()时出错:linear-gradient()



问题的原因在于Compass具有自己的linear-gradient()radial-gradient()函数,但函数conic-gradient()从未存在过。



通常,所有这些问题均源于Sass或Compass具有自己的功能,它们的名称与CSS中的名称相同。当满足这些功能时,Sass和Compass都认为我们将使用它们自己的这些功能的实现,而不是标准的实现。



这是伏击!





通过记住Sass区分大小写,而CSS不区分大小写,可以解决此问题。



这意味着您可以这样写,Min(20em, 50vh)而Sass在该结构中不能识别其自身的功能min()。不会产生错误。此构造将是格式正确的CSS,可完全按预期工作。同样,摆脱问题与其他功能就可以了,非标通过写自己的名字的方式:HSL()HSLA()RGB()RGBA()Invert()



对于渐变,我通常使用以下形状:linear-Gradient()radial-Gradient()。我这样做是因为该表示法与SVG中使用的名称接近,但任何其他包含至少一个大写字母的类似名称在这种情况下都可以使用。



为什么所有这些并发症?



几乎每当我发布有关Sass的信息时,我都会得到关于如何使用CSS变量的演讲,而不再需要使用Sass。我决定应该回答这个问题,并解释我不同意这个想法的原因。



首先,我会注意到我发现CSS变量非常有用,并且在过去三年中我将它们用于各种任务。但是我想您需要记住,使用它们会对性能产生影响。在迷宫中寻找问题calc()可能是最不愉快的经历。标准的浏览器开发人员工具还不是很好。我尽量不要迷惑于使用CSS变量,以免陷入劣势比优势更多的情况。





很难理解对这些calc()表达式求值的结果。



通常,如果将变量用作常量,则它不会因元素而,也不因状态而(在这种情况下,CSS变量一定要使用如果需要),或者如果该变量不会减少已编译CSS的数量(解决前缀创建的重复问题),那么我将使用Sass变量。



其次,在我使用Sass的原因中,保持变量一直是一个次要的原因。当我在2012年下半年开始使用Sass时,主要是为了循环。对于CSS仍然缺少的功能。尽管我将一些循环逻辑移到了HTML预处理器中(因为这减少了生成的代码量,并且避免了修改HTML和CSS的需要),但在很多情况下,我仍然使用Sass循环。这些包括生成值列表,创建用于调整梯度的值,在使用函数polygon()时创建点列表,创建转换列表等。



以下是我使用预处理器创建一些HTML元素时本该做的示例。哪个预处理器并不重要,但是我选择了Pug:



- let n = 12;

while n--
  .item


然后,我将$n在Sass中创建一个变量(该变量的值应与HTML中的值相同)并开始使用它的循环,在该循环中,我将生成用于放置每个元素的转换:



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


不利的一面是,如果元素数量发生变化,我将不得不更改Pug代码和Sass代码中的值。另外,代码中有很多重复。





从上面的代码生成的CSS



现在,我采用了另一种方法。即,使用Pug,我将索引生成为自定义属性,然后在声明中使用它们transform



这是Pug计划执行的代码:



- let n = 12;

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


这是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) }
}


可以在此处尝试此代码。





使用循环生成和样式化的元素



使用此方法已大大减少了自动生成CSS的数量。





由上述代码生成的CSS



但是,如果要创建彩虹之类的东西,就不能没有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()) }


是此示例工作版本。





彩色背景



当然,这可以使用Pug变量生成,但是这种方法相对于CSS变量的动态特性没有优势,并且不会减少传输到浏览器的代码量。结果,放弃我过去的习惯对我来说没有任何意义。



我经常使用Sass(和Compass)的内置数学函数,例如三角函数。如今,这些功能已成为CSS规范的一部分,但并非所有浏览器都支持它们。 Sass没有这些功能,但是Compass有,这就是为什么我经常使用Compass的原因。



当然,我可以在Sass中编写自己的此类函数。在Compass支持逆三角函数之前,我一开始就这样做。我确实需要这些函数,所以我自己使用Taylor系列编写了它们。但是如今,指南针具有这些功能。他们比我自己写的要更好,也更有生产力。



数学功能对我来说非常重要,因为我是程序员,而不是艺术家。我的CSS代码中的值通常是通过数学计算生成的。这些不是一些“魔术数字”,也不是纯粹起到美学作用的东西。其用法的一个示例是为以下对象生成一个正则或准正多边形的列表clip-path... 例如,在创建形状不同于矩形的化身或贴纸之类的东西时,将使用此属性。



考虑一个顶点位于一个圆上的正多边形。在下面的示例中拖动滑块(我们可以在此处进行实验)可以让我们看到具有不同数量顶点的形状的点放置位置。





具有三个顶点的形状



这是对应的Sass代码如下所示:



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


请注意,我们在这里使用循环和其他构造,这对于纯CSS而言非常不便。



此示例的稍微高级的版本可能涉及通过向与$oa每个顶点对应的角添加相同的偏移量()来旋转多边形在下面的示例中可以看到这一点此处生成星,它们以相似的方式排列,但始终具有偶数个顶点。此外,每个具有奇数索引的顶点都位于半径小于主圆($f*50%)的圆上





星星



您可以制作出如此有趣的星星。





星号



您可以border使用不寻常的模板创建带有边框()的贴纸示例中,从单个HTML元素创建了一个标签,并且border使用clip-pathSass循环和数学创建了用于自定义的模板实际上,这里有很多计算。





带有复杂边框的贴纸



另一个示例如何为卡片创建背景。在这里,使用模运算符和指数函数在一个循环中,模仿抖动效果来创建背景。





抖动效果



在这里,CSS变量也被大量使用,



接下来,您可以考虑使用mixins来避免在设置类似slider的样式时一遍又一遍地编写相同的声明。不同的浏览器使用不同的伪元素来设置此类控件的内部组件的样式,因此对于每个组件,您需要定义使用不同的伪元素来控制其外观的样式。



不幸的是,在CSS中,听起来很诱人,但是您不能放置以下代码:



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


它不会工作。如果未识别至少一个选择器,则忽略这整套规则。并且,由于在此示例中没有浏览器知道所有三个选择器的存在,因此这些样式将不会应用于任何浏览器。



如果您希望样式有效,则需要执行以下操作:



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


但这可能导致一个事实,即相同的样式在代码中出现了三次。并且,如果您需要更改track属性background,这意味着您必须在中::-webkit-slider-runnable-track,中::-moz-range-track和中编辑样式::-ms-track



解决此问题的唯一明智的方法是使用mixins。样式在已编译的代码中重复,因为没有样式就没有办法,但是现在,至少我们不必在编辑器中输入三次相同的代码。



@mixin track() { /*   */ }

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


结果



我可以得出的主要结论是:Sass in是我们尚不能做的事情。



您使用Sass吗?






All Articles