如何通过 Sass 将工具转换成可用的混合宏

发布于 2021-12-20 12:51:14 字数 21455 浏览 997 评论 0

为了提高码农的开发效率,现在在线上有很多在线小工具,这些小工具可以帮助大家快速实现自己需要的效果,并且可以生成可用代码。前几天看到一个制作三角的小工具,尝试着使用Sass来将其转换成可用的混合宏。尝试成功,来说说怎么实现的。其实只要你有时间,很多小工具都可以用类似的方法来实现。

工具来源

Caret

CaretLugo Labs分享的一个制作三角形的在线小工具,在这个小工具中,你只要修改几个参数,就能生成你需要的三角形,如图:

Caret

来简单的看一个示例,我们调整几个小参数:

  • 三角形大小
  • 边框宽度
  • 三角形方向
  • 边框颜色
  • 背景颜色

自动就会生成所需的三角形代码:

.caret {
  position: relative;
}

.caret:before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  border-top: 50px solid #9a1b1b;
  border-left: 50px solid transparent;
  border-right: 50px solid transparent;
}

.caret:after {
  content: '';
  position: absolute;
  left: 5px;
  top: 0;
  border-top: 45px solid #ece6e1;
  border-left: 45px solid transparent;
  border-right: 45px solid transparent;
}

实现原理这里就不多说了,就是使用 border 和伪类 :after:before 来实现。

工具分析

从 Caret 小工具中可以非常明显的得知,制作三角形只需要五个参数:

  • Caret宽度: 三角形大小
  • 边框宽度: 三角形边框大小
  • 方向: 三角形超哪个方向,主要有 toprightbottom 和 left 四个方向
  • 颜色: 边框颜色,也是实心三角形的颜色
  • 背景颜色: 制作空心三角形的内部颜色

文章开头的图中,可以获悉,三角形分为两种,一种是实心三角形,另一种是空心三角形。当边框大小和Caret宽度相等时三角形呈一个实心三角形,另外当背景颜色和边框颜色相同时,也会呈实心三角形。只有这两种情形都不具备之时,才会是一个空心三角形。

定义混合宏 caret

如果要实现一个类似于 caret 工具的混合宏,也需要给这个混合宏传相同的参数。假设定义的混合宏名 caret,给混合宏传递的参数有:

  • $caret-width用来设置三角形的大小
  • $border-width设置边框的大小
  • $direction设置三角形方向
  • $border-color设置边框的颜色
  • $background-color设置背景颜色

除此之外,在工具的基础我们添加另一个参数$position用来控制三角形的定位形式。

如此一来,caret的混合宏所传的参数就有六个:

@mixin caret($position, $caret-width, $border-width, $direction, $border-color, $background-color){
    ...
}

三角形在 Web 使用中常见的地方,主要会有:

  • 代表方向性,比如说向下,向左,向上,向右等,这些三角形是不做定位处理,常常是跟在某个元素之后
  • 跟tooltip和Popover等提示框一起使用

Caret

制作三角形都是依赖于元素的伪类 :before 和 :after 来实现,而且都是通过绝对定位来控制三角形。

@mixin caret($position,$caret-width,$border-width,$direction,$border-color,$background-color){
  position: $position;

  &:before,
  &:after {
    content:"";
    position: absolute;
  }
}

注:由于我们三角形同时需要实现空心和实心两种三角形风格,因此在这个混合宏中同时使用了:before:after

三角形方向有四种方向,因此使用Sass的@if{}@else if{}根据$direction参数传的值来判断三角形的方向。而且每个方向的不同时,对应的CSS属性topleftborder值不一样。共中最为关键的是border中的border-widthborder-color

由于三角形有空心和实心之分,所以在计算boder-width的值时,是通过混合宏中$caret-width$border-width差值来决定。

$caret-width - $border-width

当其值为0时,生成的三角形是实现三角形,反之将是空心三角形。

对于空心三角表,则通过 :before:after 层叠造成的一个假像来实现,如下图:

Caret

上图演示的是向下三角形,那么根据 $direction 传递的参数,根据同样的原理,可以得到:

@mixin caret($position,$caret-width,$border-width,$direction,$border-color,$background-color){
  position: $position;

  &:before,
  &:after {
    content:"";
    position: absolute;
  }
  @if $direction == top {
    &:before {
      top:0;
      left: 0;
      border-bottom: $caret-width solid $border-color;
      border-left: $caret-width solid transparent;
      border-right: $caret-width solid transparent;
    }
    &:after {
      left: $border-width;
      top: $border-width;
      border-bottom: ($caret-width - $border-width) solid $background-color;
      border-left: ($caret-width - $border-width) solid transparent;
      border-right: ($caret-width - $border-width) solid transparent;
    }
  }
  @else if $direction == right {
    &:before {
      top:0;
      left: 0;
      border-left: $caret-width solid $border-color;
      border-top: $caret-width solid transparent;
      border-bottom: $caret-width solid transparent;
    }
    &:after {
      left: 0;
      top: $border-width;
      border-left: ($caret-width - $border-width) solid $background-color;
      border-top: ($caret-width - $border-width) solid transparent;
      border-bottom: ($caret-width - $border-width) solid transparent;
    }
  }
  @else if $direction == bottom {
    &:before {
      top:0;
      left: 0;
      border-top: $caret-width solid $border-color;
      border-left: $caret-width solid transparent;
      border-right: $caret-width solid transparent;
    }
    &:after {
      left: $border-width;
      top: 0;
      border-top: ($caret-width - $border-width) solid $background-color;
      border-left: ($caret-width - $border-width) solid transparent;
      border-right: ($caret-width - $border-width) solid transparent;
    }
  } 
  @else if $direction == left {
    &:before {
      top:0;
      left: 0;
      border-right: $caret-width solid $border-color;
      border-top: $caret-width solid transparent;
      border-bottom: $caret-width solid transparent;
    }
    &:after {
      left: $border-width;
      top: $border-width;
      border-right: ($caret-width - $border-width) solid $background-color;
      border-top: ($caret-width - $border-width) solid transparent;
      border-bottom: ($caret-width - $border-width) solid transparent;
    }
  }
}

示例

混合宏完成了,实战一回。

假设你需要制作一个 tips,可以简单的像这样使用:

HTML

<div class="tips">
  <span class="caret"></span>
  我是一个tooltip
</div>

SCSS

.tips {
  width: 200px;
  height: 50px;
  line-height: 50px;
  text-align: center;
  position: relative;
  margin: 20px auto;
  border: 1px solid orange;
  border-radius: 3px;

  .caret {
    top: -10px;
    left: 10px;
    @include caret(absolute,10px,1px,top,orange,#fff);
  }
}

效果

Sass

// ----
// Sass (v3.4.12)
// Compass (v1.0.3)
// ----

@mixin caret($position,$caret-width,$border-width,$direction,$border-color,$background-color){
  position: $position;
  
  &:before,
  &:after {
    content:"";
    position: absolute;
  }
  @if $direction == top {
    &:before {
      top:0;
      left: 0;
      border-bottom: $caret-width solid $border-color;
      border-left: $caret-width solid transparent;
      border-right: $caret-width solid transparent;
    }
    &:after {
      left: $border-width;
      top: $border-width;
      border-bottom: ($caret-width - $border-width) solid $background-color;
      border-left: ($caret-width - $border-width) solid transparent;
      border-right: ($caret-width - $border-width) solid transparent;
    }
  }
  @else if $direction == right {
    &:before {
      top:0;
      left: 0;
      border-left: $caret-width solid $border-color;
      border-top: $caret-width solid transparent;
      border-bottom: $caret-width solid transparent;
    }
    &:after {
      left: 0;
      top: $border-width;
      border-left: ($caret-width - $border-width) solid $background-color;
      border-top: ($caret-width - $border-width) solid transparent;
      border-bottom: ($caret-width - $border-width) solid transparent;
    }
  }
  @else if $direction == bottom {
    &:before {
      top:0;
      left: 0;
      border-top: $caret-width solid $border-color;
      border-left: $caret-width solid transparent;
      border-right: $caret-width solid transparent;
    }
    &:after {
      left: $border-width;
      top: 0;
      border-top: ($caret-width - $border-width) solid $background-color;
      border-left: ($caret-width - $border-width) solid transparent;
      border-right: ($caret-width - $border-width) solid transparent;
    }
  } 
  @else if $direction == left {
    &:before {
      top:0;
      left: 0;
      border-right: $caret-width solid $border-color;
      border-top: $caret-width solid transparent;
      border-bottom: $caret-width solid transparent;
    }
    &:after {
      left: $border-width;
      top: $border-width;
      border-right: ($caret-width - $border-width) solid $background-color;
      border-top: ($caret-width - $border-width) solid transparent;
      border-bottom: ($caret-width - $border-width) solid transparent;
    }
  }
}
.tips {
  width: 200px;
  height: 50px;
  line-height: 50px;
  text-align: center;
  position: relative;
  margin: 20px auto;
  border: 1px solid orange;
  border-radius: 3px;
  
  .caret {
    top: -10px;
    left: 10px;
    @include caret(absolute,10px,1px,top,orange,#fff);
  }
}

CSS

.tips {
  width: 200px;
  height: 50px;
  line-height: 50px;
  text-align: center;
  position: relative;
  margin: 20px auto;
  border: 1px solid orange;
  border-radius: 3px;
}
.tips .caret {
  top: -10px;
  left: 10px;
  position: absolute;
}
.tips .caret:before, .tips .caret:after {
  content: "";
  position: absolute;
}
.tips .caret:before {
  top: 0;
  left: 0;
  border-bottom: 10px solid orange;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
}
.tips .caret:after {
  left: 1px;
  top: 1px;
  border-bottom: 9px solid #fff;
  border-left: 9px solid transparent;
  border-right: 9px solid transparent;
}

下面的示例中,演示了其他几种三种形式:

Sass

// ----
// Sass (v3.4.12)
// Compass (v1.0.3)
// ----

@mixin caret($position,$caret-width,$border-width,$direction,$border-color,$background-color){
  position: $position;
  
  &:before,
  &:after {
    content:"";
    position: absolute;
  }
  
  @if $direction == bottom {
    &:before {
      top:0;
      left: 0;
      border-top: $caret-width solid $border-color;
      border-left: $caret-width solid transparent;
      border-right: $caret-width solid transparent;
    }
    &:after {
      left: $border-width;
      top: 0;
      border-top: ($caret-width - $border-width) solid $background-color;
      border-left: ($caret-width - $border-width) solid transparent;
      border-right: ($caret-width - $border-width) solid transparent;
    }
  } @else if $direction == top {
    &:before {
      top:0;
      left: 0;
      border-bottom: $caret-width solid $border-color;
      border-left: $caret-width solid transparent;
      border-right: $caret-width solid transparent;
    }
    &:after {
      left: $border-width;
      top: $border-width;
      border-bottom: ($caret-width - $border-width) solid $background-color;
      border-left: ($caret-width - $border-width) solid transparent;
      border-right: ($caret-width - $border-width) solid transparent;
    }
  } @else if $direction == left {
    &:before {
      top:0;
      left: 0;
      border-right: $caret-width solid $border-color;
      border-top: $caret-width solid transparent;
      border-bottom: $caret-width solid transparent;
    }
    &:after {
      left: $border-width;
      top: $border-width;
      border-right: ($caret-width - $border-width) solid $background-color;
      border-top: ($caret-width - $border-width) solid transparent;
      border-bottom: ($caret-width - $border-width) solid transparent;
    }
  } @else if $direction == right {
    &:before {
      top:0;
      left: 0;
      border-left: $caret-width solid $border-color;
      border-top: $caret-width solid transparent;
      border-bottom: $caret-width solid transparent;
    }
    &:after {
      left: 0;
      top: $border-width;
      border-left: ($caret-width - $border-width) solid $background-color;
      border-top: ($caret-width - $border-width) solid transparent;
      border-bottom: ($caret-width - $border-width) solid transparent;
    }
  }
}

.box {
  width: 100px;
  height: 100px;
  margin: 20px;
  border: 1px solid orange;
  display: inline-block;
  background: orange;
  position: relative;
  vertical-align: middle;
  
  &.box2 {
    background-color: transparent;
    border: 1px solid orange;
  }
  
  .caret-top {
    bottom: 9px;
    left: 20px;
    @include caret(absolute,10px,1px,top,orange,#fff);
  }
  .caret-right {
    left: -1px;
    top: 20px;
    @include caret(absolute,10px,1px,right,orange,#fff);
  }
  .caret-bottom {
    top: -1px;
    left: 20px;
    @include caret(absolute,10px,1px,bottom,orange,#fff);
  }
  .caret-left {
    right: 9px;
    top: 20px;
    @include caret(absolute,10px,1px,left,orange,#fff);
  }
}

.tip{
  width: 150px;
  height: 50px;
  background: #000;
  border-radius:3px;
  position: relative;
  display: inline-block;
  vertical-align: middle;
  margin: 20px;
  
  .caret-top{
    top: -10px;
    left: 10px;
    @include caret(absolute,10px,1px,top,#000,#000);
  }
  .caret-right{
    top: 10px;
    right: 0px;
    @include caret(absolute,10px,1px,right,#000,#000);
  }
  .caret-bottom{
    bottom: 0px;
    left: 10px;
    @include caret(absolute,10px,1px,bottom,#000,#000);
  }
  .caret-left{
    left: -10px;
    top: 10px;
    @include caret(absolute,10px,1px,left,#000,#000);
  }
}
.tip2 {
  background-color: transparent;
  border: 1px solid #000;
  
  .caret-top {
    @include caret(absolute,10px,1px,top,#000,#fff);
  }
  .caret-right {
    @include caret(absolute,10px,1px,right,#000,#fff);
  }
  .caret-bottom {
    @include caret(absolute,10px,1px,bottom,#000,#fff);
  }
  .caret-left {
    @include caret(absolute,10px,1px,left,#000,#fff);
  }
}

CSS

.box {
  width: 100px;
  height: 100px;
  margin: 20px;
  border: 1px solid orange;
  display: inline-block;
  background: orange;
  position: relative;
  vertical-align: middle;
}
.box.box2 {
  background-color: transparent;
  border: 1px solid orange;
}
.box .caret-top {
  bottom: 9px;
  left: 20px;
  position: absolute;
}
.box .caret-top:before, .box .caret-top:after {
  content: "";
  position: absolute;
}
.box .caret-top:before {
  top: 0;
  left: 0;
  border-bottom: 10px solid orange;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
}
.box .caret-top:after {
  left: 1px;
  top: 1px;
  border-bottom: 9px solid #fff;
  border-left: 9px solid transparent;
  border-right: 9px solid transparent;
}
.box .caret-right {
  left: -1px;
  top: 20px;
  position: absolute;
}
.box .caret-right:before, .box .caret-right:after {
  content: "";
  position: absolute;
}
.box .caret-right:before {
  top: 0;
  left: 0;
  border-left: 10px solid orange;
  border-top: 10px solid transparent;
  border-bottom: 10px solid transparent;
}
.box .caret-right:after {
  left: 0;
  top: 1px;
  border-left: 9px solid #fff;
  border-top: 9px solid transparent;
  border-bottom: 9px solid transparent;
}
.box .caret-bottom {
  top: -1px;
  left: 20px;
  position: absolute;
}
.box .caret-bottom:before, .box .caret-bottom:after {
  content: "";
  position: absolute;
}
.box .caret-bottom:before {
  top: 0;
  left: 0;
  border-top: 10px solid orange;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
}
.box .caret-bottom:after {
  left: 1px;
  top: 0;
  border-top: 9px solid #fff;
  border-left: 9px solid transparent;
  border-right: 9px solid transparent;
}
.box .caret-left {
  right: 9px;
  top: 20px;
  position: absolute;
}
.box .caret-left:before, .box .caret-left:after {
  content: "";
  position: absolute;
}
.box .caret-left:before {
  top: 0;
  left: 0;
  border-right: 10px solid orange;
  border-top: 10px solid transparent;
  border-bottom: 10px solid transparent;
}
.box .caret-left:after {
  left: 1px;
  top: 1px;
  border-right: 9px solid #fff;
  border-top: 9px solid transparent;
  border-bottom: 9px solid transparent;
}

.tip {
  width: 150px;
  height: 50px;
  background: #000;
  border-radius: 3px;
  position: relative;
  display: inline-block;
  vertical-align: middle;
  margin: 20px;
}
.tip .caret-top {
  top: -10px;
  left: 10px;
  position: absolute;
}
.tip .caret-top:before, .tip .caret-top:after {
  content: "";
  position: absolute;
}
.tip .caret-top:before {
  top: 0;
  left: 0;
  border-bottom: 10px solid #000;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
}
.tip .caret-top:after {
  left: 1px;
  top: 1px;
  border-bottom: 9px solid #000;
  border-left: 9px solid transparent;
  border-right: 9px solid transparent;
}
.tip .caret-right {
  top: 10px;
  right: 0px;
  position: absolute;
}
.tip .caret-right:before, .tip .caret-right:after {
  content: "";
  position: absolute;
}
.tip .caret-right:before {
  top: 0;
  left: 0;
  border-left: 10px solid #000;
  border-top: 10px solid transparent;
  border-bottom: 10px solid transparent;
}
.tip .caret-right:after {
  left: 0;
  top: 1px;
  border-left: 9px solid #000;
  border-top: 9px solid transparent;
  border-bottom: 9px solid transparent;
}
.tip .caret-bottom {
  bottom: 0px;
  left: 10px;
  position: absolute;
}
.tip .caret-bottom:before, .tip .caret-bottom:after {
  content: "";
  position: absolute;
}
.tip .caret-bottom:before {
  top: 0;
  left: 0;
  border-top: 10px solid #000;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
}
.tip .caret-bottom:after {
  left: 1px;
  top: 0;
  border-top: 9px solid #000;
  border-left: 9px solid transparent;
  border-right: 9px solid transparent;
}
.tip .caret-left {
  left: -10px;
  top: 10px;
  position: absolute;
}
.tip .caret-left:before, .tip .caret-left:after {
  content: "";
  position: absolute;
}
.tip .caret-left:before {
  top: 0;
  left: 0;
  border-right: 10px solid #000;
  border-top: 10px solid transparent;
  border-bottom: 10px solid transparent;
}
.tip .caret-left:after {
  left: 1px;
  top: 1px;
  border-right: 9px solid #000;
  border-top: 9px solid transparent;
  border-bottom: 9px solid transparent;
}

.tip2 {
  background-color: transparent;
  border: 1px solid #000;
}
.tip2 .caret-top {
  position: absolute;
}
.tip2 .caret-top:before, .tip2 .caret-top:after {
  content: "";
  position: absolute;
}
.tip2 .caret-top:before {
  top: 0;
  left: 0;
  border-bottom: 10px solid #000;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
}
.tip2 .caret-top:after {
  left: 1px;
  top: 1px;
  border-bottom: 9px solid #fff;
  border-left: 9px solid transparent;
  border-right: 9px solid transparent;
}
.tip2 .caret-right {
  position: absolute;
}
.tip2 .caret-right:before, .tip2 .caret-right:after {
  content: "";
  position: absolute;
}
.tip2 .caret-right:before {
  top: 0;
  left: 0;
  border-left: 10px solid #000;
  border-top: 10px solid transparent;
  border-bottom: 10px solid transparent;
}
.tip2 .caret-right:after {
  left: 0;
  top: 1px;
  border-left: 9px solid #fff;
  border-top: 9px solid transparent;
  border-bottom: 9px solid transparent;
}
.tip2 .caret-bottom {
  position: absolute;
}
.tip2 .caret-bottom:before, .tip2 .caret-bottom:after {
  content: "";
  position: absolute;
}
.tip2 .caret-bottom:before {
  top: 0;
  left: 0;
  border-top: 10px solid #000;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
}
.tip2 .caret-bottom:after {
  left: 1px;
  top: 0;
  border-top: 9px solid #fff;
  border-left: 9px solid transparent;
  border-right: 9px solid transparent;
}
.tip2 .caret-left {
  position: absolute;
}
.tip2 .caret-left:before, .tip2 .caret-left:after {
  content: "";
  position: absolute;
}
.tip2 .caret-left:before {
  top: 0;
  left: 0;
  border-right: 10px solid #000;
  border-top: 10px solid transparent;
  border-bottom: 10px solid transparent;
}
.tip2 .caret-left:after {
  left: 1px;
  top: 1px;
  border-right: 9px solid #fff;
  border-top: 9px solid transparent;
  border-bottom: 9px solid transparent;
}

结论

使用 Sass 实现 三角形的方案 多种,但这篇文章仅仅是想向大家介绍的是如何使用 Sass 这样的预处理器,将在线的小工具转换成实用的混合宏。如果您对此感兴趣,可以自己动手试试别的小工具。欢迎在下面的评论中与我们一起分享你定义的混合宏。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

晚风撩人

暂无简介

0 文章
0 评论
24509 人气
更多

推荐作者

lorenzathorton8

文章 0 评论 0

Zero

文章 0 评论 0

萧瑟寒风

文章 0 评论 0

mylayout

文章 0 评论 0

tkewei

文章 0 评论 0

17818769742

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文