使用渐变创建条纹背景(以及 Sass Mixin)

Avatar of Kitty Giraudel
Kitty Giraudel 发表

DigitalOcean 为您旅程的每个阶段提供云产品。 立即开始使用 200 美元的免费额度!

以下是 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, lightgreendeepskyblue 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,但这完全取决于您。

您觉得怎么样?

如果您觉得可以使代码更简单,请务必告诉我!感谢您的阅读。 :)