by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=6326
本文可全文转载,但需得到原作者书面许可,同时保留原作者和出处,摘要引流则随意。
一、从 SVG 文本换行说起
SVG 和 CSS 几乎可以看成是同一个年代出来的东西,但是在 Web 界面展示这块,CSS 长期统领江山,SVG 偃旗息鼓,直到这些年,SVG 开始乘势而上。
时势造英雄。当年 web 网页都是以图文展示为主,所以门户,博客这些网站兴起。而 SVG 擅长的是图形展示,对于文本呈现,只能嘿嘿一下,跟 CSS 相比那可就弱了几条街。举个最简单的效果,文本换行。在 CSS 下,当我们一段文字很长的时候,是会自动换到下一行的,但是在 SVG 中,基本上就是要手动控制换行,对于新闻、博客展示而言简直就是噩梦。于是,CSS 火了,SVG 萎了。
但,时代是发展的,现代网络带宽有大腿粗,电脑性能比第一次还快,屏幕密度比姚明还高,丰富的富媒体展现和复杂的图形表现需求越来越高,随着 flash 的日渐衰微,显然,规范标准化的 SVG 就顺势崛起。
然而需求是千变万化的,当我们使用 SVG 实现一些视觉表现精湛的效果的时候,免不了会有增加一段描述文字的需求。呵呵,这个时候 SVG 怕是要傻眼了,SVG 的<text>
元素应付多行文字实在不擅长,如果 SVG 中的文字可以如同 CSS 中的表现一样就好了?
嘿,还真有,那就是 SVG 的<foreignObject>
元素。
二、SVG forginObject 元素简介
我们平常使用 SVG 使用的是 SVG 的命名空间:
xmlns
全称是 “XML Namespaces”,指 “XML 命名空间”。XML 是一个比较大的统称,是一种用于标记电子文件使其具有结构性的标记语言。我们平时写的 HTML 代码是 XML,RSS 订阅文档也是种 XML,SVG 也属于 XML。而这些 XML 类型的渲染规则是有差异的,例如 HTML 中裸露的<circle>
元素是不会表现为圆,而是一个普通的自定义元素。RSS 中的 XML 浏览器会自动进行文章排版渲染等。
所以我们可以看到,指定命名空间可以让浏览器精准解析,举个例子,如下 XML 代码:
虽然是 SVG 标签,明摆着应该安装 SVG 渲染,但是,实际上,由于没有指定xmlns
,在浏览器中打开的时候,直接以普通 XML 文档树渲染了。
可狠狠的点击此 SVG 文件亲自感受下:close-no-ns.svg
Chrome 浏览器下:
Firefox 浏览器下:
一旦我们加上了 SVG 专属命名空间,如下代码:
则符合预期的 SVG 图形就渲染出来了。
可狠狠的点击此 SVG 文件亲自感受下:close.svg
结果如下截图:
这就是命名空间的作用。但这里有必要额外说明下:如果我们的 SVG 文件是直接内联在 XHTML 页面中,是可以不指定命名空间的!
好,回到<foreignObject>
这里,<foreignObject>
元素的作用是可以在其中使用具有其它 XML 命名空间的 XML 元素,换句话说借助<foreignObject>
标签,我们可以直接在 SVG 内部嵌入 XHTML 元素,举个简单的例子:
文字。
可以看到<foreignObject>
标签里面有一个设置了xmlns="http://www.w3.org/1999/xhtml"
命名空间的<body>
标签,此时<body>
标签及其子标签都会按照 XHTML 标准渲染,实现了 SVG 和 XHTML 的混合使用。
这种混合特性有什么作用呢?作用很多,其中之一就是轻松实现 SVG 内的文本自动换行。
三、SVG forginObject 元素与文本自动换行
SVG 要实现文本换行,往往需要手动阻断,类似下面的代码:
需要2
个<tspan>
元素,这一点都不工程。虽然 Chrome 浏览器可以对<text>
标签进行white-space:normal
的强制设置,但也只是 Chrome 浏览器可以。
但是如果使用<foreignObject>
元素,则自动换行就是小菜:
一段需要word wrap的文字。
结果 Chrome 浏览器下效果为:
您可以狠狠地点击这里:foreignObject 下文本自动换行 demo
四、SVG forginObject 元素其它作用 - 图片生成
除了轻松实现文本换行,SVG <foreignObject>
元素还有其他更高级的应用,就是可以将页面上的 DOM 元素轻松变成图片,原理如下:
获取对应 DOM 元素的
outerHTML
代码;放在
<foreignObject>
元素中;图片方式显示我们的 SVG 图形,例如:
- 上一步的图片本质还是 SVG,我们可以借助
canvas
drawImage()
方法将图片放在画布上,然后使用canvas.toDataURL()
方法转换成png
或jpg
图片,核心代码:
var canvas = document.createElement(‘canvas’);
var context = canvas.getContext(‘2d’);
canvas.drawImage(img, 0, 0);
img.src = canvas.toDataURL(‘image/png’);
上一篇文章 “canvas 实现图片前端 JS 压缩” 有详细的 canvas 绘图和转图片示意,有兴趣可以参考下。
一旦我们可以把 DOM 元素转换成图片,我们就可以轻轻松松配合 JS 在前端实现网页截图功能。
想了想,还是做个 demo 示意下吧,您可以狠狠地点击这里:借助 forginObject 实现 DOM 转图片并直接下载 demo
点击 demo 页面右侧小模块任意区域,都可以保存想要内容,例如,外面框框:
结果:
触发保存,保存后的图片(点击可预览)就是 DOM 页面的样子。
更新于 2020-06-18
回过头看此文,发现 demo 页面生成图片的功能挂了,一排查,发现 Chrome 浏览器提高了安全限制级别,内联 CSS 样式中的#
字符也需要转义,也是 demo 页面源码调整了下,现在功能又 OK 啦!
——- 更新 end——-
补充说明:理论上,借助<foreignObject>
实现截图效果 Firefox 也是支持的,但是,上面例子为了简化,直接把页面上的<style>
元素以及里面 CSS 代码一起内联到 SVG 的<foreignObject>
中了,这种用法只有 Chrome 浏览器支持。因此,上面 demo 效果仅在 Chrome 及其内核浏览器下有效。Firefox 浏览器要想支持,需要使用特殊方法将所有元素样式style
属性内联在元素上。
SVG forginObject 兼容性
可以看出 SVG 的<foreignObject>
的特性非常棒!但相比其他 SVG 元素兼容性要差一些,主要是 IE 浏览器,好在大头 Chrome 和 Firefox 都支持,Safari 虽然支持<foreignObject>
貌似由于安全限制,转换成图片功能受限。
五、结束语
SVG <foreignObject>
元素可以让 DOM 变图片,发挥我们的创造力,我们可以做的事情就非常非常多,举个例子,各种特效,因为 DOM 图片化,我们就能使用canvas
读取图片完整的像素点信息,通过特点的算法,我们就可以做很多效果,例如常见的高斯模糊。高斯模糊浏览器天然支持,那我们可以实现浏览器默认没有的动感模糊或者镜像模糊;又或者我们可以把 DOM 元素变成粒子特效(canvas 擅长的);又或者实现类似 OS X 系统的 DOCK 中软件打开和收起的拉伸扭曲效果等等。
有技术,有创意,还不赶快行动,把你的网页炫起来!
(本篇完)
是不是学到了很多?可以分享到微信!
有话要说?点击这里。
https://www.zhangxinxu.com/wordpress/2017/08/svg-foreignobject/