我为了让客户满意而奋斗了很长时间,找到了解决方案。我使用 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,尝试设置两者和标签,但都没有结果......
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>
手动调整/缩放图标的大小以适合您所需的视图框。
您可以在 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>