gmfe / Think

观麦前端团队的官方博客
68 stars 3 forks source link

一个由CSS绘制三角标而引发的思考 #3

Open fondadam opened 7 years ago

fondadam commented 7 years ago

背景

在网页中,随处可见各种三角标(小三角): tooltip提示框下拉菜单返回顶部按钮 ... 其中的实现方案也各式各样,虽然看起来很简单,但哪一个才是最适合我们当下需求的呢?

最近,团队内部React组件库中的某个组件(Trigger),需要给其浮层添加一个三角标,秉着再小的需求也要一个方案的原则,在这里给大家分享分享我实现这个三角标的思路以及记录下来的一些知识点。

需求list

  1. 添加三角标相当于是组件Trigger的一个patch,因此这个必须是向后兼容的。
  2. 组件Trigger可通过参数控制其浮层所在位置,那么这个三角标也要随之定位。
  3. 三角标与浮层间的样式过渡不应该是突兀的。
  4. 三角标与浮层间不应该有相互侵入的地方。注意控制好z-index、padding、margin等

实现方案

摸清楚大致需求后,我们先将细节放一边,从简单的入手: 绘制一个实心三角。

border实现

对于纯CSS来说,最容易想到便是使用border来实现三角形的绘制,只要控制好border四条边的样式,别说上下左右朝向的三角,甚至是各种直三角、等腰三角都能轻而易举。

<div class="demo"></div>
.demo {
    width: 0;
    height: 0;
    border-width: 10px; 
    border-color: #000 transparent transparent; 
    border-style: solid;
}

优点: 简单、快捷、兼容性好 缺点: 因为使用的是border,所以对一些阴影、渐变的添加可能难以达到你想要的效果

transform实现

创建一个正方形的元素A,里面再使用伪元素创建一个被旋转了45度的正方形元素B,同时将A设置成overflow: hidden,元素B则通过定位溢出,便可完美实现一个三角标。

<div class="demo"></div>
.demo {
    position: relative;
    width: 100px;
    height: 100px;
    background-color: transparent;
    overflow: hidden;
}
.demo:after {
    position: absolute;
    content: "";
    background-color: #F00;
    width: 100px;
    height: 100px;
    top: -70%;
    transform: rotate(45deg)
}

优点: 暂时没想到什么优点,就是复杂了些,但绘制其他复杂图形用此方法倒是挺不错的 缺点: 使用了CSS3(PS: IE6/7/8现在基本不考虑了吧,再说还有postcss

图片法

图片转换成base64编码 优点: 随意设计,想要怎么样的三角就怎样的三角 缺点: 对于较大的图片,一长串的字符串看着也闹心 (PS: 你需要先设计一个图片)

字符

使用字符如▲、▶、▼、◀,你可以用text-shadow属性添加阴影, 但可惜最多只能某两条边。 优点: 快 缺点: 可控性差

当然,要是觉得有趣,可以尝试用Canvas、SVG去实现。


进一步实现

从技术角度来看,有非常多的方案,毕竟这也是一个老掉牙的话题了。但作为一个通用组件的patch,需要考虑的地方还是很多的。因组件库使用的是React,在这里我将会从React的角度去举例。

trigger_demo2

正因为三角标的小,所以1px的差异都会显得那么突兀,但稍微修正一下,再下移那么一点不就可以遮挡住浮层边框,完美实现浮层的提示小三角了吗? 看起来貌似基本实现需求了,但若产品说这样实心三角不好看,要设置成空心的,类似这样:

trigger_demo

trigger_demo3 看到被三角标遮挡住的D了吗?

你也许会说,那通过控制z-index使浮层遮挡住正方形的话,这样不就没有侵入了吗?但是这样浮层和三角标间的border就被暴露出来了。

最终实现

为了组件的调用方便,我们应该暴露诸如arrowBgColorarrowBorderColor这样的参数给调用者,方便直接修改三角标的border和背景,而不应该单纯暴露arrowStyle这样的参数给调用者自己去修改样式,这样会显得麻烦而且也没必要暴露。

<Trigger 
    showArrow 
    arrowBgColor="#FFF"
    arrowBorderColor='#000'
>
    <Button />
</Trigger>

trigger_demo4

总结

  1. 作为一个通用组件的patch, 一定要做好向后兼容。
  2. 把握好元素间的层级关系。(传送门:深入理解CSS中的层叠上下文和层叠顺序
  3. 要时不时求证该技术方案的合理性, 不能单纯地以为实现了想要的效果就完事了。