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-...

相关推荐
蓝鲸屿2 分钟前
JS基础第九天——对象(2)+Random
开发语言·前端·javascript
全栈练习生3 分钟前
ESModule的工作原理是什么
前端
疯狂的沙粒21 分钟前
Vue 前端大屏做多端屏幕适配时,如何让其自动适配多种不同尺寸的屏幕?
前端·javascript·vue.js
范小多25 分钟前
24小时学会Python Visual code +Python Playwright通过谷歌浏览器取控件元素(连载、十一)
服务器·前端·python
ooolmf26 分钟前
matlab2024读取温度01
java·前端·javascript
打工人小夏27 分钟前
前端vue3项目使用nprogress动画组件,实现页面加载动画
前端
一颗宁檬不酸29 分钟前
前端农业商城中产品产地溯源功能的实现
前端
李少兄36 分钟前
深入理解前端中的透视(Perspective)
前端·css
江公望1 小时前
HTML5 History 模式 5分钟讲清楚
前端·html·html5
云和数据.ChenGuang1 小时前
Zabbix Web 界面安装时**无法自动创建配置文件 `zabbix.conf.php`** 的问题
前端·zabbix·运维技术·数据库运维工程师·运维教程