CSS 技巧 | 如何给 svg 改颜色

场景描述

当鼠标移到卡片上,svg 格式的 icon 颜色可以变化

这个需求实现方式有很多,最基本的可以通过监听鼠标移入/移出事件,准备两套图片,根据状态切换:

JSX 复制代码
import React, { useState } from 'react';

const [imgSrc,setImgSrc] = useState();

var example = document.getElementById("example");
example.addEventListener("mouseover", function(){
    console.log("鼠标移入了元素");
    setImgSrc(iconLight) // 更新图片src为亮色图
});
example.addEventListener("mouseout", function(){
    console.log("鼠标移出了元素");
    setImgSrc(iconDark) // 更新图片src为暗色图
});

但挺麻烦,如果容器中每个item的图片都不一样,那图片一共要准备 2N 张,还有大量的状态切换会让代码脏乱。

进阶偷懒

我不想整这么多图,也不想搞这么多状态!

能不能直接给 icon 改个色直接用就行呢?可以,用SVG(因为我写的是个内部工具小需求,自由度比较高,以下描述的方法仅适合纯色的 icon 图)

前置准备

由于是小需求,所以 icon 也没设计同事出,所以直接去开源的网站拿。

我用的是 iconfont: https://www.iconfont.cn/ 接下来的例子用到的资源都这里找的。

进入 icon 图标库,随便点一个,发现有多种方式获取icon资源。接下来有两种解法可以实现:

方法一:引入 svg 代码,修改 fill 颜色

点击复制 SVG 代码,会得到如下内容:

JSX 复制代码
<svg
  t="1699337638484"
  class="icon" // 我用的 JSX 所以一会要改用className
  viewBox="0 0 1024 1024"
  version="1.1"
  xmlns="http://www.w3.org/2000/svg"
  p-id="1322"
  width="16"
  height="16">
  <path
    d="M373.08 481.35q-28.51 2.28-57.12 2.28t-57.46-2.28a96.2 96.2 0 0 1-88.24-88.24q-2.26-28.6-2.26-57.29t2.29-57.3a96.2 96.2 0 0 1 88.24-88.23q28.56-2.29 57.26-2.29t57.29 2.29a96.2 96.2 0 0 1 88.24 88.23q2.28 28.61 2.29 57.3t-2.29 57.29a96.2 96.2 0 0 1-88.24 88.24zM628.1 480.83q-22-18.76-42.47-39.21t-39.45-42.72a97.26 97.26 0 0 1 0-126.17q18.81-22.08 39.33-42.59t42.59-39.33a97.26 97.26 0 0 1 126.17 0q22.08 18.81 42.6 39.33t39.32 42.59a97.26 97.26 0 0 1 0 126.17q-18.81 22.1-39.32 42.6t-42.6 39.33a97.28 97.28 0 0 1-126.17 0zM373.08 856.74Q344.57 859 316 859t-57.46-2.29a96.2 96.2 0 0 1-88.24-88.23q-2.28-28.6-2.29-57.3t2.29-57.29a96.2 96.2 0 0 1 88.24-88.24q28.59-2.28 57.29-2.28t57.29 2.28a96.2 96.2 0 0 1 88.24 88.24q2.28 28.61 2.29 57.29t-2.29 57.3a96.2 96.2 0 0 1-88.28 88.26zM748.48 856.74Q720 859 691.36 859t-57.47-2.29a96.2 96.2 0 0 1-88.23-88.23q-2.29-28.6-2.29-57.3t2.29-57.29a96.2 96.2 0 0 1 88.23-88.24q28.61-2.28 57.3-2.28t57.29 2.28a96.21 96.21 0 0 1 88.24 88.24q2.28 28.64 2.28 57.32t-2.28 57.3a96.21 96.21 0 0 1-88.24 88.23z"
    p-id="1323"
    fill="#2c2c2c"></path>
</svg>

可以看到 path 标签里有一个属性叫 fill ,这个值决定了 icon 的颜色。

如果用网站自带的颜色选择器,选了颜色后再复制 SVG 代码就会的到带该属性内容。但这个内联值(优先级高)影响了我们通过 className 赋予 icon 颜色。所以要删掉,然后用 css 伪类 :hover 实现颜色变化。

JSX 复制代码
<svg
  t="1699337638484"
  className="logo"
  viewBox="0 0 1024 1024"
  version="1.1"
  xmlns="http://www.w3.org/2000/svg"
  p-id="1322"
  width="16"
  height="16">
  <path
    d="M373.08 481.35q-28.51 2.28-57.12 2.28t-57.46-2.28a96.2 96.2 0 0 1-88.24-88.24q-2.26-28.6-2.26-57.29t2.29-57.3a96.2 96.2 0 0 1 88.24-88.23q28.56-2.29 57.26-2.29t57.29 2.29a96.2 96.2 0 0 1 88.24 88.23q2.28 28.61 2.29 57.3t-2.29 57.29a96.2 96.2 0 0 1-88.24 88.24zM628.1 480.83q-22-18.76-42.47-39.21t-39.45-42.72a97.26 97.26 0 0 1 0-126.17q18.81-22.08 39.33-42.59t42.59-39.33a97.26 97.26 0 0 1 126.17 0q22.08 18.81 42.6 39.33t39.32 42.59a97.26 97.26 0 0 1 0 126.17q-18.81 22.1-39.32 42.6t-42.6 39.33a97.28 97.28 0 0 1-126.17 0zM373.08 856.74Q344.57 859 316 859t-57.46-2.29a96.2 96.2 0 0 1-88.24-88.23q-2.28-28.6-2.29-57.3t2.29-57.29a96.2 96.2 0 0 1 88.24-88.24q28.59-2.28 57.29-2.28t57.29 2.28a96.2 96.2 0 0 1 88.24 88.24q2.28 28.61 2.29 57.29t-2.29 57.3a96.2 96.2 0 0 1-88.28 88.26zM748.48 856.74Q720 859 691.36 859t-57.47-2.29a96.2 96.2 0 0 1-88.23-88.23q-2.29-28.6-2.29-57.3t2.29-57.29a96.2 96.2 0 0 1 88.23-88.24q28.61-2.28 57.3-2.28t57.29 2.28a96.21 96.21 0 0 1 88.24 88.24q2.28 28.64 2.28 57.32t-2.28 57.3a96.21 96.21 0 0 1-88.24 88.23z"
    p-id="1323"></path>
</svg>
SCSS 复制代码
.logo {
  width: 30px;
  height: 30px;
  fill: #249ffd;
}

.logo:hover {
  width: 30px;
  height: 30px;
  fill: #ffffff;
}

方法二:引入 svg 图片,修改 drop-shadow

方法一会导致代码里出现大量的 svg 标签,又会导致代码脏乱。能更简单一点吗?

可以,不过要用奇技淫巧:CSS3 滤镜 filter 中的 drop-shadow https://developer.mozilla.org/zh-CN/docs/Web/CSS/filter-function/drop-shadow

下载svg图片到本地,然后 import 引入。通过 filter: drop-shadow 修改投影颜色改变 icon 颜色

JSX 复制代码
import logo from './logo.svg';

<img
  className="logo"
  style={{ transform: 'translate(-100px)' }}
  src={logo}
/>
SCSS 复制代码
.item {
  overflow: hidden;  // 用父级超出范围裁掉,隐藏投影
}
.logo {
  width: 30px;
  height: 30px;
  filter: drop-shadow(100px 0 0 #249ffd);
}

.logo:hover {
  width: 30px;
  height: 30px;
  filter: drop-shadow(100px 0 0 #ffffff);
}

为什么说是奇技淫巧呢?归根到底还是兼容性的问题,看你的用户受众,合理使用技巧。

参考文档

  1. PNG格式小图标的CSS任意颜色赋色技术:www.zhangxinxu.com/wordpress/2...

  2. CSS3 filter:drop-shadow滤镜与box-shadow区别应用:www.zhangxinxu.com/wordpress/2...

  3. img标签使用svg改变颜色:lhalcyon.com/change-svg-...

相关推荐
Martin -Tang15 分钟前
vite和webpack的区别
前端·webpack·node.js·vite
迷途小码农零零发16 分钟前
解锁微前端的优秀库
前端
王解1 小时前
webpack loader全解析,从入门到精通(10)
前端·webpack·node.js
我不当帕鲁谁当帕鲁1 小时前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis
那一抹阳光多灿烂1 小时前
工程化实战内功修炼测试题
前端·javascript
放逐者-保持本心,方可放逐2 小时前
微信小程序=》基础=》常见问题=》性能总结
前端·微信小程序·小程序·前端框架
毋若成4 小时前
前端三大组件之CSS,三大选择器,游戏网页仿写
前端·css
红中马喽4 小时前
JS学习日记(webAPI—DOM)
开发语言·前端·javascript·笔记·vscode·学习
Black蜡笔小新5 小时前
网页直播/点播播放器EasyPlayer.js播放器OffscreenCanvas这个特性是否需要特殊的环境和硬件支持
前端·javascript·html
秦jh_6 小时前
【Linux】多线程(概念,控制)
linux·运维·前端