打工人必备!实现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,不然浏览器会给一个默认的宽高,会影响整体的布局。

最终看下成品效果:

相关推荐
吃饭睡觉打豆豆嘛15 小时前
深入剖析 Promise 实现:从原理到手写完整实现
前端·javascript
前端端15 小时前
claude code 原理分析
前端
GalaxyMeteor15 小时前
Elpis 开发框架搭建第二期 - Webpack5 实现工程化建设
前端
Spider_Man15 小时前
从 “不会迭代” 到 “面试加分”:JS 迭代器现场教学
前端·javascript·面试
我的写法有点潮15 小时前
最全Scss语法,赶紧收藏起来吧
前端·css
小高00715 小时前
🧙‍♂️ 老司机私藏清单:从“记事本”到“旗舰 IDE”,我只装了这 12 个插件
前端·javascript·vue.js
Mo_jon15 小时前
css 遮盖滚动条,鼠标移上显示
前端·css
EveryPossible15 小时前
终止异步操作
前端·javascript·vue.js
Stringzhua16 小时前
setup函数相关【3】
前端·javascript·vue.js
neon120416 小时前
解决Vue Canvas组件在高DPR屏幕上的绘制偏移和区域缩放问题
前端·javascript·vue.js·canva可画