改变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>
相关推荐
0wioiw012 分钟前
Flutter基础(前端教程④-组件拼接)
前端·flutter
花生侠37 分钟前
记录:前端项目使用pnpm+husky(v9)+commitlint,提交代码格式化校验
前端
一涯44 分钟前
Cursor操作面板改为垂直
前端
我要让全世界知道我很低调1 小时前
记一次 Vite 下的白屏优化
前端·css
1undefined21 小时前
element中的Table改造成虚拟列表,并封装成hooks
前端·javascript·vue.js
蓝倾1 小时前
淘宝批量获取商品SKU实战案例
前端·后端·api
comelong2 小时前
Docker容器启动postgres端口映射失败问题
前端
花海如潮淹2 小时前
硬件产品研发管理工具实战指南
前端·python
用户3802258598242 小时前
vue3源码解析:依赖收集
前端·vue.js