改变svg图标颜色

背景

前段时间做的一个需求,菜单的图标是通过接口返回,且在不同主题下使用不同的颜色。 接到这个需求,大脑立刻想到的做法是接口配置了N套不同主题的图标。这种做法,可能会带来的一个问题是,当存在多套主题时,同一个系统就要配置多套图标。但有时候,主题与主题之间的不同点仅仅是配色。如何通过只配置一套图标,就能在不同的主题下渲染为相应的颜色,这是这篇文章的背景了。

filter

在网络上,搜索css改变svg图标颜色,最多的推荐方式是使用css的filter,于是,我立马动起手来。

html 复制代码
<span class="menu-item-wrapper">
    <span id="menuSpan" class="menu-item-icon" />
</span>
css 复制代码
.menu-item-wrapper{
    display: inline-block;
    width: 128px;
    height: 128px;
    overflow: hidden;
}
.menu-item-icon{
    display: inline-block;
    width: 128px;
    height: 128px;
    filter: drop-shadow(#474F5E -128px 0);
    background-image: url(./home.svg);
    transform: translateX(128px);
}
.menu-item-wrapper:hover .menu-item-icon{
    filter: drop-shadow(red -128px 0);
}

在Chrome的效果如下:

初始状态:

鼠标hover后改变颜色:

但是在safari浏览器下,却会因为父元素overflow:hidden导致图标无法显示。在移动端浏览器的效果,也存在兼容问题。虽然可以通过各种修修补补的方式实现目的,但让人难受,总要担心没有测试到的浏览器,显示会异常。

-webkit-mask-box-image

虽然是不标准的语法,但是,它在safari的效果,却让人满意。

html 复制代码
<!DOCTYPE html>
<html>
    <head>
        <style>
            .menu-item-wrapper{
                display: inline-block;
                width: 30px;
                height: 30px;
                overflow: hidden;
            }
            .menu-item-wrapper:hover .menu-item-icon{
                background-color: red;
            }
            .menu-item-icon{
                display: inline-block;
                width: 30px;
                height: 30px;
                background-color: #474F5E;
                -webkit-mask-box-image: url('./home.svg') 0 0;
            }
        </style>
    </head>
    <body>
        <div>
            <span id="menuSpanWrapper" class="menu-item-wrapper">
                <span id="menuSpan" class="menu-item-icon" />
            </span>
        </div>
    </body>
</html>

初始状态:

鼠标hover后改变颜色:

当然,它也不是没有坑的,它在firefox下是不支持的。

最终方案

综合了这两个样式的特点,于是,我想到了个折中的方式: Chrome、safari,使用-webkit-mask-box-image firefox,使用filter

html 复制代码
<!DOCTYPE html>
<html>
    <head>
        <style>
            .menu-item-wrapper{
                display: inline-block;
                width: 128px;
                height: 128px;
                overflow: hidden;
            }
            .menu-item-wrapper:hover .menu-item-icon{
                background-color: red;
            }
            .menu-item-icon{
                display: inline-block;
                width: 128px;
                height: 128px;
                background-color: #474F5E;
            }
            .menu-item-icon.firefox{
                background-color: unset;
                filter: drop-shadow(#474F5E -128px 0);
                transform: translateX(128px);
            }
            .menu-item-wrapper:hover .menu-item-icon.firefox{
                background-color: unset;
                filter: drop-shadow(red -128px 0);
            }
        </style>
    </head>
    <body>
        <div>
            <span id="menuSpanWrapper" class="menu-item-wrapper">
                <span id="menuSpan" class="menu-item-icon" />
            </span>
        </div>
    </body>

    <script>
        const isFirefox = /firefox/i.test(navigator.userAgent)

        const menuSpanEl = document.getElementById('menuSpan')
        if(isFirefox) {
            menuSpanEl.classList.add('firefox')
            menuSpanEl.style.backgroundImage = 'url("./home.svg")'
        }else{
            menuSpanEl.style.webkitMaskBoxImage = 'url("./home.svg") 0 0'
        }
    </script>
</html>
相关推荐
兄弟加油,别颓废了。1 分钟前
系统全功能详细操作手册,从启动到测试
前端·chrome
ZC跨境爬虫18 分钟前
跟着 MDN 学 HTML day_32:(AbstractRange 抽象接口与 DOM 范围操作)
前端·javascript·ui·html·音视频
十子木22 分钟前
设置把所有终端移动到最前端的快捷键
前端
陈老老老板24 分钟前
Bright Data Web Scraping 实战:用 MCP + Dify 构建 eBay 商品详情采集 AI 工作流(2026)
前端·人工智能
一渊之隔33 分钟前
uniapp蓝牙搜索连接展示蓝牙设备包含信号显示
前端·网络·uni-app·bluetooth
Cisyam^39 分钟前
Bright Data Web Scraper 实战:构建 TikTok 与 LinkedIn Web Scraping 自动化 Skill(2026)
运维·前端·自动化
李剑一1 小时前
开箱即用!Vue3+TS 视频组件完整代码,自动提取视频第一帧做封面。妈妈再也不用担心我手动截封面了
前端
盐多碧咸。。1 小时前
echarts折线图矩形选择 框选图表
前端·javascript·echarts
羽沢311 小时前
Canvas学习一
前端·css·学习·canvas
KaMeidebaby1 小时前
卡梅德生物技术快报|锦葵科植物遗传转化工程化优化:棉花胚尖农杆菌转化体系参数固化与效率提升
前端