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


    最近做了一个画图的功能,后端提供棋盘数据,前端需要把数据转换成一个棋盘画出来,当时有两种实现方法,一种是使用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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    效果如下:

    在这里插入图片描述

    在电脑上能够正常显示,但是到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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

    不过使用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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

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

    渐变兼容性在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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80

    效果如下:

    在这里插入图片描述

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

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    效果如下:

    在这里插入图片描述

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

    在这里插入图片描述

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

    边缘棋子不显示问题

    在这里插入图片描述

    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是圆角矩形的半径
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

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

    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

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

  • 相关阅读:
    Kubernetes入门 十七、Helm 包管理器
    MySQL数据库中text类型的数据使用Mybatis自动生成之后,返回值为空
    linux练习题
    CSS 中的 : 和 :: 有什么区别?
    MybatisPlus高级特性
    SpringMVC
    Docker系列第01部分:介绍+虚拟化+什么是Decker+组件
    2100. 适合打劫银行的日子;2080. 区间内查询数字的频率;1774. 最接近目标价格的甜点成本
    c#基础0-类型、起步
    【Lilishop商城】No1-1.业务了解+划分各模块逻辑
  • 原文地址:https://blog.csdn.net/qq_44859233/article/details/127939869