改变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>
相关推荐
踩着两条虫18 分钟前
AI 驱动的 Vue3 应用开发平台 深入探究(七):双向代码转换之 Vue源码到DSL解析
前端·vue.js·ai编程
专业流量卡19 分钟前
用ai去看源码
前端·react.js
踩着两条虫21 分钟前
AI 驱动的 Vue3 应用开发平台 深入探究(六):双向代码转换之DSL到Vue代码生成
前端·vue.js·ai编程
Wect21 分钟前
React 中的双缓存 Fiber 树机制
前端·react.js·面试
天才熊猫君21 分钟前
Vue 3 中 Watch 的陷阱:为什么异步操作后创建的监听会泄漏?
前端·javascript
梵得儿SHI22 分钟前
Vue3 生态工具实战进阶:API 请求封装 + 样式解决方案全攻略(Axios/Sass/CSS Modules)
前端·css·vue3·sass·api请求·样式解决方案·组合式api管理
有梦想的咸鱼还是咸鱼吗23 分钟前
前端必会|防抖与节流从原理到实战,解决90%高频事件卡顿问题
前端
阿诺木25 分钟前
Node.js 局域网设备发现:mDNS、UDP 广播和子网扫描
前端
盐焗乳鸽还要砂锅26 分钟前
亲手造一只有灵魂的 AI 小龙虾是种什么体验?
前端·llm·agent
YimWu27 分钟前
Opencode 核心设计-Session会话机制
前端·agent·ai编程