svg VS canvas,哪种在移动端适配度更好?实战经历告诉你~

news2025/1/18 7:01:28

最近做了一个画图的功能,后端提供棋盘数据,前端需要把数据转换成一个棋盘画出来,当时有两种实现方法,一种是使用canvas画图,一个是使用svg画图.

ui提供的设计稿如下:

在这里插入图片描述

由于这是一个轮播图,当后端返回多少张棋盘数据时,就需要渲染多少张棋盘,最多有十张,基于canvas和svg画图,为了保证页面的首次渲染时长最优,就是不使用库来画,正好可以熟悉一下canvas和svg的基础.

svg画棋盘

适配

由于是在移动端的页面,所以首选就是使用rem单位,但是画着画着就出现了问题

svg画简单形状的代码是

<p>使用rem单位画线</p>
  <svg>
    <line
      x1="0"
      y1="0"
      x2="5rem"
      y2="5rem"
      stroke-width="2"
      stroke="#975B2A"
    />
  </svg>
  <p>使用rem单位画圆</p>
  <svg>
    <circle 
      cx="6rem" 
      cy="6rem" 
      fill="#A7632D" 
      r="0.3rem"
    ></circle>
  </svg>

效果如下:

在这里插入图片描述

在电脑上能够正常显示,但是到iphone13上,就显示不出来了.

我发现是小于1的rem单位的显示不出来,不过我没有使用各种各样的机型测试,但是iphone13就不行,那就只能放弃了.

所以就只能依赖js计算

40px的线条距离:40 * document.documentElement.clientWidth / 375;

虽然不能使用rem单位,但是可以使用百分比,使用svg的DOM元素使用rem单位还是没有问题的,使用百分比就能够正常显示

<p>使用百分比单位画线</p>
  <svg>
    <line
      x1="0"
      y1="0"
      x2="50%"
      y2="50%"
      stroke-width="2"
      stroke="#975B2A"
    />
  </svg>
  <p>使用百分比单位画圆</p>
  <svg>
    <circle 
      cx="60%" 
      cy="60%" 
      fill="#A7632D" 
      r="1%"
    ></circle>
  </svg>

在这里插入图片描述

不过使用js计算一次就可以了,百分比对着ui稿我还得计算一遍,所以我就直接使用document.documentElement.clientWidth计算了.

很快棋盘的样式就画好了

在这里插入图片描述

所以很快就被ui设计师打了回来,没有光泽,她说棋子需要画渐变,也需要有阴影,不然不好看.

加渐变

<p>加渐变(first:没渐变,second:有渐变)</p>
  <svg>
    <defs>
      <linearGradient id="b" x1="0" x2="1" y1="0" y2="1">
          <stop offset="0" stop-color="#fff" stop-opacity="1"></stop>
          <stop offset="1" stop-color="#D0CBC7" stop-opacity="1"></stop>
      </linearGradient>
  </defs>
  <circle 
      cx="20%" 
      cy="60%" 
      fill="#fff" 
      r="3rem"
    ></circle>
    <circle 
      cx="60%" 
      cy="60%" 
      fill="url(#b)" 
      r="3rem"
    ></circle>
  </svg>
  <svg>
    <defs>
      <linearGradient id="a" x1="0" x2="1" y1="0" y2="1">
          <stop offset="0" stop-color="#7B7B7B" stop-opacity="1"></stop>
          <stop offset="1" stop-color="#0B0B0B" stop-opacity="1"></stop>
      </linearGradient>
  </defs>
  <circle 
      cx="20%" 
      cy="60%" 
      fill="#000" 
      r="3rem"
    ></circle>
    <circle 
      cx="60%" 
      cy="60%" 
      fill="url(#a)" 
      r="3rem"
    ></circle>
  </svg>

效果对比如下:
在这里插入图片描述

渐变兼容性在PC,iphone,ipad,安卓都支持~

加阴影

<p>加阴影(first:没阴影,second:有阴影)</p>
  <svg>
    <defs>
      <linearGradient id="b" x1="0" x2="1" y1="0" y2="1">
          <stop offset="0" stop-color="#fff" stop-opacity="1"></stop>
          <stop offset="1" stop-color="#D0CBC7" stop-opacity="1"></stop>
      </linearGradient>
      
      <filter id="bb" width="200%" height="200%">
        <!-- 投影偏移 -->
        <feOffset dx="0" dy="2" />
        <!-- 投影模糊 -->
        <feGaussianBlur stdDeviation="2" result="offset-blur" />
        <!-- 反转投影使其变成内投影 -->
        <feComposite
          operator="out"
          in="SoredurceGraphic"
          in2="offset-blur"
          result="inverse"
        />
        <!-- 内投影附加黑色 -->
        <feFlood flood-color="#BE8C2E" flood-opacity=".95" result="color" />
        <feComposite operator="in" in="color" in2="inverse" result="shadow" />
        <!-- 把内投影显示在图像上 -->
        <feComposite operator="over" in="shadow" in2="SourceGraphic" />
      </filter>
  </defs>
  <circle 
      cx="20%" 
      cy="60%" 
      fill="url(#b)" 
      r="3rem"
    ></circle>
    <circle 
      cx="60%" 
      cy="60%" 
      fill="url(#b)"
      filter="url(#bb)"
      r="3rem"
    ></circle>
  </svg>
  <svg>
    <defs>
      <linearGradient id="a" x1="0" x2="1" y1="0" y2="1">
          <stop offset="0" stop-color="#7B7B7B" stop-opacity="1"></stop>
          <stop offset="1" stop-color="#0B0B0B" stop-opacity="1"></stop>
      </linearGradient>
      <filter id="aa" x="-0.05" y="0" width="120%" height="120%">
        <!-- 投影偏移 -->
        <feOffset dx="0" dy="1" />
        <!-- 投影模糊 -->
        <feGaussianBlur stdDeviation="1" result="offset-blur" />
        <!-- 反转投影使其变成内投影 -->
        <feComposite
          operator="out"
          in="SoredurceGraphic"
          in2="offset-blur"
          result="inverse"
        />
        <!-- 内投影附加黑色 -->
        <feFlood flood-color="#1D1D1D" flood-opacity=".95" result="color" />
        <feComposite operator="in" in="color" in2="inverse" result="shadow" />
        <!-- 把内投影显示在图像上 -->
        <feComposite operator="over" in="shadow" in2="SourceGraphic" />
      </filter>
  </defs>
  <circle 
      cx="20%" 
      cy="60%" 
      fill="url(#a)" 
      r="3rem"
    ></circle>
    <circle 
      cx="60%" 
      cy="60%" 
      fill="url(#a)" 
      filter="url(#aa)"
      r="3rem"
    ></circle>
  </svg>

效果如下:

在这里插入图片描述

阴影没有加渐变这么顺利,出现了新的问题

iphone中棋子不见了

在这里插入图片描述

排查原因:发现去掉去掉filter标签就能够看到棋子.

于是我查看svg中filter标签的兼容性。如下:

https://caniuse.com/?search=filter svg

在这里插入图片描述

上面写着IOS6就开始支持了,但是在iphone13中就是没有显示出来,所以就只能不能这样画阴影了,得另寻他路.

重叠元素加阴影

  <p>重叠元素加阴影(first:没阴影,second:有阴影)</p>
  <svg>
    <defs>
      <linearGradient id="b" x1="0" x2="1" y1="0" y2="1">
          <stop offset="0" stop-color="#fff" stop-opacity="1"></stop>
          <stop offset="1" stop-color="#D0CBC7" stop-opacity="1"></stop>
      </linearGradient>
  </defs>
  <circle 
      cx="20%" 
      cy="60%" 
      fill="url(#b)" 
      r="3rem"
    ></circle>
    <circle 
      cx="60%" 
      cy="64%" 
      fill="rgba(0,0,0,.16)"
      r="3rem"
    ></circle>
    <circle 
      cx="60%" 
      cy="60%" 
      fill="url(#b)"
      r="3rem"
    ></circle>
    
  </svg>
  <svg>
    <defs>
      <linearGradient id="a" x1="0" x2="1" y1="0" y2="1">
          <stop offset="0" stop-color="#7B7B7B" stop-opacity="1"></stop>
          <stop offset="1" stop-color="#0B0B0B" stop-opacity="1"></stop>
      </linearGradient>
  </defs>
  <circle 
    cx="60%" 
    cy="64%" 
    fill="rgba(0,0,0,.24)"
    r="3rem"
  ></circle>
  <circle 
      cx="20%" 
      cy="60%" 
      fill="url(#a)" 
      r="3rem"
    ></circle>
    <circle 
      cx="60%" 
      cy="60%" 
      fill="url(#a)" 
      r="3rem"
    ></circle>

  </svg>

效果如下:

在这里插入图片描述

不过这个需要特别注意顺序,阴影需要在下面显示,所以要先绘制阴影,不然就会把棋子盖住,效果像下面这样:

在这里插入图片描述

突然发现使用重叠元素加出来的阴影更加好看.

边缘棋子不显示问题

在这里插入图片描述

svg中的cricle标签没有z-index层级之说

解决办法:svg面积增大,svg中的元素x,y轴偏移,根据rect画圆角矩形

<p>画圆角矩形</p>
<svg>
    <rect 
    width="60%" 
    height="60%" 
    x="22" 
    y="22" 
    rx="20" 
    ry="20" 
    style="
      fill: transparent; 
      stroke: rgb(151, 91, 42); 
      fill-opacity: 0.5; 
      stroke-opacity: 1; 
      opacity: 1;
      stroke-width: 2;
    "
    ></rect>
  </svg>
  // x,y是矩形的起点;w,h是矩形的宽高;r是圆角矩形的半径

效果如下:
在这里插入图片描述

canvas和svg比较

android效果

canvas截图如下:

在这里插入图片描述

svg截图如下:

在这里插入图片描述

ipad效果

canvas截图如下:

在这里插入图片描述

svg截图如下:

在这里插入图片描述

canvas拍照效果:

在这里插入图片描述

svg拍照效果:

在这里插入图片描述

iphone效果

canvas截图如下:

在这里插入图片描述

svg截图如下:

在这里插入图片描述

canvas拍照效果:

在这里插入图片描述

svg拍照效果:

在这里插入图片描述

从上面效果来说,我觉得svg画的棋盘在移动端更高清,而canvas更像是一张图片,对效果有更加浓厚的兴趣的可以去下载一下源码,然后自己手动在手机上看看效果.

性能比较

我只是通过谷歌浏览器的lighthouse测量了一下,下面是绘制十张棋盘的测试结果,当然觉得这样测量不准确的,也欢迎下载源码自己去测试一下~

canvas

在这里插入图片描述

svg

在这里插入图片描述

从上面结果上看,svg和canvas画十张棋盘的性能,svg优胜一点点,总阻塞时间svg快了100ms的样子.

源码:

为了保证公平性,源码中没有使用任何库,只是js操作,十张棋盘的数据也是一样的.

gitee地址:svg_vs_canvas_chess: svg和canvas在移动端适配比较 (gitee.com)

github地址:https://github.com/tiantianhy/svg_vs_canvas_chess

上述分享中,如有疑问和想法,欢迎一起探讨~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/18698.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Milvus的以图搜图】

0. 介绍 Milvus官方在bootcamp项目中给开发者提供多种解决方案&#xff0c;包含常见的以图搜图、人脸检索、DNA相似性检索、视频检索等等&#xff0c;具体可以参考bootcamp项目。 本文主要就bootcamp中以图搜图reverse_image_search的代码介绍如何运行该样例&#xff0c;进而了…

文献阅读-VSE++:使用困难负样本来改经视觉语义嵌入

Title&#xff1a;《VSE: Improving Visual-Semantic Embeddings with Hard Negatives》 Authors&#xff1a;Fartash FaghriDavid FleetJ. KirosS. FidlerJournal&#xff1a;ArXiv (2017)Date&#xff1a;2017 code&#xff1a;GitHub - fartashf/vsepp: PyTorch Code for t…

Java基础38 面向对象三大特征之多态

OOP之多态 多态1.多态的具体体现2.向上转型3.向下转型4.属性重写5.instanceOf6.动态绑定机制&#xff08;核心&#xff09;● Java的动态访问机制7.多态数组8.多态参数)多态 ● 多【多种】态【状态】 方法或对象具有多种形态。 是建立在封装和继承之上的面向对象的第三大特征…

一文带你学会Vue3基本语法

Vue3 起步1.通过 CDN 使用 Vue32.Vue3 模板语法文本Html属性表达式指令参数3.模板用户输入双向绑定1.通过 CDN 使用 Vue3 你可以借助 script 标签直接通过 CDN 来使用 Vue&#xff1a; <script src"https://unpkg.com/vuenext"></script>通过 CDN 使用…

在WPF中使用Prism弹出自定义窗体样式的对话框

概述 我们在Prism中弹出一个对话框&#xff0c;默认是一个Windows默认样式的窗口&#xff0c;这样会同自己所开发的项目完全不搭调&#xff0c;譬如下面这样子 那么如果为了配合软件主体的风格&#xff0c;可以做出类似这样效果 其实原理也很简单&#xff0c;Prism也考虑到了这…

不科学,RocketMQ生产者在一个应用服务竟然不能向多个NameServer发送消息

前言 目前有两套RocketMQ集群&#xff0c;集群A包含topic名称为cluster_A_topic&#xff0c;集群B包含topic名称为cluster_B_topic&#xff0c;在应用服务OrderApp上通过RocketMQ Client创建两个DefaultMQProducer实例发送消息给集群A和集群B&#xff0c;架构图如下&#xff1…

使用Vue脚手架配置代理服务器的两种方式

1 前言 本文主要介绍使用Vue脚手架配置代理服务器的两种方式 注意&#xff1a;Vue脚手架给我们提供了两种配置代理服务器的方式&#xff0c;各有千秋&#xff0c;使用的时候只能二选一&#xff0c;不能同时使用 2 代理 除了cros和jsonp&#xff0c;还有一种代理方式&#x…

传奇GM调整极品属性的命令------技术分享

传奇GM调整极品属性的命令 GM命令supermake命令用法&#xff01; 以下格式皆为supermake a b c   以上命令含义&#xff1a;调整A(装备)的B(属性)到C(点数) supermake 1 0 10  1代表武器  0代表攻击 10代表调整的点数 B参数代表需要调整的那项属性如攻击 魔法 道术 …

黑*头条_第4章_文章搜索前后端成形记 实名认证审核

黑*头条_第4章_文章搜索前后端成形记 & 实名认证审核 文章目录黑*头条_第4章_文章搜索前后端成形记 & 实名认证审核文章搜索前后端成形记 & admin实名认证审核1 文章详情-前端开发1.1登录接口1.1.1 基本定义1.1.2 code定义1.1.3 mapper实现1.1.4 service代码实现1.…

宝塔一键安装wordpress

使用宝塔面板来部署网站是非常方便的&#xff0c;以WordPress网站为例来说&#xff1a; 一般有两种方式安装WordPress网站&#xff0c;第一种是上传网站程序到网站根目录手动安装&#xff0c;另外一种是在宝塔面板后台左侧菜单&#xff0c;找到“WordPress一键部署”&#xff…

Map 和 Set

模型 一般我们把搜索的数据称为 关键字(key) , 关键字对应的值叫做 值(value) , 将之称为 key-value 键值对. 衍生出两种模型: 1. 纯 key 模型 例如 : 班级上点名, 在花名册上找人的名字. 2. key-value 模型 例如 : 统计一个字符串中每个字母出现的次数, 结果是每个字母和它对…

简易版 图书管理系统

目录 1. Book包 1.1 Book类 1.2 BookList类 2. User包 2.1 User抽象类 2.2 AdminUser类 2.3 NormalUser类 3. Operate包 3.1 MyOperate接口 3.2 AddOperation类 3.3 DelOperation类 3.4 ExitOperation 3.5 FindOperation类 3.6 ShowOperation类 3.7 BorrowedOpe…

MySQL——数据库、表的操作

文章目录数据库的操作创建数据库创建数据库例子字符集和校验规则查看数据库支持的字符集查看默认的字符校验规则校验规则对数据库的影响查看数据库显示详细的创建数据库语句修改数据库删除数据库查看连接情况表的操作创建表显示创建表的详细过程不同的数据库引擎查看表结构修改…

【C语言】操作符与优先级详解

C的操作符 文章目录C的操作符前言一、算术操作符二、移位操作符三、位操作符四、赋值操作符五、单目操作符六、条件操作符七、逻辑操作符八、条件操作符九、逗号表达式十、下标引用、函数调用和结构成员十一、表达式求值11.1 隐式类型转换12.2 算术转换12.2 操作符的属性总结前…

解决Vue前后端跨域问题的多种方式

1 前言 本文主要介绍借助解决Vue前后端跨域问题的几种方式 说到ajax请求&#xff0c;就不得不说下xhr(XMLHttpRequest)了&#xff0c;它可以说是鼻祖&#xff0c;但是实际开发中&#xff0c;我们不会直接使用它&#xff0c;而是进行二次封装或者使用成熟的第三方封装&#xf…

Zookeeper:分布式过程协同技术

Zookeeper 是一个高性能的分布式一致系统&#xff0c;在分布式系统中有着广泛的应用。基于它&#xff0c;可以实现诸如“分布式同步”、“配置管理”、“命名空间管理”等众多功能&#xff0c;是分布式系统中常见的基础系统。Zookeeper 主要用来解决分布式集群中应用系统的一致…

http,https,ip,tcp,udp

http:超文本传输协议&#xff0c;明文传输&#xff0c;不安全 超文本&#xff1a;早期&#xff0c;文本存在本地&#xff0c;文本可以被计算机解析为二进制的数据包&#xff0c;随着发展&#xff0c;出现图片&#xff0c;视频&#xff0c;链接等&#xff0c;成为超文本 传输&a…

批量生成Excel文件,可以按模板进行自动生成

目录 一、文件目录结构 二、编辑生成名单 三、编辑模板 四、生成操作 软件描述&#xff1a;根据Excel模板 和 生成名单 可以批量生成相同格式的文件&#xff0c;可以应用于考核、工资单等文件的批量生成。方便快捷&#xff0c;有需求的小伙伴可以到最下面点击下载 注&#…

mysql 客户端简单搭建

主要使用的是mysql开发包中的api接口 操作流程 1.初始化mysql操作句柄 MYSQL *mysql_init(MYSQL *mysql)&#xff1b; 对传人的句柄进行初始化 若传入的句柄为NULL&#xff0c;则内部会动态申请空间&#xff0c;进行初始化&#xff0c;并返回句柄首地址 返回值&#xff1a;若…

基于51单片机的ds18b20数字华氏温度计

资料编号&#xff1a;114 下面是相关功能视频演示&#xff1a; 114-基于51单片机的数字华氏温度计报警&#xff08;源码仿真全套资料&#xff09;功能讲解&#xff1a; 采用51单片机采集DS18B20的温度&#xff0c;LCD1602显示&#xff0c;并且可以设置上下限值&#xff0c;超…