用SVG实现一个优雅的提示框

前言

Tooltips常被称为提示框(或信息提示框),提示框可以以较强的交互性、自由度为用户提供相应的提示信息。今天咱们要聊的不是如何实现强大的交互行为,而是来看看如何以最好的方式来还原他们的视觉效果,而且能适用于不一样的场景。css

背景

上图是从平时工做场景碰到的UI效果截图过来的。上图中展现的Tooltips框基本上覆盖了常见的UI风格。简单的来概括一下:html

  • 带边框的提示框
  • 纯色(或带透明度纯色)的提示框
  • 带内阴影(或外阴影)的提示框
  • 带边框+渐变的提示框
  • 带边框+透明度背景的提示框
  • 提示框三角带圆角和阴影的提示框

可能还有我未碰到的提示框UI风格。面对这么多的UI风格,对于前端实现上来讲是具备必定的挑战性,特别是多种效果组合在一块儿的。好比说,带有边框+内外阴影+渐变(或透明度)+圆角三角等。基本上组合了上图所提到的各类UI风格。前端

clip-path方案

一般上图的实现是使用CSS画个尖角来拼接上去,比较优秀的方案以下图:css3

咱们简单介绍下clip-path方案:canvas

把提示框分红两个部分,一个是四方形,一个是三角形,而后两个拼接在一块儿组合成一个提示框。这样整个坐标示意图以下:markdown

假设提示框的尺寸是w x h,边框厚度是h1,那么绘制带有缺口的时须要如下几个坐标点:app

``svg

  • d1坐标(0, 0)
  • d2坐标((50% - b), 0)((w / 2 - b), 0) 其中b是三角形对角边长度的一半,后面会介绍到
  • d3坐标((50% - b - h1), h1)((w / 2 - b - h1), h1)
  • d4坐标((50% + b + h1), h1)((w / 2 + b + h1), h1)
  • d5坐标((50% + b), 0)((w / 2 + b), 0)
  • d6坐标(100%, 0)(w, 0)
  • d7坐标(100%, 100%)(w, h)
  • d8坐标(0, 100%)(0, h)

``wordpress

坐标点放置到clip-pathpolygon()函数中,最终剪切以后的图形看上去像下图函数

clip-path: polygon(    0 0,    calc(50% - 4px) 0,    calc(50% - 7px) 2px,    calc(50% + 7px) 2px,     calc(50% + 4px) 0,     100% 0,     100% 100%,      0 100%,    0 0);
复制代码

另外就是三角形的部分,若是咱们的三角形是一个 10px x 10px 旋转 45deg 获得。根据一些三角函数的公式和已知的正方形边长就能够计算出正方形斜对角的长度:

clip-path方案碰到问题

这个效果总体看起来仍是不错的,可是细看就会发如今接缝处或许会存在有空隙、有重叠的问题,以下图:

采用vw方案后这类像素对不齐的问题也算是司空见惯了,同时第一个Tooltips因为是背景须要从左到右渐变的,此时尖角的渐变过分要和下方的渐变匹配上就更须要费力气了。

因为先前就遇到过此类ToolTip样式问题,告知视觉同窗后,体贴的视觉同窗修改了一版不带透明度的纯色提示框,然而视觉效果大打折扣。

其实咱们对于原先采用CSS clip-path的方案其实也存在不少的缺陷,它在面对带有阴影、背景透明或者渐变、带边框同时出现时就显出了实现成本高和效果通常的缺点。

SVG 方案

在讨论中咱们想到 SVG的path 和这个提示框的样式自然的匹配(建议先了解下path的相关文档),查阅了相关的文档和资料后咱们大体获得了使用SVG来实现的以下几个优势:

  • 能轻松知足阴影、背景透明或者渐变、带边框的效果,甚至更为复杂多变的场景
  • SVG的path实现简单,而且代码量极小
  • 可扩展性,可维护性

参考相关文章后,咱们完善Demo工具以下:

使用Demo工具,咱们会获得path的数据大体以下:

M 0,0 L -15,-15 H -79 Q -84,-15 -84,-20 V -85 Q -84,-90-79,-90 H 61 Q 66,-90 66,-85 V -20 Q 66,-15 61,-15 H 15 z
复制代码

一般使用SVG画path时用到命令以下表:

贝塞尔曲线

在SVG path 命令中我我的认为最精髓的部分是贝塞尔曲线,贝塞尔能画出各类使人愉悦的曲线。

贝塞尔曲线彻底由其控制点决定其形状, n个控制点对应着n-1阶的贝塞尔曲线,而且能够**经过递归的方式来绘制。**咱们先看下一次和二次贝塞尔曲线如何来绘制的:

一次曲线:

一条直线上,随着时间t的变化,红色线段的那个点的坐标公式应该以下:

二次贝塞尔曲线:

p0、p一、p2是3个不共线的点,依次用线段链接,此时随意取线段p0p1上的一个点p0' , 如上图: 咱们的p0'点在p0p1线段的0.26处(t=0.26),此刻p1p2线段相同比列取p1'点,此时p0'p1'链接后造成线段p0'p1', 在按照如上比列进行取值 p0'', 这时候就肯定了二次贝塞尔曲线的一个点。

经过一番巴拉巴拉牛逼的推导后,二次贝塞尔曲线公式为:

N次贝塞尔能够认为是如上取值方式的迭代过程,能够经过下图直观的感觉到1~4次曲线随着时间t的变化过程,具体N次贝塞尔曲线的公式能够参考下方关于曲线的文章

SVG中的Q命令

回到咱们的ToolTips 话题, 其中的圆角是能够经过二次贝塞尔曲线来实现,SVG中 Q 命令就是来实现二次贝塞尔曲线的,SVG中 Q 命令的示例图以下:

对应的指令,其中x1,y1就是咱们上面提到的p1点:

Q x1 y1, x y
复制代码

二次贝塞尔曲线 Q 示例以下:

<svg width="190px" height="160px" version="1.1" xmlns="http://www.w3.org/2000/svg">   <path d="M10 80 Q 95 10 180 80" stroke="black" fill="transparent"/></svg>
复制代码

经过设置起始点和调整控制点p1 咱们能获得咱们想要的圆角,以下图所示,小圆点为咱们的p1控制点

样式设置

实现了上方的SVG后接下来的透明、背景渐变、阴影、边框的设置就都不成问题了。

背景透明

path {  fill: rgba(0,0,0, .3);  storke: #ffffff;  storke-width: 1px}
复制代码

阴影

svg {  filter:drop-shadow(2px 4px 6px black)}
复制代码

关于为什么使用drop-shadow来实现阴影,能够看下图使用了box-shadowdrop-shadow效果区别,

使用box-shadow的时候咱们的尖角部分没有阴影,气泡框部分是有阴影的,就会出现下图所示的状况,而使用drop-shadow 就能符合咱们尖角和睦泡框都有阴影的要求。

背景渐变

SVG不只支持简单的填充,还支持线性渐变和径向渐变以及图形纹理等。为了让渐变能被重复使用,渐变内容须要定义在标签内部。

以下图是径向渐变的演示:

<svg width="120" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg">  <defs>      <linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1">        <stop offset="0%" stop-color="red"/>        <stop offset="50%" stop-color="black" stop-opacity="0"/>        <stop offset="100%" stop-color="blue"/>      </linearGradient>  </defs>  <rect x="10" y="120" rx="15" ry="15" width="100" height="100" fill="url(#Gradient2)"/>  </svg>
复制代码

将这个渐变做用到咱们提示框后能够看到以下图的效果,终于不用辛辛苦苦的处理尖角的渐变衔接问题了。

更多

SVG同时也支持纹理叠加效果,具体感兴趣的能够自行去研究下。

需求还没完

上面方案落地到项目中后,多是咱们不经意感动了设计师,最近的需求视觉稿中咱们发现其中涉及到的Tooltips样式已经愈加使人惊艳。简单列举以下两个样式:

初版方案咱们基于Demo工具演示咱们已经产出了ToolTips的SDK, 咱们使用的单个参数arrowHeight传入来生成尖角。在应付上方两个样式是不可能的,尖角样式多变,如何来扩展性和易用性成为了一个问题,不可能多变的尖角样式都开发一个SDK。

方案改进

要应付多变的气泡尖角必定要想办法把尖角抽离出原先的气泡外层路径,生成尖角路径后在整合到气泡上造成一个完整的闭合路径。

为了简单处理数值,我将原先的尖角 (0,0) 坐标定义更换到下方图示点:

因此接下来尖角能够自由设计了,只要保证从**(0,0)**出发最后回到**(-arrowWidth,0)**就好了,以下是一个尖角的路径:(M 0 0 C -10 0 -8 5 -12 5 S -14 0 -24 0

经过设计不一样的尖角路径咱们就能组合成不一样的气泡样式:

上方右侧的尖角气泡最终给出的路径字符串以下,其中Q -2 7 -9 10 Q -6 5 -7 0 这一段即为咱们的尖角路径:

M 0 0 Q -2 7 -9 10 Q -6 5 -7 0H -110Q -116,0 -116,-6V -56Q -116,-62 -110,-62H 101Q 107,-62 107,-56V -6Q 107,0 101,0H 0 z

从上方简短的路径能看出,咱们的尖角路径是完整的整合在整个SVG气泡路径中的,因此就不会担忧会出现CSS的 clip-path 方案的问题。
复制代码

可视化工具

方案看起来好像已经搞定了需求中的尖角样式,然而你可能会说这尖角路径是如何产生,难道须要经过强大的数学能力推导出来?以下三次贝塞尔曲线就已经不敢直视了,更况且四次、五次...

因此想配合的咱们必定要产出可视化工具来实现这路径生成过程,得益于D3.js工具库操做SVG方面的强大功能,咱们开发完的 生成工具地址 (market.m.taobao.com/app/fdilab/…) 以下:

对于熟悉SVG的 path命令的同窗来讲这个操做不难,若是不熟悉的推荐看下下方的参考文章,了解了曲线命令后就能画出圆滑的曲线。

总结

至此在ToolTips这块基本已经知足了设计的需求,同时也沉淀了SVG路径生成工具。使用SVG来实现ToolTips能覆盖 CSS clip-path不能完美解决的几个场景。在此特别感谢大漠老师的指导。

参考文章

相关文章
相关标签/搜索