Как использовать 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 & Spritesheets

Подгоните к размеру контейнера ;

Использование SVG в качестве фонового изображения

... но даже после всего этого мне не удалось найти решение.

РЕДАКТИРОВАТЬ: я забыл упомянуть, это должно работать в IE9. Я уверен, что это немного проблематично, но поддержка SVG в IE9 приличная, поэтому я выбрал SVG для этого проекта.

2 ответа

Решение

По сути, я хочу знать, есть ли более простой способ определить ячейки в таблице спрайтов и упростить CSS, который я использую, чтобы указать каждому элементу div, какой значок отображать в таблице спрайтов.

Нет, ты не можешь сделать это проще.

Попробуйте эту статью

Тогда есть проблема масштабирования. С этой настройкой SVG масштабируется до соответствующего размера, который будет отображаться на экране, но если я решу увеличить масштаб, используя масштаб в моем браузере, он пикселизируется. Это не то, как SVG должен работать.

В Chromium 18 это выглядит довольно хорошо - вообще нет пикселизации.

В моем списке тестовых браузеров (FF3.6 Opera 9.2 IE6) я не увидел то, что увидел в Chromium

А насчет IE9, может проблема в движке

Если ваши значки имеют одинаковый размер, вы можете сделать следующее:

  1. Упакуйте свои иконки в спрайт горизонтально (используйте svg-sprite, если иконки находятся в отдельных файлах).
  2. Задавать background-size: auto 100%; для вашего целевого селектора.
  3. Установите целевые элементы 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>

Другие вопросы по тегам