打工人必备!实现JS控制的SVG渐变图标,让你的页面更加生动有趣

在我们开发界面时,有时候渐变的图像会相比固定颜色的图形更加富有层次感与有趣。熟悉css的同学都知道,我们可以通过样式让背景呈现一个线性的渐变图片,比如这样:

css 复制代码
.simple-linear {
  background: linear-gradient(blue, pink);
}

也可以通过裁剪背景颜色到文本的方式实现文本颜色渐变

css 复制代码
.text-gradient {
  background-image: linear-gradient(to right, orange, purple);
  -webkit-background-clip: text;
  color: transparent;
}

这些解决方案都是网络上随便都能搜到的,那么现在背景渐变有了,文本渐变有了,看上去我们似乎可以实现各种渐变了,但是我们还差一个非常常见的元素没有办法做到渐变,那就是svg图标。

目前网络上所能找到的所有关于svg渐变颜色的方案都是需要通过svg本身的配置来实现的。举个例子:

比如这样:

html 复制代码
<svg
  class="svg-gradient"
  xmlns="<http://www.w3.org/2000/svg>"
  width="24"
  height="24"
  viewBox="0 0 24 24"
>
  <defs xmlns="<http://www.w3.org/2000/svg>">
    <linearGradient y2="0" x2="1" y1="1" x1="1" id="svg_1">
      <stop stop-color="#ff0000" offset="0" />
      <stop stop-color="#ffff00" offset="1" />
    </linearGradient>
  </defs>
  <path
    d="M12 2a9 9 0 0 0-9 9v11l3-3l3 3l3-3l3 3l3-3l3 3V11a9 9 0 0 0-9-9M9 8a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m6 0a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2Z"
    fill="url(#svg_1)"
  />
</svg>

这看上去很美好,因为我们我们只需要把这段svg代码复制到我们的项目中,然后需要的时候引用一下就好了。

当然是可以,但是在实际开发中我们往往会遇到更加复杂的挑战。比如我们用的图标是在一个图标库组件中,我们没有办法去直接修改(比如 react-icons )。比如我们需要让图标在渐变色(选中状态)和单色(未选中状态)之间来回切换。

难道我要准备两个一样的仅仅颜色不一样的图标因为状态来选择使用哪个图标么?这很丑陋,且难以维护。

想象一下我们是如何使用单色图标的?仅仅配置 color=#<hex-color> 即可实现不同颜色的切换。为什么渐变色图标不能有类似方式?

我搜索了网络上所有的资料,但是我没有找到我想要的方法,因此我决定自己探索。

一个很少有人会注意到的事实是,<defs> 标签的定义作用域不是父级的svg节点而是整个文档流。因此我们可以跨多个svg声明共用一个svg定义。然后只需要通过固定的id就可以了。

具体方案如下:

html 复制代码
<style>
  .svg-gradient {
    fill: url(#my-gradient);
  }
</style>

<svg width="0" height="0">
  <defs xmlns="<http://www.w3.org/2000/svg>">
    <linearGradient y2="0" x2="1" y1="1" x1="1" id="my-gradient">
      <stop stop-color="#ff0000" offset="0" />
      <stop stop-color="#ffff00" offset="1" />
    </linearGradient>
  </defs>
</svg>

<svg
  class="svg-gradient"
  xmlns="<http://www.w3.org/2000/svg>"
  width="24"
  height="24"
  viewBox="0 0 24 24"
>
  <path
    d="M12 2a9 9 0 0 0-9 9v11l3-3l3 3l3-3l3 3l3-3l3 3V11a9 9 0 0 0-9-9M9 8a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2m6 0a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2a2 2 0 0 1 2-2Z"
  />
</svg>

只需要我们把第一个表示颜色定义的svg放在全局预先加载,然后给定义的渐变色起一个有意义的名字,然后我们就可以在任意地方直接在svg的样式上告知需要采用的fill颜色即可 fill: url(#my-gradient);

颜色的切换就变成了 fill 属性的切换,这样就和单色图标一样了。

需要注意的是需要给用于声明的svg的宽高设为0,不然浏览器会给一个默认的宽高,会影响整体的布局。

最终看下成品效果:

相关推荐
java1234_小锋5 小时前
【技术专题】HTML5 网页技术 - HTML5 Canvas 基础以及动画入门
前端·html·html5
知了学历孙老师8 小时前
小自考的校考和统考,出题方和难度差在哪
java·大数据·前端
ShineWinsu10 小时前
对于JavaScript:操作元素的解析
开发语言·前端·javascript·面试·web·dom·元素
福兮说11 小时前
JSON 格式正确,数据就可靠吗?我用一份自编配置检查类型与空值
java·前端·json
程序员老赵13 小时前
Docker 部署青龙面板:轻松搭建定时任务管理平台
前端·docker·开源
Swot13 小时前
Asciidoctor 公式数字下标错位问题:原因分析与解决方案
前端
Swot13 小时前
leo-editor 中将 Markdown 内容转成 asciidoc 格式
前端
狒狒AI13 小时前
Remotion / GSAP+Three / HyperFrames / Skia 四栈实测:代码渲染知识视频的选栈方法(附开源技能)
前端·人工智能·aigc
修炼的dance13 小时前
浏览器里导出H.265,8.5秒和55.5秒差在硬件
前端
补码缩写13 小时前
WebCodecs选编码器,探测之后还要验解码和播放
前端