以下是 Kitty Giraudel 的客座文章。 Hugo 已经为 CSS-Tricks 撰写过几次文章,包括一篇关于非常聪明的 派计时器 的文章,以及 年鉴 的几篇文章。 我很高兴再次邀请他,这次他将解释一些非常硬核的 Sass 内容及其非常实用的应用。
大家好! 我很高兴再次为 CSS-Tricks 撰写文章并分享一些关于 Sass 的酷技巧! 在过去几周里,我一直在深入试验 Sass 列表。 我发现了很多可能大多数人不知道的东西。
我最近构建了一个 @mixin
来创建条纹。 这个想法是为 mixin 提供一个常规渐变,它会将其转换为条纹渐变。 由于这变成了一件相当复杂的事情,我认为写一篇关于它的文章是个好主意。
让我们从一些关于渐变如何工作的提醒开始。
条纹渐变
当您为渐变提供两个具有相同停止值的连续颜色停止点时,它们之间的过渡会是突然的而不是平滑的。 从技术上讲,它是一个渐变,但颜色之间没有平滑的过渡。 请考虑以下代码
.el {
/* This is smooth */
background: linear-gradient(deepskyblue, tomato);
/* This is striped */
background: linear-gradient(deepskyblue 50%, tomato 50%);
}
您可以设置任意数量的颜色停止点,只要您记住为每个颜色停止点提供与前一个相同的停止值(第一个除外)。
.french-flag {
height: 10em;
width: 15em;
background: linear-gradient(
to right,
blue 33.33%, white 33.33%,
white 66.66%, red 66.66%
);
}
这几乎是您需要了解的关于本文中渐变的所有内容。 如果您碰巧有兴趣深入研究渐变,Ana Tudor 撰写了一篇关于此的 精彩文章。
Sass 列表
让我们从一开始就了解它。 Sass 中的列表与 JavaScript 中的数组非常相似。 要初始化列表:$list: ();
。
请注意,如果您愿意,也可以使用 $list: null;
(甚至 $list: unquote("");
)来初始化它,但请注意 它们是不同的。 无论如何,这是一个非常简单的 Sass 列表
$css-tricks-is: (#b4d455, 42, "awesome");
这变得有点复杂,因为 Sass 语法在列表方面非常宽松。 您可以做很多事情,其中一些事情是不应该做的。 让我们逐一介绍。
您可以省略大括号。
您不必用大括号括起列表,如果愿意,可以完全省略它们。 说实话,我们经常省略它们。
$css-tricks-is: #b4d455, 42, "awesome";
第一个索引是 1
不是像数组那样的 0。 这很不幸,因为它使我们即将推出的示例代码变得更加复杂。 当您使用 nth()
函数操作索引时,了解这一点非常重要。
$item-1: nth($css-tricks-is, 1); // #b4d455
您可以使用空格或逗号分隔值。
两者都完全有效。 我很确定您会更喜欢逗号,因为它是数组值的标准分隔符(JS、PHP…),但如果您愿意,完全可以使用空格。
$css-tricks-is: #b4d455 42 "awesome";
您可以混合使用空格和逗号。
在嵌套列表中,您可以使第一级列表用逗号分隔,而嵌套列表用空格分隔。 在下面的示例中,第三个值是一个用空格分隔的列表。
$css-tricks-is: #b4d455, 42, "awesome" "interesting" "free";
您可以省略字符串周围的引号。
没错,Sass 中的字符串不一定需要加引号。 不要问我为什么。
$css-tricks-is: #b4d455, 42, awesome;
无论如何,我强烈建议您
- 保留大括号
- 使用逗号
- 为字符串加引号
相信我,这会为您节省一些时间。
条纹 Mixin
让我们进入本文的重点:我们的条纹 mixin! 主要思想是利用 Sass 列表可以像渐变中的颜色停止点一样用逗号分隔的事实。 简单来说,像 $list: red 20%, blue 55%
这样的列表可以直接在 linear-gradient()
函数中使用:linear-gradient($list)
输出 linear-gradient(red 20%, blue 55%)
。
因为我们是高手,所以我们希望使其尽可能灵活。 所以
- 我们可以定义颜色停止点的集合
- 如果我们希望所有条纹都具有相同的大小,我们可以定义一个颜色列表
- 我们定义一个方向作为默认值,以便在某些情况下可以省略它
因此,我们需要两件事才能将常规渐变转换为条纹渐变:颜色/颜色停止点的列表(例如 deepskyblue, tomato, lightgreen
或 deepskyblue 20%, tomato 35%, lightgreen 62%
)和一个可选方向。 让我们从框架开始
@mixin stripes($colors, $direction: "to bottom") {
/* Core */
}
对于 $colors
,有 3 种不同的场景可用
- 用户传递一个用逗号分隔的颜色停止点列表:
(deepskyblue 20%, tomato 35%, lightgreen 62%)
, - 用户传递一个用逗号或空格分隔的颜色列表:
(deepskyblue, tomato, lightgreen)
, - 用户传递单个颜色:
deepskyblue
或(deepskyblue)
。
其他所有内容要么会输出无效输出,要么会抛出 Sass 错误。 mixin предназначен для осведомленных разработчиков в среде разработки, поэтому не имеет большого значения, если мы не охватим каждый отдельный крайний случай.
我们必须首先弄清楚我们是在处理颜色列表还是颜色停止点列表。 找出这一点最简单的方法是检查 $color
列表中的第一项(使用 type-of()
)。 如果它是一个列表,那么我们必须处理颜色停止点,否则用户希望所有条纹都具有相同的宽度,这对我们来说非常容易。
不幸的是,我们不能执行 $auto : !(type-of($first-item) == list)
,因为 Sass 无法识别此为有效语法。 因此,为了检查,我们可以使用 if()
Sass 函数,它类似于其他语言中的 var = condition ? true : false
语句。
$auto: if( type-of(nth($colors, 1)) == list, false, true );
总而言之,如果 $auto
为真,则表示所有条纹都将具有相同的大小,因此计算由 Sass 处理。 如果为假,则表示我们必须处理自定义停止点。 在循环遍历颜色之前,我们仍然需要两个变量:一个用于在自动模式下定义条纹的大小;另一个用于在循环过程中存储颜色停止点(稍后在 linear-gradient 函数中使用)。
$stripe-width: 100% / length($colors); /* Only used in auto mode */
$gradient: ();
现在我们可以循环遍历颜色/颜色停止点并将内容添加到我们的 $gradient
变量中。 要向循环添加数字组件,我们使用 @for 循环而不是 @each 循环。 不过,它并没有使事情变得复杂很多。 我们还在循环内部声明了 2 个新变量:一个用于当前项,另一个用于存储当前颜色停止点,然后再将其附加到 $gradient
。
@for $i from 1 through length($colors) {
$item: nth($colors, $i);
$dump: ();
}
事情从这里开始变得复杂。首先,我们必须区分自动模式和硬模式:颜色停止点并不相同。在自动模式下,它们是计算出来的,这意味着在第一次循环运行(当$i
等于1时),“前一个颜色停止点”等于0%($stripe-width * ($i - 1)
)。在硬模式下,我们必须检查是否处于第一次循环运行,因为nth($colors, 0)
是不允许的;它会抛出一个Sass错误。让我们检查一下代码。
@for $i from 1 through length($colors) {
$item: nth($colors, $i);
$dump: ();
/* If we're in auto-mode,
* $item equals a color,
* color-stops are automatically calculated based on $i
*/
@if $auto == true {
$dump: $item $stripe-width * ($i - 1), $item $stripe-width * $i;
/* red 0% , red 50%
* ^ This is what the first loop run would output with a 2 colors gradient
*/
}
/* If we're in hard-mode
*/
@else {
/* We check if it is the first run loop;
* if it isn't, we add the current color with the previous stop
*/
@if $i > 1 {
$previous-item: nth($colors, $i - 1);
$dump: append($dump, nth($item, 1) nth($previous-item, 2));
}
/* No matter what,
* we add the new color stop
*/
$dump: append($dump, $item);
}
/* And no matter what,
* we append $dump to $gradient using join(),
* separating both with a comma by forcing it as a 3rd argument
*/
$gradient: join($gradient, $dump, comma);
}
在循环结束时,我们得到一个格式良好的列表,准备用于线性渐变中。现在我们可以安全地将其用作背景图像。即使使用Compass内置的mixin来输出所有前缀。以下是整个mixin。
@mixin stripes($colors, $direction: "to bottom") {
$stripe-width: 100% / length($colors);
$auto: if( type-of(nth($colors, 1)) == list, false, true );
$gradient: ();
@for $i from 1 through length($colors) {
$item: nth($colors, $i);
$dump: ();
@if $auto == true {
$dump: $item $stripe-width * ($i - 1), $item $stripe-width * $i;
}
@else {
@if $i > 1 {
$previous-item: nth($colors, $i - 1);
$dump: append($dump, nth($item, 1) nth($previous-item, 2));
}
$dump: append($dump, $item);
}
$gradient: join($gradient, $dump, comma);
}
@include background-image(linear-gradient($direction, $gradient));
}
演示
作为演示,我使用了Treehouse博客的标题:由大约50条彩色条纹组成的线条。它看起来非常漂亮。他们目前使用了50个span
元素。哎呦!他们可以使用条纹渐变来代替,现在有了这个mixin,这变得很容易。
我做了两个版本:第一个版本在自动模式下运行,这意味着所有条纹都具有相同的宽度;第二个版本使用自定义颜色停止点来重现Treehouse的效果。

/* Colors only (auto-mode) */
$treehouse-auto: #fa9300, #66c9ee, #c9c9c9, #82b964, #d24d33, #fffbdb, #2e77bb, #6bd5b1, #f87aa0, #c9c9c9, #72664e, #ccd600, #fffbdb, #df620e, #993838, #ff9600, #d24d33, #8960a7, #82b964, #f87aa0, #d43f3f, #668000, #ff9600, #8960a7, #c9c9c9, #993838, #ccd600, #668000, #f4cc13, #72664e, #fa9300, #66c9ee, #c9c9c9, #82b964, #ccd600, #fffbdb, #2e77bb, #6bd5b1, #f87aa0, #c9c9c9, #fa9300, #66c9ee, #c9c9c9, #82b964, #ccd600, #fffbdb, #fa9300;
/* Color-stops (hard-mode) */
$treehouse-hard: #fa9300 2.61%, #66c9ee 4.35%, #c9c9c9 6.96%, #82b964 9.13%, #d24d33 11.3%, #fffbdb 13.91%, #2e77bb 16.52%, #6bd5b1 17.82%, #f87aa0 19.12%, #c9c9c9 21.29%, #72664e 23.9%, #ccd600 26.07%, #fffbdb 28.68%, #df620e 31.29%, #993838 33.03%, #ff9600 34.33%, #d24d33 36.94%, #8960a7 39.55%, #82b964 42.16%, #f87aa0 43.36%, #d43f3f 45.63%, #668000 47.8%, #ff9600 50.41%, #8960a7 51.71%, #c9c9c9 53.88%, #993838 55.18%, #ccd600 57.79%, #668000 59.53%, #f4cc13 60.83%, #72664e 63.44%, #fa9300 66.05%, #66c9ee 67.35%, #c9c9c9 69.96%, #82b964 71.7%, #ccd600 74.31%, #fffbdb 76.92%, #2e77bb 79.53%, #6bd5b1 80.4%, #f87aa0 81.7%, #c9c9c9 83.87%, #fa9300 86.04%, #66c9ee 87.78%, #c9c9c9 90.39%, #82b964 92.56%, #ccd600 95.17%, #fffbdb 97.34%, #fa9300 100%;
/* Using a pseudo-element to display it, no extra markup */
.header:after {
content: '';
position: absolute;
left: 0;
right: 0;
top: 100%;
height: .5em;
// Auto
@include stripes($treehouse-auto, to right);
// Hard
@include stripes($treehouse-hard, to right);
}
因此,您可以在以下笔的顶部看到自动模式,在底部看到硬模式。后者看起来肯定更好。
Check out this Pen!
另一个用例可能是帮助实现等高流体宽度列技巧(参见Doug Neiner方法)。
总结
我认为我们团队已经完成了。如果您更喜欢函数而不是mixin,则可以轻松地进行编辑:只需将@mixin
更改为@function
,并将背景图像行更改为类似@return linear-gradient(#{$gradient}, #{$linear})
的内容,然后使用background-image: stripes($colors)
。我个人更喜欢使用mixin,但这完全取决于您。
您觉得怎么样?
如果您觉得可以使代码更简单,请务必告诉我!感谢您的阅读。 :)
我宁愿使用50个带背景色的span,也不愿使用如此大量的渐变。
哈哈,好吧,尽管试试。
我想知道哪种方法实际上代码更多/更少,渲染效率更高/更低,以及浏览器兼容性更好/更差。
@michelle 在我看来,如果您需要最后一个示例的结果,背景图像可能是最佳解决方案。
此示例开启了您可以使用Sass的数百个可能的项目,现在将3D CSS3与之结合以获得一些惊人的效果。很棒的文章。
@Daniele 我同意。尽管许多纯CSS解决方案都很酷,但在很多情况下,普通图像在性能、实现和可维护性方面都更好。
虽然这是一个很棒的SASS高级示例,但如果我们可以计算得出混合停止百分比(而不是列出它们),那么它将远远优于50个span的解决方案。
我喜欢上面的CSS渐变示例,当然,如果这不可能,我想我会退回到图像。但是Peter的评论让我很想进行头脑风暴。还有哪些其他疯狂的方法可以做到这一点?
使用nth-of-type样式化的LI列表
滥用下划线进行排版(负字间距、粗体,可能在更大的容器中溢出:隐藏)
其中一个盒子阴影技巧
2,000,000个浮动且着色的1x1px div
Flash :P
抛开这些不靠谱的:Hugo,精彩的阅读!
一旦函数编写完成,您就可以开始使用了,这实际上会更快,而且它可以完美地处理响应式和视网膜内容,尤其是与背景图像相比。
我实际上同意。使用Zen编码,您可以在几秒钟内完成。
@Chris:在听了几个Shop Talk播客后,当我阅读您的评论时,我完全听到了您的声音。(别再出现在我脑海里了!)
我也是……
这太棒了,感谢分享,Hugo!
现在我们只需要在其之上创建一个函数,该函数根据我们想要的颜色数量生成随机颜色停止点,它将是有史以来最好的Sass函数。
嘿,好主意!问题是Sass无法生成随机数。实际上,使用额外的ruby gem(例如这个:http://stackoverflow.com/a/8692220/1705630)可以做到,但不能直接在Sass中实现。
无论如何,我肯定应该尝试一下。 :)
关于使用空格作为分隔符。我非常懒惰,所以我做了很多次。这就是我发现像这样的列表
$l: 5 -$a 7
无法正常工作的方式 - 测试(第二个,带旋转变换的那个)。巧妙的想法,使用mixin使构建条纹更容易。(我绝对认为渐变或其他类型的背景图像比五十个
<div>
要好得多。)只是一些想法您无需使用
if(condition, false, true)
来模拟!
- Sass中的!
运算符是not
。因此,您只需要另一种方法是
它会根据长度检查它是否为列表。(要添加到您的列表怪异性列表中的另一个怪异之处是,单个值可以在很多地方被视为单项列表,例如列表函数。)
字符串在Sass中可以不带引号的原因是,只要它们不包含任何奇怪的字符,它们就可以在CSS中不带引号。
我认为能够使用空格或逗号来引用列表很方便,因为这正是CSS的工作方式。CSS中的元组(例如,背景速记的值列表)以空格分隔,而它们的组(例如,同一速记的多个值集)以逗号分隔。在Sass中,您可以使用括号将列表嵌套到任意深度。
嘿,检查$auto是真还是假的一些巧妙想法,我喜欢这个。非常感谢您的提示,Paul。;)
没问题!我现在一直在做大量令人作呕的Sass工作,做了一些您永远不应该在预处理器语言中做的事情,并且在此过程中获得了很多提示。
这真是太棒了,感谢分享。我还没有完全理解,因为我仍然是新手,但我正在努力学习。另外,这些笔是否需要登录Codepen才能正常工作?因为我得到一个男人拿着放大镜的图片,上面写着“这里什么也没有”。
我的大脑爆炸了……我想我需要再读一遍!
Treehouse使用span是因为兼容性问题。整个东西在Safari中无法正常工作:(
您正在运行哪个版本的Safari?我相当确定这是一个供应商前缀的问题。
这些示例在最新iOS(6.1.4)的iPhone5上的Safari上似乎根本无法工作。如果这确实是前缀的问题,您能否修复代码笔?文章不必提及它们,但如果演示在开发人员用来阅读此文章的现代浏览器上实际有效,则会使其更具吸引力,否则您会让我认为这是一个我甚至无法实际用于开发人员受众的CSS功能。
感谢您撰写这篇精彩的文章,很高兴再次阅读您的文章。
我认为这是因为 Safari 仍然使用旧的渐变语法。我建议您使用 Prefix-free、Bourbon 或 Compass 来处理这种情况。
不过我很好奇。当使用 Prefix-free 或 Compass 时,渐变应该在 CodePen 中添加前缀。我需要仔细研究一下。
编辑:Ana Tudor 复制了我的笔,以添加对旧语法的支持:http://codepen.io/thebabydino/pen/LDwGt。
哈哈 @ “Go for it” 喜欢它。
*** 阅读后从此处删除以下内容 ***
Chris(或版主)在博客首页上“striped”拼写错误,应该是“stripped”——别因为我是一个词语狂而讨厌我。我喜欢这个网站,不希望任何人对你们有不好的看法;)
既然我们处于语法纳粹模式:later != latter
而且不要让我开始说你犯了多少次“colour”错误……
@Jimmy:既然我们处于语言纳粹模式,我不得不指出 Chris 没有拼错“colour”,因为他是一个美国人,而“color”在美国是可以接受的拼写:-)毕竟,让我们面对现实:英语拼写本来就很乱。
这很酷,但是我理解这可能会给旧版浏览器带来问题。不要误解我的意思,这是一篇很棒的小文章,但目前我宁愿使用“background-image… repeat…”。
确实,但是为什么不能对旧版浏览器使用回退技术呢?我认为更多的开发者需要拥抱新技术,才能正确地推动 HTML5/CSS3 的发展,并将其完全推向市场并付诸实践。
如果人们从未使用过新技术,我们就无法发展。
好吧,首先,这永远不会在旧版浏览器中造成问题。在最坏的情况下,渐变根本不会显示。由于这显然是一个图形元素,所以没什么大不了的。
现在正如 Richard 所说,这是渐进增强。为旧版浏览器提供图像甚至平面边框,而为现代浏览器提供此解决方案。这可以为支持渐变的浏览器节省一个 HTTP 请求;这是一件大事。
我刚刚开始在我的网站上使用 CSS 渐变(不像这些那么复杂),但我很难让它们在 IE 中看起来正确——我知道,我知道……哈哈
尽管如此,我的大部分受众仍在使用 IE,因此我对此表示担忧。
Hugo,您在这篇文章中编写的所有内容在跨浏览器和向后版本兼容性方面如何?
干杯,
~Steve
本文中的所有内容都只是由于 Sass 而产生的语法糖,因此不存在任何兼容性问题。
但是,我们正在处理渐变,不幸的是,Internet Explorer 9 及更低版本不支持渐变。对此你无能为力。通常,我们只是为旧版浏览器(如 IE)提供一些回退。
在这种情况下,我认为无论如何我都会使用实线边框,然后在其上放置一个渐变伪元素以供支持的浏览器使用。
这是一个带有注释的快速且粗略的概念验证:http://jsfiddle.net/kxjpk/
我没有使用这些函数,但文章的第一部分启发我制作了英国国旗的 CSS 渐变版本。我认为效果还不错。棘手的地方是如何处理非对称的对角线条纹 http://cdpn.io/GAKty