如何通过 Sass 将工具转换成可用的混合宏
为了提高码农的开发效率,现在在线上有很多在线小工具,这些小工具可以帮助大家快速实现自己需要的效果,并且可以生成可用代码。前几天看到一个制作三角的小工具,尝试着使用Sass来将其转换成可用的混合宏。尝试成功,来说说怎么实现的。其实只要你有时间,很多小工具都可以用类似的方法来实现。
工具来源
Caret是Lugo Labs分享的一个制作三角形的在线小工具,在这个小工具中,你只要修改几个参数,就能生成你需要的三角形,如图:
来简单的看一个示例,我们调整几个小参数:
- 三角形大小
- 边框宽度
- 三角形方向
- 边框颜色
- 背景颜色
自动就会生成所需的三角形代码:
.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宽度: 三角形大小
- 边框宽度: 三角形边框大小
- 方向: 三角形超哪个方向,主要有
top
、right
、bottom
和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等提示框一起使用
制作三角形都是依赖于元素的伪类 :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属性top
、left
、border
值不一样。共中最为关键的是border
中的border-width
和border-color
。
由于三角形有空心和实心之分,所以在计算boder-width
的值时,是通过混合宏中$caret-width
和$border-width
差值来决定。
$caret-width - $border-width
当其值为0
时,生成的三角形是实现三角形,反之将是空心三角形。
对于空心三角表,则通过 :before
和 :after
层叠造成的一个假像来实现,如下图:
上图演示的是向下三角形,那么根据 $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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论