Как использовать SVG Sprite Sheet в качестве фонового изображения CSS при сохранении пропорций и масштабируемости
TL;DR: я хочу использовать несколько значков в листе спрайта SVG в качестве фоновых изображений CSS, которые сохраняют свои пропорции и автоматически масштабируются для заполнения родительского элемента, используя только SVG и CSS. Нет JavaScript, пожалуйста.
Итак, у меня есть таблица спрайтов в формате SVG, которую я сделал с помощью комбинации SVG-Edit и некоторого ручного кодирования в Notepad++. Вот исходный код:
<svg version="1.1"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
width="600"
height="400"
viewBox="0 0 600 400">
<!-- Created with SVG-edit - http://svg-edit.googlecode.com/ -->
<title>chosen_sprite</title>
<g>
<title>Add</title>
<rect fill="none" stroke-width="10" stroke-dasharray="null" stroke-linejoin="null" stroke-linecap="null" x="5" y="5" width="90" height="90" id="svg_1" stroke="#dcdcdc"/>
<line id="svg_2" y2="50" x2="70" y1="50" x1="30" stroke-linecap="round" stroke-linejoin="null" stroke-dasharray="null" stroke-width="12" stroke="#00a00c" fill="none"/>
<line id="svg_3" y2="30" x2="50" y1="70" x1="50" stroke-linecap="round" stroke-linejoin="null" stroke-dasharray="null" stroke-width="12" stroke="#00a00c" fill="none"/>
</g>
<g>
<title>Delete</title>
<rect fill="none" stroke-width="10" stroke-dasharray="null" stroke-linejoin="null" stroke-linecap="null" x="105" y="5" width="90" height="90" id="svg_1" stroke="#dcdcdc"/>
<line id="svg_2" y2="70" x2="170" y1="30" x1="130" stroke-linecap="round" stroke-linejoin="null" stroke-dasharray="null" stroke-width="12" stroke="#ff0000" fill="none"/>
<line id="svg_3" y2="30" x2="170" y1="70" x1="130" stroke-linecap="round" stroke-linejoin="null" stroke-dasharray="null" stroke-width="12" stroke="#ff0000" fill="none"/>
</g>
<g>
<title>Expand Dark</title>
<rect stroke="#505050" id="svg_1" height="90" width="90" y="5" x="205" stroke-linecap="null" stroke-linejoin="null" stroke-dasharray="null" stroke-width="10" fill="none"/>
<line fill="none" stroke="#000000" stroke-width="12" stroke-dasharray="null" stroke-linejoin="null" stroke-linecap="round" x1="250" y1="65" x2="280" y2="35" id="svg_2"/>
<line fill="none" stroke="#000000" stroke-width="12" stroke-dasharray="null" stroke-linejoin="null" stroke-linecap="round" x1="220" y1="35" x2="250" y2="65" id="svg_3"/>
</g>
<g>
<title>Collapse Dark</title>
<rect stroke="#505050" height="90" width="90" y="5" x="305" stroke-linecap="null" stroke-linejoin="null" stroke-dasharray="null" stroke-width="10" fill="none" id="svg_4"/>
<line fill="none" stroke="#000000" stroke-width="12" stroke-dasharray="null" stroke-linejoin="null" stroke-linecap="round" x1="350" y1="35" x2="380" y2="65" id="svg_5"/>
<line fill="none" stroke="#000000" stroke-width="12" stroke-dasharray="null" stroke-linejoin="null" stroke-linecap="round" x1="320" y1="65" x2="350" y2="35" id="svg_6"/>
</g>
<g>
<title>Expand Green</title>
<rect fill="none" stroke-width="10" stroke-dasharray="null" stroke-linejoin="null" stroke-linecap="null" x="405" y="5" width="90" height="90" id="svg_1" stroke="#dcdcdc"/>
<line id="svg_2" y2="35" x2="480" y1="65" x1="450" stroke-linecap="round" stroke-linejoin="null" stroke-dasharray="null" stroke-width="12" stroke="#00a00c" fill="none"/>
<line id="svg_3" y2="65" x2="450" y1="35" x1="420" stroke-linecap="round" stroke-linejoin="null" stroke-dasharray="null" stroke-width="12" stroke="#00a00c" fill="none"/>
</g>
<g>
<title>Collapse Green</title>
<rect fill="none" stroke-width="10" stroke-dasharray="null" stroke-linejoin="null" stroke-linecap="null" x="505" y="5" width="90" height="90" id="svg_1" stroke="#dcdcdc"/>
<line id="svg_2" y2="65" x2="580" y1="35" x1="550" stroke-linecap="round" stroke-linejoin="null" stroke-dasharray="null" stroke-width="12" stroke="#00a00c" fill="none"/>
<line id="svg_3" y2="35" x2="550" y1="65" x1="520" stroke-linecap="round" stroke-linejoin="null" stroke-dasharray="null" stroke-width="12" stroke="#00a00c" fill="none"/>
</g>
<g>
<title>Search</title>
<circle id="svg_9" r="32" cy="140" cx="60" stroke-width="8" stroke="#000000" fill="none"/>
<line id="svg_11" y2="167.5" x2="32.5" y1="190" x1="10" stroke-linecap="round" stroke-linejoin="null" stroke-dasharray="null" stroke-width="12" stroke="#000000" fill="none"/>
</g>
<g>
<title>Search 2</title>
<rect id="svg_10" stroke="#505050" height="90" width="90" y="105" x="105" stroke-linecap="null" stroke-linejoin="null" stroke-dasharray="null" stroke-width="10" fill="none"/>
<circle r="25" cy="142.5" cx="157.5" stroke-width="8" stroke="#000000" fill="none" id="svg_7"/>
<line y2="165" x2="135" y1="180" x1="120" stroke-linecap="round" stroke-linejoin="null" stroke-dasharray="null" stroke-width="12" stroke="#000000" fill="none" id="svg_8"/>
</g>
</svg>
Он отлично работает и выглядит так, как я хочу.
Проблема в CSS. Определение ячеек в таблице спрайтов немного сложнее, чем хотелось бы. Вот страница, на которой я показываю эти значки:
<!DOCTYPE html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<html>
<head>
<style>
* {padding: 0px; margin: 0px; outline: 1px solid rgba(0,0,0,0.1);}
html {width: 100%; height: 100%;}
body {width: 100%; height: 100%;}
.svgSprite {
background-image: url('./svgicons/form_icons_sprite.svg');
background-repeat: no-repeat;
background-size: 600%;
}
.svgSprite.add {
background-position: 0px 0px;
width: 12px;
height: 12px;
}
.svgSprite.delete {
background-position: -16px 0px;
width: 16px;
height: 16px;
}
.svgSprite.expandDark {
background-position: -24px 0px;
width: 12px;
height: 12px;
}
.svgSprite.collapseDark {
background-position: -36px 0px;
width: 12px;
height: 12px;
}
.svgSprite.expandGreen {
background-position: -48px 0px;
width: 12px;
height: 12px;
}
.svgSprite.collapseGreen {
background-position: -60px 0px;
width: 12px;
height: 12px;
}
.svgSprite.search {
background-position: 0px -12px;
width: 12px;
height: 12px;
}
.svgSprite.search2 {
background-position: -16px -16px;
width: 16px;
height: 16px;
}
</style>
</head>
<body>
<div class="svgSprite add"></div>
<div class="svgSprite delete"></div>
<div class="svgSprite expandDark"></div>
<div class="svgSprite collapseDark"></div>
<div class="svgSprite expandGreen"></div>
<div class="svgSprite collapseGreen"></div>
<div class="svgSprite search"></div>
<div class="svgSprite search2"></div>
</body>
</html>
По сути, я хочу знать, есть ли более простой способ определить ячейки в таблице спрайтов и упростить CSS, который я использую, чтобы указать каждому элементу div, какой значок отображать в таблице спрайтов.
Я бы предпочел, чтобы это решение было строго SVG и CSS; Я не заинтересован в использовании библиотек JavaScript. Я стремлюсь довести его до такой степени, чтобы я мог просто определить ячейки и получить конкретный значок, для которого я хочу автоматически масштабировать, чтобы соответствовать его контейнеру, сохраняя при этом его соотношение сторон. В настоящее время, чтобы значок соответствовал родительскому контейнеру, его ширина и высота должны быть явно определены и соответствовать ширине и высоте родительского контейнера. Если я изменю ширину и высоту родительского контейнера, мне нужно также изменить размеры фона.
Тогда есть проблема масштабирования. С этой настройкой SVG масштабируется до соответствующего размера, который будет отображаться на экране, но если я решу увеличить масштаб, используя масштаб в моем браузере, он пикселизируется. Это не то, как SVG должен работать.
Я полагаю, что я мог бы просто поместить каждый значок в отдельный файл, потому что это, кажется, прекрасно работает, но мне просто очень нравится использовать спрайты; это не только экономит мне несколько запросов к серверу, но и просто здорово.
Я в курсе SVG Icon Loader. Это довольно круто, но это еще один файл JavaScript, на который я бы предпочел не полагаться.
Я уже читал документы по SVG w3, документы MDG SVG и следующие темы по SO:
Использование SVG в качестве фонового изображения
... но даже после всего этого мне не удалось найти решение.
РЕДАКТИРОВАТЬ: я забыл упомянуть, это должно работать в IE9. Я уверен, что это немного проблематично, но поддержка SVG в IE9 приличная, поэтому я выбрал SVG для этого проекта.
2 ответа
По сути, я хочу знать, есть ли более простой способ определить ячейки в таблице спрайтов и упростить CSS, который я использую, чтобы указать каждому элементу div, какой значок отображать в таблице спрайтов.
Нет, ты не можешь сделать это проще.
Попробуйте эту статью
Тогда есть проблема масштабирования. С этой настройкой SVG масштабируется до соответствующего размера, который будет отображаться на экране, но если я решу увеличить масштаб, используя масштаб в моем браузере, он пикселизируется. Это не то, как SVG должен работать.
В Chromium 18 это выглядит довольно хорошо - вообще нет пикселизации.
В моем списке тестовых браузеров (FF3.6 Opera 9.2 IE6) я не увидел то, что увидел в Chromium
А насчет IE9, может проблема в движке
Если ваши значки имеют одинаковый размер, вы можете сделать следующее:
- Упакуйте свои иконки в спрайт горизонтально (используйте svg-sprite, если иконки находятся в отдельных файлах).
- Задавать
background-size: auto 100%;
для вашего целевого селектора. - Установите целевые элементы
width
,height
или жеfont-size
для масштаба.
.icon {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="64" height="16" viewBox="0 0 64 16"> <circle fill="blue" cx="8" cy="8" r="8"/> <circle fill="red" cx="24" cy="8" r="8"/> <circle fill="yellow" cx="40" cy="8" r="8"/> <circle fill="green" cx="56" cy="8" r="8"/> </svg>');
background-repeat: no-repeat;
background-size: auto 100%;
display: inline-block;
}
.icon.small {
height: 1em;
width: 1em;
}
.icon.medium {
height: 2em;
width: 2em;
}
.icon.large {
height: 4em;
width: 4em;
}
.icon_1 {
background-position: 0 0;
}
.icon_2 {
background-position: 33.33% 0;
}
.icon_3 {
background-position: 66.67% 0;
}
.icon_4 {
background-position: 100% 0;
}
<span class="icon icon_1 small"></span>
<span class="icon icon_1 medium"></span>
<span class="icon icon_2 large"></span>