TL;DR: I want to use several icons tiled in an SVG sprite sheet as CSS background-images, which maintain their aspect ratio and automatically scale to fill the parent element, using nothing but SVG and CSS. No JavaScript please.
So I have a spritesheet in SVG format, which I made with a combination of SVG-Edit and some hand-coding in Notepad++. Here's the source code:
<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>
It works fine and looks the way I want it to.
The problem is the CSS. Defining the cells in the spritesheet is a little bit messier than I would like it to be. Here's the page I'm displaying these icons in:
<!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>
Basically, I want to know if there's an easier way to define the cells in the spritesheet and simplify the CSS I use to tell each div which icon to display from the spritesheet.
I would prefer that this solution be strictly SVG and CSS; I am not interested in using JavaScript libraries. I am aiming to get it to a point where I can simply define the cells and have the particular icon I'm aiming for automatically scale to fit its container, while maintaining its aspect ratio. Currently, in order to make the icon fit its parent container, its width and height need to be explicitly defined, and match the width and height of the parent container. If I change the width and height of the parent container, I need to change the background-position sizes as well.
Then, there's the problem of scaling. With this setup, the SVG scales to the appropriate size to be drawn on-screen, but if I decide to zoom using my browser's zoom, it pixelates. This is not how SVG is supposed to work.
I suppose I could just put each icon in its own file, because that seems to work wonderfully, but I just really like using sprites; it not only saves me several server requests, it's just cool.
I am aware of SVG Icon Loader. It's pretty cool, but it's one more JavaScript file that I would rather not rely on.
I've already read the w3 SVG docs, the MDN SVG docs, and the following threads on SO:
SVG & Spritesheets
Fit <svg> to the size of <object> container
Using SVG as background image
...but even after all that, I haven't managed to find a solution.
EDIT: I forgot to mention, this needs to work in IE9. That's a bit of an issue, I'm sure, but IE9's SVG support is decent, which is why I chose SVG for this project.
SVG images can be used as background-image in CSS as well, just like PNG, JPG, or GIF. All the same awesomeness of SVG comes along for the ride, like flexibility while retaining sharpness. Plus you can do anything a raster graphic can do, like repeat.
The background-size CSS property lets you resize the background image of an element, overriding the default behavior of tiling the image at its full size by specifying the width and/or height of the image. By doing so, you can scale the image upward or downward as desired.
SVG Sprite StacksIt can't be used in an <img> , <iframe> , <object> , or as a CSS background. The method works in all browsers including Internet Explorer 9 and above. SVG stacks are less popular today, because embedding SVGs directly into the HTML has become a best-practice technique.
If your icons have the same size you can do the following:
background-size: auto 100%;
for your target selector.width
, height
or font-size
for scale..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>
Basically, I want to know if there's an easier way to define the cells in the spritesheet and simplify the CSS I use to tell each div which icon to display from the spritesheet.
No, you can't do it easier.
Try this article
Then, there's the problem of scaling. With this setup, the SVG scales to the appropriate size to be drawn on-screen, but if I decide to zoom using my browser's zoom, it pixelates. This is not how SVG is supposed to work.
In Chromium 18 it looks pretty fine - no pixelations at all.
In my test browsers list (FF3.6 Opera 9.2 IE6) I didn't see what I saw in Chromium
And about IE9, maybe problem in engine
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With