Подтвердить что ты не робот

Как использовать SVG Sprite Sheet в качестве фонового изображения CSS при сохранении соотношения сторон и масштабируемости

TL; DR: Я хочу использовать несколько значков, выложенных на листе SVG sprite в качестве фоновых изображений CSS, которые сохраняют их соотношение сторон и автоматически масштабируются, чтобы заполнить родительский элемент, используя только SVG и CSS. Нет JavaScript, пожалуйста.


Итак, у меня есть spritesheet в формате 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. Определение ячеек в spritesheet немного более беспорядочно, чем хотелось бы. Вот страница, на которой я показываю эти значки:

<!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>

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

Я бы предпочел, чтобы это решение было строго SVG и CSS; Я не заинтересован в использовании библиотек JavaScript. Я собираюсь довести это до точки, где я могу просто определить ячейки и иметь конкретный значок, который я намереваюсь автоматически масштабировать, чтобы соответствовать его контейнеру, сохраняя при этом его соотношение сторон. В настоящее время для того, чтобы значок соответствовал его родительскому контейнеру, его ширина и высота должны быть явно определены и соответствовать ширине и высоте родительского контейнера. Если я изменяю ширину и высоту родительского контейнера, мне также нужно изменить размеры фоновой позиции.

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

Я полагаю, я мог бы просто поместить каждый значок в свой собственный файл, потому что это работает чудесно, но мне просто очень нравится использовать спрайты; он не только сохраняет мне несколько запросов сервера, но и просто классно.

Я знаю загрузчик значков SVG. Это довольно круто, но это еще один файл JavaScript, на который я бы предпочла не полагаться.

Я уже прочитал w3 SVG-документы, MDV-документы SVG и следующие потоки в SO:

SVG и спрайты

Fit <svg> к размеру <object> контейнер

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

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

EDIT: Я забыл упомянуть, что это необходимо для работы в IE9. Это немного проблема, я уверен, но поддержка IE9 SVG достойна, поэтому я выбрал SVG для этого проекта.

4b9b3361

Ответ 1

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

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

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

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

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

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

И про IE9, может быть, проблема в двигателе

Ответ 2

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

  • Установите значки в спрайт по горизонтали (используйте 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>