精灵内的viewBox错误

问题描述 投票:0回答:1

我为了让客户满意而奋斗了很长时间,找到了解决方案。我使用 svg sprites 和标签在 css 中插入图标。它工作得很好,但是改变分辨率显然会破坏 ViewBox。就好像图标不适合其尺寸并在边缘消失。

我该怎么办?设置 viewBox 的正确方法是什么?

我的 svg 精灵:

<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <style><![CDATA[
      .sprite { display: none; }
      .sprite:target { display: inline; }
    ]]></style>
  </defs>
  <g class="sprite" id="circle">
    <circle cx="50" cy="50" r="45" stroke-width="5" stroke="#0f0" fill="#0f0" fill-opacity="0.5" />
  </g>
  <g class="sprite" id="square">
    <rect y="5" x="5" width="90" height="90" stroke-width="5" stroke="#f00" fill="#f00"
      fill-opacity="0.5" />
  </g>
  <g class="sprite" id="triangle">
    <path d="M20,7 L92,50 L6,93 z" stroke-width="5" stroke="#00f" fill="#00f" fill-opacity="0.5" />
  </g>

  <g id="popup" fill="none" class="sprite" viewBox="0 0 14 9">
    <path d="M1 1L7 7L13 1" stroke="#29354D" stroke-width="1.5" />
  </g>

  <g id="filter" class="sprite" fill="none">
    <path
      d="M21 15H14M4 15H1M21 4H18M8 4H1M6 12H12C13.1 12 14 12.5 14 14V16C14 17.5 13.1 18 12 18H6C4.9 18 4 17.5 4 16V14C4 12.5 4.9 12 6 12ZM10 1H16C17.1 1 18 1.5 18 3V5C18 6.5 17.1 7 16 7H10C8.9 7 8 6.5 8 5V3C8 1.5 8.9 1 10 1Z"
      stroke="#292D32" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round"
      stroke-linejoin="round" />
  </g>

</svg>

我的风格是这样的:

background-image: url('/sprite.svg#filter');

在 html 标记中像这样:

<svg class="popup-block__more-icon">
   <use xlink:href="sprite.svg#popup" />
 </svg>  

请帮助我。这个svg的话题已经折磨我一周了,客户很生气,时间越来越短。我无法改变我的方法,我需要准确地找出这个变体。

我尝试完全不使用viewBox,尝试设置两者和标签,但都没有结果......

css svg frontend sprite viewbox
1个回答
0
投票

SVG

<g>
组不能像
<symbol>
元素一样具有单独的 viewBox 值。

您的图标具有不同的边界框/尺寸,浏览器不会自动调整或使这些图标适合所需的布局宽度和高度。

这就是图标在 sprite svg 中的实际外观。

<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" >
  <g class="sprite" id="circle">
    <circle cx="50" cy="50" r="45" stroke-width="5" stroke="#0f0" fill="#0f0" fill-opacity="0.5" />
  </g>
  <g class="sprite" id="square">
    <rect y="5" x="5" width="90" height="90" stroke-width="5" stroke="#f00" fill="#f00" fill-opacity="0.5" />
  </g>
  <g class="sprite" id="triangle">
    <path d="M20,7 L92,50 L6,93 z" stroke-width="5" stroke="#00f" fill="#00f" fill-opacity="0.5" />
  </g>
  <g id="filter" class="sprite" >
    <path d="M21 15H14M4 15H1M21 4H18M8 4H1M6 12H12C13.1 12 14 12.5 14 14V16C14 17.5 13.1 18 12 18H6C4.9 18 4 17.5 4 16V14C4 12.5 4.9 12 6 12ZM10 1H16C17.1 1 18 1.5 18 3V5C18 6.5 17.1 7 16 7H10C8.9 7 8 6.5 8 5V3C8 1.5 8.9 1 10 1Z" stroke="#292D32" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round" fill="none" />
  </g>
  <g id="popup" fill="none" class="sprite" viewBox="0 0 14 9">
    <path d="M1 1L7 7L13 1" stroke="#29354D" stroke-width="1.5" />
  </g>
</svg>

解决方法 1:在编辑器中缩放(例如 inkscape)

手动调整/缩放图标的大小以适合您所需的视图框。

解决方法 2:将图标转换为符号/使用元素

您可以在 vanilla JS 中编写自定义转换器,以创建

<use>
元素,并通过
viewBox
方法检索适当的
getBBox()

将转换后的 svg 文件另存为新资源。现在您可以通过

<use>
放置图标(但您需要像“use_popup”这样的前缀)或
<img>
/ CSS
background-image

let svg = document.querySelector('svg');

// find icons
let icons = svg.querySelectorAll('g[id]');

icons.forEach(icon => {
  // get icon boundaries
  let {
    x,
    y,
    width,
    height
  } = icon.getBBox();

  // copy attributes like classNames or fill
  let iconClass = icon.getAttribute('class');
  let iconFill = icon.getAttribute('fill');

  // replace groups with symbols
  let ns = "http://www.w3.org/2000/svg";
  let symbol = document.createElementNS(ns, 'symbol')
  symbol.setAttribute('viewBox', `${[0, 0, width+x*2, height+y*2].join(' ')}`);
  symbol.id = icon.id;
  if (iconFill) {
    symbol.setAttribute('fill', iconFill)
  }

  // move group children to symbol
  let children = [...icon.children];
  children.forEach(child => {
    symbol.append(child)
  })
  icon.replaceWith(symbol)

  // append use instances
  let use = document.createElementNS(ns, 'use')
  let useID = `use_${icon.id}`;
  use.id = useID
  use.setAttribute('href', '#' + symbol.id);
  use.setAttribute('class', iconClass)
  svg.append(use)

})

// output converted SVG
svgOut.value = new XMLSerializer().serializeToString(svg)
img,
.img,
svg {
  border: 1px solid #ccc;
  width: 10em;
  height: 10em;
}

textarea {
  width: 100%;
  min-height: 20em;
  display: block;
}

.img {
  display: inline-block;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Cstyle%3E .sprite %7B display: none; %7D .sprite:target %7B display: inline; %7D %3C/style%3E%3Csymbol viewBox='0 0 100 100' id='circle'%3E%3Ccircle cx='50' cy='50' r='45' stroke-width='5' stroke='%230f0' fill='%230f0' fill-opacity='0.5'/%3E%3C/symbol%3E%3Csymbol viewBox='0 0 100 100' id='square'%3E%3Crect y='5' x='5' width='90' height='90' stroke-width='5' stroke='%23f00' fill='%23f00' fill-opacity='0.5'/%3E%3C/symbol%3E%3Csymbol viewBox='0 0 98 100' id='triangle'%3E%3Cpath d='M20,7 L92,50 L6,93 z' stroke-width='5' stroke='%2300f' fill='%2300f' fill-opacity='0.5'/%3E%3C/symbol%3E%3Csymbol viewBox='0 0 22 19' id='filter'%3E%3Cpath d='M21 15H14M4 15H1M21 4H18M8 4H1M6 12H12C13.1 12 14 12.5 14 14V16C14 17.5 13.1 18 12 18H6C4.9 18 4 17.5 4 16V14C4 12.5 4.9 12 6 12ZM10 1H16C17.1 1 18 1.5 18 3V5C18 6.5 17.1 7 16 7H10C8.9 7 8 6.5 8 5V3C8 1.5 8.9 1 10 1Z' stroke='%23292D32' stroke-width='1.5' stroke-miterlimit='10' stroke-linecap='round' stroke-linejoin='round' fill='none'/%3E%3C/symbol%3E%3Csymbol viewBox='0 0 14 8' id='popup' fill='none'%3E%3Cpath d='M1 1L7 7L13 1' stroke='%2329354D' stroke-width='1.5'/%3E%3C/symbol%3E%3Cuse id='use_circle' href='%23circle' class='sprite'/%3E%3Cuse id='use_square' href='%23square' class='sprite'/%3E%3Cuse id='use_triangle' href='%23triangle' class='sprite'/%3E%3Cuse id='use_filter' href='%23filter' class='sprite'/%3E%3Cuse id='use_popup' href='%23popup' class='sprite'/%3E%3C/svg%3E#use_popup");
}
<div style="position:absolute; width:0; height:0; visibility:hidden;">
  <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
  <style>
    .sprite { display: none; }
    .sprite:target { display: inline; }
   </style>
  <g class="sprite" id="circle">
    <circle cx="50" cy="50" r="45" stroke-width="5" stroke="#0f0" fill="#0f0" fill-opacity="0.5" />
  </g>
  <g class="sprite" id="square">
    <rect y="5" x="5" width="90" height="90" stroke-width="5" stroke="#f00" fill="#f00" fill-opacity="0.5" />
  </g>
  <g class="sprite" id="triangle">
    <path d="M20,7 L92,50 L6,93 z" stroke-width="5" stroke="#00f" fill="#00f" fill-opacity="0.5" />
  </g>
  <g id="filter" class="sprite" >
    <path d="M21 15H14M4 15H1M21 4H18M8 4H1M6 12H12C13.1 12 14 12.5 14 14V16C14 17.5 13.1 18 12 18H6C4.9 18 4 17.5 4 16V14C4 12.5 4.9 12 6 12ZM10 1H16C17.1 1 18 1.5 18 3V5C18 6.5 17.1 7 16 7H10C8.9 7 8 6.5 8 5V3C8 1.5 8.9 1 10 1Z" stroke="#292D32" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round" fill="none" />
  </g>
  <g id="popup" fill="none" class="sprite" viewBox="0 0 14 9">
    <path d="M1 1L7 7L13 1" stroke="#29354D" stroke-width="1.5" />
  </g>
</svg>
</div>

<h3>SVG use: </h3>
<svg>
  <use href="#popup"></use>
</svg>

<svg>
  <use href="#filter"></use>
</svg>

<h3>img: fragment identifier</h3>
<img src="data:image/svg+xml,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Cstyle%3E .sprite %7B display: none; %7D .sprite:target %7B display: inline; %7D %3C/style%3E%3Csymbol viewBox='0 0 100 100' id='circle'%3E%3Ccircle cx='50' cy='50' r='45' stroke-width='5' stroke='%230f0' fill='%230f0' fill-opacity='0.5'/%3E%3C/symbol%3E%3Csymbol viewBox='0 0 100 100' id='square'%3E%3Crect y='5' x='5' width='90' height='90' stroke-width='5' stroke='%23f00' fill='%23f00' fill-opacity='0.5'/%3E%3C/symbol%3E%3Csymbol viewBox='0 0 98 100' id='triangle'%3E%3Cpath d='M20,7 L92,50 L6,93 z' stroke-width='5' stroke='%2300f' fill='%2300f' fill-opacity='0.5'/%3E%3C/symbol%3E%3Csymbol viewBox='0 0 22 19' id='filter'%3E%3Cpath d='M21 15H14M4 15H1M21 4H18M8 4H1M6 12H12C13.1 12 14 12.5 14 14V16C14 17.5 13.1 18 12 18H6C4.9 18 4 17.5 4 16V14C4 12.5 4.9 12 6 12ZM10 1H16C17.1 1 18 1.5 18 3V5C18 6.5 17.1 7 16 7H10C8.9 7 8 6.5 8 5V3C8 1.5 8.9 1 10 1Z' stroke='%23292D32' stroke-width='1.5' stroke-miterlimit='10' stroke-linecap='round' stroke-linejoin='round' fill='none'/%3E%3C/symbol%3E%3Csymbol viewBox='0 0 14 8' id='popup' fill='none'%3E%3Cpath d='M1 1L7 7L13 1' stroke='%2329354D' stroke-width='1.5'/%3E%3C/symbol%3E%3Cuse id='use_circle' href='%23circle' class='sprite'/%3E%3Cuse id='use_square' href='%23square' class='sprite'/%3E%3Cuse id='use_triangle' href='%23triangle' class='sprite'/%3E%3Cuse id='use_filter' href='%23filter' class='sprite'/%3E%3Cuse id='use_popup' href='%23popup' class='sprite'/%3E%3C/svg%3E#use_filter"
  alt="filter">


<div class="img"></div>

<h3>SVG: converterd</h3>
<textarea id="svgOut"></textarea>

© www.soinside.com 2019 - 2024. All rights reserved.