Safari浏览器对SVG中的<foreignObject>标签支持不友好,渲染容易错位
在 svg 中需要写一个 markdown 编辑器,需要用到 <foreignObject> 绘制来html,编辑器选择了 simplemde。大致html部分结构如下,<markdown-editor> 组件为定制封装好的 simplemde 编辑器。
<template>
<svg>
<g>
<foreignObject :width="XXX" :height="XXX">
<div xmlns="http://www.w3.org/1999/xhtml">
<markdown-editor></markdown-editor>
</div>
</foreignObject>
</g>
</svg>
</template>
在 Chrome 浏览器开发完成,测试上线都符合预期,但是最后收到用户反馈:她用的是 mac 自带的 Safari 浏览器,在 Safari 里markdown编辑器会出现错位等各种问题。于是我先打开我的 Firefox 浏览器,自测正常,那估计就是 Safari 浏览器的兼容问题了。我看了下 Safari 浏览器的表现:markdown 编辑器每次一打开检查本身的 dom 占位是正确的,但是可视的编辑器界面却会被渲染到最顶部 <svg> 标签的左上角原点(0,0)。最后排查到是因为 safari 对 SVG 中的 <foreignObject> 标签支持不友好,渲染容易错位,特别是遇到 position 属性的时候,而我在引入simplemde 编辑器的同时也引入了 simplemde.min.css,其中大量使用了 position 属性我也在 StackOverflow 和 Github 找到了几篇关于这个bug的讨论帖作为参考:
StackOverflow:SVG foreignObject not working properly on Safari
Github:Safari + foreignobject render issue

最后Github一位程序员ankero一锤定音,原文大意如下:
这不是一个问题,但是可以添加到 README 中。我将在这里添加它,以便如果有人面临类似的问题,可以在这个仓库中找到一个解决方案。在使用这个库(指的是react-d3-tree库,但是遇到的问题是一样的)进行开发时,如果使用 foreignObject 呈现节点,请检查它在 Safari (Mac + iOS)中的显示方式。我们遇到了一个问题,节点内容呈现为父 SVG 的坐标0,0(左上角)。这是由于 Safari 中的一个 bug,它影响 foreignObject 根据顶部 SVG 而不是 foreignObject 本身计算呈现位置。通过检查节点并查看基于浏览器的节点是否在应该在的位置,您可以非常清楚地看到这种效果,但是呈现在了错误的位置。(这段描述和我当时排查的结果一模一样)
那么,如果你看到这个问题,解决方案是什么?
据我所知,如果您使用以下任何 CSS 选项,dom 元素将呈现在错误的位置。所以解决办法就是不要用这些。对我们来说,我们需要检查浏览器是否是 Safari,然后删除一些需要一个或多个这样的样式的功能。
所以不要在 Safari + foreignObject 中使用以下样式:
- position(您可以使用 position: fixed,但这将导致溢出问题)
- webkit-transform-style
- webkit-backface-visibility
- transition
- transform
如何检测 Safari?
我们使用以下片段:
export const IS_SAFARI = /Safari/.test(navigator.userAgent) && /Apple Computer/.test(navigator.vendor);
这里提一下 position: fixed 导致的溢出问题,这个在上一个StackOverflow链接中被很多程序员提为解决,方案,这个办法确实能解决一些简单的需求和页面,但是需要注意的一点是,使用这种办法会导致页面缩放出现问题。具体来说就是svg所绘制元素的缩放比例与<foreignObject>所绘制元素的缩放比例不是一致的,这也会带来位置错乱问题。不过可以根据自己的具体情况进行抉择。
各大浏览器之间的兼容问题是各位前端er心中永远的痛,一方面希望谷歌或火狐浏览器能一统江湖,但是另一方面又希望百家齐放能促进前端技术的发展。但是话说又说回来,最重要的还是遵守标准,既然标准都设立在那了,为啥各家不跟上标准呢。
Safari浏览器对SVG中的<foreignObject>标签支持不友好,渲染容易错位的更多相关文章
- WebKit策略:<foreignObject>可用于绘制svg中的html标签,但与<use>搭配不生效
在<svg>里面可以利用<foreignObject>绘制html标签,原本是我在iconfont采用Font class方式引入svg的无奈之举. 起初的设计是所有icon先 ...
- html页面在苹果手机内,safari浏览器,微信中滑动不流畅问题解决方案
1. -webkit-overflow-scrolling:touch是什么? MDN上是这样定义的: -webkit-overflow-scrolling 属性控制元素在移动设备上是否使用滚动回弹效 ...
- Dedecms中{dede:type}标签支持调用父级栏目名称
需求: 我们用{dede:type}标签调用栏目相关内容时,同时需要调用该栏目的父级栏目的名称. {dede:type}标签的代码做了一下开发,支持这个调用了. 开发方法: 1.打开include/t ...
- eclipse中添加jstl标签支持(引入头)
https://blog.csdn.net/wangyuxuan_java/article/details/8580318
- d3.js svg中 g 标签问题一览
svg 中的g标签, 算是比较特殊 1 没有x y属性 2 没有width height 属性 3 不能fill 4 .... g标签基本只管分组问题, 其他功能一概不提供 要解决这些问题, 直接在g ...
- iOS中Safari浏览器select下拉列表文字太长被截断的处理方法
网页中的select下拉列表,文字太长的话在iOS的Safari浏览器里会被自动截断,显示成下面这种: 安卓版的浏览器则没有这个问题. 如何让下拉列表中的文字在iOS的Safari浏览器里显示完整呢? ...
- 利用iOS中Safari浏览器创建伪Web App
在safari浏览器里有一个“添加到主屏幕”选项,我们可以用来创建伪Web App,下面来了解一下iOS中Safari的私有属性 第一步设置Web App的主屏幕图标: 有两种属性值apple-tou ...
- 获取SVG中g标签的宽度高度及位置坐标
1. 问题的出现 对于普通的HTML元素,有很多获得其宽度width.高度height.距左left.距顶top等属性的方法: 类似offsetWidth,clientWidth,width之类的,通 ...
- 发布时一键添加html中的css标签和script标签版本号来防止浏览器缓存
AppendFileVersion 是一个VSIX插件支持vs2015意以上版本 是我用来发布时一键添加html中的css标签和script标签版本号来防止浏览器缓存 分享给大家! download ...
- 解决java web中safari浏览器下载后文件中文乱码问题
解决java web中safari浏览器下载后文件中文乱码问题 String fileName = "测试文件.doc"; String userAgent = request.g ...
随机推荐
- Django 出现 frame because it set X-Frame-Options to deny 错误
一.背景 使用django3 进行开发时,由于项目前端页面使用iframe框架,浏览器错误提示信息如下 Refused to display 'http://127.0.0.1:8000/' in a ...
- 同一台电脑安装两个不同版本的mysql。简单暴力有效
1.先找到mysql的安装地址.找到my.ini 2.修改端口号(mysql默认端口是3306)我这里修改为3307 3.打开服务.找到刚刚修改的mysql版本 4.重新启动该服务(我已经安装了mys ...
- 在IDEA 、springboot中使用切面aop实现日志信息的记录到数据库
文章目录 1.导入相关的依赖 2.创建要保存的数据信息实体类 3 .编写对应的sql语句 4.使用spring 的 aop 技术切到自定义注解上,所以先创建一个自定义注解类 5. 创建aop切面实现类 ...
- 6.-Django设计模式及模版层
一.MVC (java等其他语言) MVC代表Model-view-Contorller(模型-视图-控制器)模式 M模型层主要用于对数据库层的封装 V视图层用于向用户展示结果 C控制器用于处理请求. ...
- GlusterFS常用维护操作命令
GlusterFS常用维护操作命令 1.启动/关闭/查看glusterd服务 # /etc/init.d/glusterd start # /etc/init.d/glusterd stop # /e ...
- Java Stream流的使用
流相关的方法可以分为三种类型,分别是:获取Stream流.中间方法.终结方法.中间方法会返回当前流,可以方便的进行链式调用. 流不可重复使用,否则会报错: java.lang.IllegalState ...
- JS逆向实战3——AESCBC 模式解密
爬取某省公共资源交易中心 通过抓包数据可知 这个data是我们所需要的数据,但是已经通过加密隐藏起来了 分析 首先这是个json文件,我们可以用请求参数一个一个搜 但是由于我们已经知道了这是个json ...
- Python基础之模块:5、 第三方模块 requests模块 openpyxl模块
目录 一.第三方模块的下载与使用 1.什么是第三方模块 2.如何安装第三方模块 方式一:pip工具 方式二:pycharm中下载 3.注意事项 1.报错并有警告信息 2.报错,提示关键字 3.报错,无 ...
- Django系列---理论一
教程:http://c.biancheng.net/django/ 特点 集成 ORM 组件:Django 的 Model 层自带数据库 ORM 组件,为操作不同类型的数据库提供了统一的方式. URL ...
- 1.docker的基本使用
1.简介 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows操作系统的机器上,也可以实现虚拟化.容器是完 ...