Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to generate a sprite with margin, without adding padding to each icon #200

Open
ghusse opened this issue Nov 10, 2016 · 15 comments
Open
Assignees
Milestone

Comments

@ghusse
Copy link

ghusse commented Nov 10, 2016

Hello,

I have an issue with generated sprites and how individual icons are displayed in the browser in the end.

With the default configuration, in some browsers, icons are sometimes displayed with a part of the icon next to them. I can see that in safari, here is an example:

aew8ees8og

I tried to used padding in the config, it worked great because it added margin around images in the generated SVG. But the drawback was that images were also larger in the CSS.

Padding is added to images dimensions in the CSS, so it does not work for me.

Is there a way to generate a stacked svg sprite with margin around images, without modifying their size?

I tried different box configuration values, but without any luck.

Thanks

@nhall
Copy link

nhall commented Jan 18, 2017

I'm trying to do the same thing. What are the different box configurations available? I don't see that information in the docs. Adding padding seems ideal here, I was surprised to see that padding increased the defined image dimensions as well. Is that intended?

@nhall
Copy link

nhall commented Jan 18, 2017

Update: I just found this conversation: #24

That seems like what we are looking for. The combination of padding: x and box: padding. Should add space around each sprite icon but not add to width and height dimensions. I couldn't get it to work though. I'm using the grunt wrapper:

svg_sprite: {
	target: {
		expand: true,
		cwd: 'images/src/icons',
		src: ['**/*.svg'],
		dest: 'images/src',
		options: {
			'dest': 'images/',
			'shape': {
				'spacing': {
					'padding': 10,
					'box': 'padding'
				}
			},
			'svg': {
				'xmlDeclaration': false,
				'doctypeDeclaration': false
			},
			'mode': {
				'css': {
					'common': 'sprite',
					'prefix': '.icon_%s',
					'dimensions': '_dims',
					'sprite': '../src/icons.svg',
					'bust': false,
					'render': {
						'less': {
							'dest': '../../css/src/imports/icons.less'
						}
					},
					'example': {
							'dest': '../icons.html'
					}
				}
			}
		}
	}
},

I can't figure out what settings I need to keep the dimensions the size of the icons, not the icons plus padding.

@ghusse
Copy link
Author

ghusse commented Jan 18, 2017

I cannot try right now if it works, but can you try with box: 'content-box' or maybe box: 'content'? @jkphl wrote it works the same as box-sizing in CSS.

@ghusse
Copy link
Author

ghusse commented Jan 18, 2017

Ok, content seems to be the default value... I expected it to be the one to use. I'll try with padding or border to see if something changes.

@nhall
Copy link

nhall commented Jan 18, 2017

@ghusse: Correct, content is the default. I tried padding but there was no change. Here is the documentation I am using.

@nhall
Copy link

nhall commented Jan 23, 2017

@jkphl: Perhaps we should be using a different setting here? Thank you.

@nhall
Copy link

nhall commented Jan 26, 2017

I took a look at this for a while and it seems like spacing.box is a property that doesn't actual do anything. Inside of lib/svg-sprite/shape.js there is a comment that reads:

* Might be 'content' (padding is added outside of the shape), 'padding' (shape plus padding will make for the given maximum size)
* or 'contain' (like 'padding', but size will be fixed instead of maximum)

If I am reading this correctly than the default value of content should be exactly what we want, the padding to be added outside of the shape. This reads like we'd need to purposefully set to padding (not the default value) to have padding added to the size.

Furthermore, I cannot find anywhere in the source where we check against the value of spacing.box. It seems as though the intentions were there when setting up lib/svg-sprite/layouter.js where I see a width.inner and height.inner set (padding is subtracted).

            width                   : {
                inner               : dimensions.width - padding.right - padding.left,
                outer               : dimensions.width
            },
            height                  : {
                inner               : dimensions.height - padding.top - padding.bottom,
                outer               : dimensions.height
            },

The rub is that there isn't a single reference to width.inner or height.inner in the project.

@vincentbernat
Copy link
Contributor

vincentbernat commented Jan 31, 2017

I am using this template to be able to use padding as margin (assuming there is equal padding on both sides):

.{{mixinName}}() {
	background: url("{{{sprite}}}") no-repeat;
}

{{#shapes}}
{{#selector.shape}}{{expression}}{{^last}},{{/last}}{{/selector.shape}} {
	.{{mixinName}}();
	background-position: ({{position.absolute.x}}px - ({{width.outer}}px - {{width.inner}}px)/2) ({{position.absolute.y}}px - ({{height.outer}}px - {{height.inner}}px)/2);
	width: {{width.inner}}px;
	height: {{height.inner}}px;
}

{{/shapes}}

This uses absolute positioning to avoid further rounding errors.

It would be more convenient to be able to have a "content-box" model, as suggested. Or a specific margin setting.

@brunobasto
Copy link

hey @vincentbernat, where exactly did you put that piece of code? I'm trying to achieve the same.

@vincentbernat
Copy link
Contributor

Put it in any file and use --css-render-less-template=... (or an equivalent option if you are not using LESS).

@brunobasto
Copy link

brunobasto commented Feb 23, 2017

Thanks @vincentbernat, I went with another option: brunobasto@9c05c34#diff-0c4330786baaab2bd590c6e37356de51R260

I'm not using it for a web project. I'm using it to arrange multiple images on a grid arrangement so that I can print to a transparency paper. Margins are essencial to distinguish one image from the other after it's printed.

@jkphl jkphl self-assigned this May 30, 2017
@jkphl jkphl added this to the 2.x milestone May 30, 2017
@panych
Copy link
Contributor

panych commented Dec 15, 2017

I've created template for Sass which can help with this issue and published as a gist. Code based on @vincentbernat solution.

@web-admin
Copy link

Hi. @vincentbernat solution is very nice and works great (I used @panych solution as well) however because of px there is no more possibility to use background-size: auto 100% and scale svg files in sprite. When I add this property to code then svg didn't work as expected. So basically I'd like to use your solution guys but on the other hand still keep the possibilities to scale svg. Do you have any good solution for that?

@Timvdv
Copy link

Timvdv commented Feb 19, 2020

I had the same issue, the artefact from the icon next to it was showing up when zoomed.

I noticed that this happened because my SVG had some properties like "transform: translate" which caused these issues. I fixed it by adding a white border around the SVG that caused the problem. Not the most elegant solution but it works fine in my case.

@applibs
Copy link

applibs commented Apr 2, 2021

I am using this template to be able to use padding as margin (assuming there is equal padding on both sides):

.{{mixinName}}() {
	background: url("{{{sprite}}}") no-repeat;
}

{{#shapes}}
{{#selector.shape}}{{expression}}{{^last}},{{/last}}{{/selector.shape}} {
	.{{mixinName}}();
	background-position: ({{position.absolute.x}}px - ({{width.outer}}px - {{width.inner}}px)/2) ({{position.absolute.y}}px - ({{height.outer}}px - {{height.inner}}px)/2);
	width: {{width.inner}}px;
	height: {{height.inner}}px;
}

{{/shapes}}

This uses absolute positioning to avoid further rounding errors.

It would be more convenient to be able to have a "content-box" model, as suggested. Or a specific margin setting.

Works but its very very stupid output:
{ background-position: calc(-770px - (24px - 16px)/2) calc(-443px - (24px - 16px)/2);width:16px;height:16px; }
My final css is 30% larger!!!
I prefer to enhance svg-sprite to real margin and not this workaround!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants