改变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>
相关推荐
掘金者阿豪2 分钟前
电商视觉要被 Agent 重做了:一个平台跑通主图、详情页、实拍、复刻和视频
前端
爱勇宝15 分钟前
《道德经》第 13 章:别让评价系统控制你的心
前端·后端·产品
掘金者阿豪19 分钟前
集中式与分布式数据库怎么选?从架构原理到电科金仓的实践思考
前端·后端
墨林陌43 分钟前
AI 热点日报(2026-11-06):乌镇峰会闭幕发布全球开源AI倡议,腾讯混元Hy4发布即开源
前端
亿元程序员1 小时前
8年游戏主程从公司毕业了,能干些啥?
前端
Cosolar1 小时前
极简智库(MiniDocs):docsify、VitePress、Notion 等知识库搭建服务的完美替代
前端·后端·架构
涛涛ing1 小时前
那些“每个决定都正确”的项目,最后是怎么烂掉的
前端
徐小夕2 小时前
万字长文!DeepSeek Super-agent × 企业知识库架构深度拆解与落地实践
前端·vue.js·github
陈随易2 小时前
TanStarter,从搭建到支付,一步到位开始赚美元
前端·后端·程序员
前端双越老师3 小时前
程序员 1v1 访谈系列第十二期:普通人没有核心竞争力
前端·ai编程·全栈