在不使用 JS 的情况下,有没有办法在悬停期间操纵自定义 CSS 变量的字符串值?

Without using JS is there a way to manipulate the string value of a custom CSS variable during a hover?

问题:在下面的例子中,有没有办法在悬停状态下使用CSS来定位多边形的填充颜色?我需要将它从 fill:rgb(0, 0, 0) 更改为 fill:rgb(255, 255, 255)

背景: 我知道我可以用不同的填充颜色制作第二个图标并将其存储在根目录中,但这看起来很浪费。此外,我可以将 SVG 作为图像包含在我的 HTML 中并定位多边形。但就我而言,我需要使用 SVG 作为背景图像。有了这些限制,有没有办法在多边形内定位填充?

示例:

: root {
    --icon-arrowDown: url('data:image/svg+xml;utf8, <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 60"><polygon style="fill:rgb(0, 0, 0)" points="50 60 0 0 100 0 50 60"/></svg>');
}

.myIcon {
  width: 2rem;
  height: 2rem;
  background-image: var(--icon-arrowDown);
}

.myIcon:hover {
  background-image: var(--icon-arrowDown); // ?
}

如果您不能 append/insert svg 元素,您可以使用 mask-image 代替(仍然需要 browser-prefixes!)。

实际填充颜色由background-color设置 属性:

.myIcon {
  -webkit-mask-image: var(--icon-arrowDownUrl);
          mask-image: var(--icon-arrowDownUrl);
  background-color: red;
}

示例使用 mask-image

:root {
  --icon-arrowDownUrl: url("data:image/svg+xml, %3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cpolygon points='50 60 0 0 100 0 50 60'/%3E%3C/svg%3E");
}

.myIcon {
  width: 2rem;
  height: 2rem;
  -webkit-mask-image: var(--icon-arrowDownUrl);
  mask-image: var(--icon-arrowDownUrl);
  -webkit-mask-size: contain;
  mask-size: contain;
  background-color: red;
  background-repeat: no-repeat;
  transition: 0.3s;
}

.myIcon:hover {
  background-color: green;
}


/* select example */

.select-wrp {
  width: 25%;
  margin-bottom: 2em;
}

.select-wrp * {
  display: block;
  width: 100%;
  font-size: inherit;
}

.select-wrp {
  width: 25%;
  margin-bottom: 2em;
  position: relative;
}

.select-wrp * {
  display: block;
  width: 100%;
  font-size: inherit;
}

.select-custom-icon {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
}

.select-wrp:after {
  content: "";
  display: block;
  width: 1em;
  height: 1em;
  -webkit-mask-image: var(--icon-arrowDownUrl);
  mask-image: var(--icon-arrowDownUrl);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: 100% 50%;
  mask-position: 100% 50%;
  position: absolute;
  right: 0.5em;
  top: 25%;
  z-index: 10;
  background-color: red;
  pointer-events: none;
}

.select-wrp:hover:after {
  background-color: green;
}
<div class="myIcon"></div>

<div class="select-wrp">
  <select class="select-custom-icon">
    <option>Option 1</option>
    <option>Option 2</option>
    <option>Option 3</option>
    <option>Option 4</option>
    <option>Option 5</option>
    <option>Option 6</option>
  </select>
</div>

常见陷阱:
如果您需要向父标签添加图标,例如 <select>[=61,请使用 附加元素 (例如带有 css content 的伪元素) =] 否则你将屏蔽整个父元素(例如 select 字段将不可见)。请参阅示例代码段。

内联 svg – 臃肿的代码?
正如@CBroe 已经提到的:在 css 样式和动态 content/shape 操作(例如通过 js)方面,将图标附加为可重用资产无疑是最通用和最强大的方法。

但也有'semi-stylable'方法:
最值得注意的是,您还可以通过从外部文件引用的 <use> 元素向 html 添加图标,如下所示:

<svg class="myIcon" viewBox='0 0 100 100'>
  <use href="icons.svg#arrowDown" />
</svg>

假设您的 svg 源存储在同一域中!

不可否认,这个概念与内联 svg 完全不同,即外部引用的 <use> 元素缺乏一些样式功能(或者至少不受绝大多数浏览器的支持),例如:

  • 过滤器
  • clip-paths/masks
  • 模式
  • ...可能还有其他功能

示例:外部 <use> href(模拟):

<!--emulate external svg file content -->
const pseudoExtSvgs = document.querySelectorAll('.pseudoExternal');
showPseudoExternal(pseudoExtSvgs);

function showPseudoExternal(els){
    els.forEach(function(item, i){  
        let type = item.nodeName.toLowerCase();
        let svgEl = type=='img' ? item : item.querySelector('use');
        let svgSrc = type=='img' ? item.getAttribute('src') : item.querySelector('use').getAttribute('href') ;
        let svgId = svgSrc.split('.svg')[0];
        let svgTarget =  svgSrc.indexOf('#')!==-1 ? '#'+svgSrc.split('#').pop() : '';
        let svg = document.querySelector('#'+svgId);
        
        if(svg){
            if(type=='img'){
                let dataUrl = svg2DataUrl(svg)+svgTarget;
                svgEl.src = dataUrl;
            }
            if(type=='svg'){
                svgEl.setAttribute('href', svgTarget);
            }
        }
    });
}
.myIcon {
  width: 2rem;
  height: 2rem;
  transition: 0.3s;
  color: red;
}

.myIcon:hover,
.select-wrp:hover .myIcon {
  color: green;
}


/* select example */
.select-wrp {
  width: 25%;
  position: relative;
}

select {
  width: 100%;
  display: block;
  appearance: none;
}

.select-wrp .myIcon {
  display: block;
  position: absolute;
  width: 0.75em;
  height: 0.75em;
  position: absolute;
  right: 0.5em;
  top: 25%;
  z-index: 10;
  pointer-events: none;
}
<div class="myIcon">
    <svg viewBox='0 0 100 100' class="pseudoExternal">
      <use href="icons.svg#arrowDown" />
    </svg>
</div>

<div class="select-wrp">
  <select class="select-custom-icon">
    <option>Option 1</option>
    <option>Option 2</option>
    <option>Option 3</option>
    <option>Option 4</option>
    <option>Option 5</option>
    <option>Option 6</option>
  </select>
    <svg class="myIcon pseudoExternal" viewBox='0 0 100 100'>
      <use href="icons.svg#arrowDown" />
    </svg>
</div>

<!--emulated icons.svg file content -->
<svg class="svgAsset" id="icons" style="width:0; height:0; position:absolute;visibility:hidden;" xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'>
  <symbol id="arrowDown">
    <polygon fill="currentColor" points='50 60 0 0 100 0 50 60' />
  </symbol>
</svg>

(Js 部分仅用于模拟外部文件源 – 在您的本地服务器、网站空间等上测试它)

但是,避免在 svg html 主体中使用冗余 svg 代码的能力对于像图标这样的简单可重用资产来说肯定很方便。
在这种情况下,更改一些更基本的属性,如填充、颜色 stroke-width 等可能就足够了。

将您的 SVG 直接添加到 HTML 是使页面样式表完全包含在 SVG 中的唯一方法。
将 SVG 嵌入为 img 或背景图像,这使得开始变得不可能。

本文提供了有关该主题的更多信息: https://css-tricks.com/using-svg/#aa-the-problem-with-both-img-and-background-image