em's or rem's instead of px?
zenopopovici opened this issue · comments
Hey,
Would it be possible to specify sizes in em's or rem's?
I would make things easier with responsive sites.
In theory, the sprite (along with the icons) should resize without a hitch on font-size changes on the body element.
Zeno.
Hey @zenopopovici,
the answer to this is a little more complex than a simple "Yes" or "No". You are referring to the dimensions used for the *-dims
CSS rules, right?
Of course the single icons (and thus the sprite as a whole) have dimensions. These are derived from the size of the elements of the original SVG files — and there is no such thing as em
(or rem
) in SVG. SVG is based on Pixels (or at least something equivalent), thus are the resulting dimensions. There is no way around this.
On the other hand, it's totally up to you to completely ignore the auto-generated dimensions (e.g. skip them altogether via dims: false
) and use your own sizing system. Just implement your own mechanism by modifying the Mustache templates or using your own custom stylesheets with appropriate CSS rules. This is not a job for svg-sprite, you may do this at any time.
Cheers,
Joschi
Hey,
You're overthinking it. I'm talking about the generated css/less file. Just about adding an option to write em or rem instead of px to the generated values.
Zeno
Well, as I said: I don't think this should be part of svg-sprite's job, instead you can do this yourself at any time, tailored to your specific setup. You can't just exchange px
with em
— that wouldn't make any sense. There would always have to be a factor involved (like e.g. 16px
= 1em
) — which could also depend on client settings by the way. I don't know too much about LESS, but in Sass you should easily be able to achieve this by modifying the rendering template like this (untested!):
...
width: #{{{width}}/16}em;
height: #{{{height}}/16}em;
...
Yes, I meant also dividing the result it by 16. I replied on the phone and your reply was a bit clipped. Sorry for that I asked if there is an option to do that.
If you do responsive design, you end up using em's or rem's and modify font-size on the body. Everything scales besides the generated sprite, because the sprite less/sass file is generated in fixed values (px). Who uses px for other than borders anymore? :)
Thanks for the support. I'll edit the rendering template to achieve that.
Who uses px for other than borders anymore? :)
This could've been my words. ;) We do responsive designs exclusively, so I'm totally understanding what your intentions are. Good look!
Doesn't work ... don't know if mustache can do calculations like that. I'm new to mustache so I'll have to dig a bit. Also a background-size of the sprite would be required to make this happen.
Just to clarify: Mustache doesn't do any calculation, but the Sass processor does (and LESS as well, i guess), so you have to output the appropriate code for the processor you use. The above example was untested though ... Cheers, Joschi
I'm working at that. Just a question: is there a variable that holds the background-size of the sprite? Without that it's kind of impossible to do any responsive resizing.
I understand it's not like a png sprite, but nevertheless if I take the size values from a png file I'm generating from the svg, placing them as background-size in rem for the svg, and converting px units to rem I'm getting the desired results: A responsive svg sprite.
Also background-position is made up of 2 values. Is it possible to split them?
Thanks for the patience and support.
Hi @zenopopovici,
please have a look at the svg-sprite documentation, especially the swidth
and sheight
respectively the positionX
and positionY
variables. These should answer your questions.
Cheers,
Joschi
Brilliant. Thanks. I've nailed it.
Congratulations! It would be nice if you could post your result (modified template) here for others as a reference. :) Cheers, Joschi
Got carried away. Of course. Here they are:
Mustache template for responsive resizing of the sprite via rem values for LESS
.{{prefix}}{{^common}}(){{/common}} {
background-repeat: no-repeat;
background-image: url({{{sprite}}});
background-size: {{swidth}} * @rem {{sheight}} * @rem;
}
{{#svg}}{{#selector}}.{{expression}}{{^last}},
{{/last}}{{/selector}} {
background-position: {{positionX}} * @rem {{positionY}} * @rem;{{^common}}
.{{prefix}}();{{/common}}
}{{#dims}}{{#dimensions}}
{{#selector}}.{{expression}}{{^last}},
{{/last}}{{/selector}} {
width: {{width}} * @rem;
height: {{height}} * @rem;
}{{/dimensions}}{{/dims}}
{{/svg}}
Needed vars for rem conversion (use them in your main less vars file):
@base-font-size: 100%;
@base-font-size-px: 16;
@rem: (1 / @base-font-size-px) + 0rem;
use dim:true
in the grunt-svg-sprite configuration.
I'm trying to do this too, but i don't know how to call the mustache template in my grunt configuration. I can't see in the docs what the option is. Any help or just a paste of the grunt config may do it?
Hey @dildeeplehal,
depending on your setup, the option will be something like
mode.css.render.less {
template: 'path/to/your/template.less',
dest: 'result/name/and/path.less'
}
Please see here for more info on rendering configurations (and bear in mind that the configuration has completely changed since @zenopopovici asked this).
Thanks, I've managed to get it calling my template. Now i need to work out what needs to go in that template so it's in EM units. Where is the documentation for the templating variables so i can work out what to do: I saw this in your files:
{{#shapes}}{{#selector.shape}}.{{#classname}}{{expression}}{{/classname}}{{^last}},
{{/last}}{{/selector.shape}} {
background-position: {{position.relative.xy}};
background-repeat: no-repeat;
background-image: url({{{sprite}}});
width: {{width.outer}}px;
height: {{height.outer}}px;
}
{{/shapes}}
I want to make the background-positon and width/height in ems so to make this responsive.
i don't know how i can write a sass calculation in there {{width.outer}}/13 + em. It doesn't work for me.
Hey @dildeeplehal,
please be aware that as of the 1.x release, svg-sprite uses percentages for placing the background images. They should be perfectly responsive out of the box. I don't see any advantage in rewriting it to use em
s. If you insist on doing so, you would have to tinker with the position.{relative|absolute}.{x|y|xy}
values. The documentation for the available variables can be found here (next time, you might just want to use the README to find it).
Cheers,
Joschi
Thanks again, i found it eventually.
But still, the background-position uses percentages, but the width and height are set using px, so i cant resize them responsively.
Sure you can. Please see this internal test page under the "Relative (%)" section.
I've updated it for the current version. Configuration for LESS:
Grunt File
svg_sprite: {
less_sprite : {
expand: true,
cwd: 'assets/images/svg',
src: ['*.svg'],
dest: 'assets/images/',
options: {
mode: {
css: {
bust: false,
dest: '',
common: '',
prefix: 'svg-',
sprite: 'sprite.svg',
render: {
less: {
template: 'sprite-mustache.less',
dest: 'sprite.less'
}
}
}
}
}
}
},
The Mustache Template
.{{mixin}}{{^common}}(){{/common}} {
background-repeat: no-repeat;
background-image: url(../images/{{{sprite}}});
background-size: {{spriteWidth}} * @rem {{spriteHeight}} * @rem;
}
{{#shapes}}{{#selector.shape}}{{expression}}{{^last}},
{{/last}}{{/selector.shape}} {
background-position: {{position.absolute.x}} * @rem {{position.absolute.y}} * @rem;{{^common}}
.{{mixin}}();{{/common}}{{#dimensions.inline}}
width: {{width.outer}} * @rem;
height: {{height.outer}} * @rem;{{/dimensions.inline}}
}{{#dimensions.extra}}
{{#selector.dimensions}}{{expression}}{{^last}},
{{/last}}{{/selector.dimensions}} {
width: {{width.outer}} * @rem;
height: {{height.outer}} * @rem;
}{{/dimensions.extra}}
{{/shapes}}
Vars for conversion
@base-font-size: 100%;
@base-font-size-px: 16;
@rem: (1 / @base-font-size-px) + 0rem;
Anyway. Just great work. I use it for all my projects. ;)
Thanks a lot for sharing this, @zenopopovici! 👍
@dildeeplehal here's the config for SASS if you really want to use ems/rems:
Drop this in your mixins file:
@function em($target, $context: $base-font-size) {
@if $target == 0 { @return 0 }
@return $target / $context + 0em;
}
$base-font-size: 16px;
Modify your Mustache template like this:
.{{mixin}}{{^common}}(){{/common}} {
background-repeat: no-repeat;
background-image: url({{{sprite}}});
background-size: em({{spriteWidth}}) em({{spriteHeight}});
}
{{#shapes}}{{#selector.shape}}{{expression}}{{^last}},
{{/last}}{{/selector.shape}} {
background-position: em({{position.absolute.x}}) em({{position.absolute.y}});{{^common}}
background-position: {{position.relative.xy}};{{^common}}
.{{mixin}}();{{/common}}{{#dimensions.inline}}
width: em({{width.outer}});
height: em({{height.outer}});{{/dimensions.inline}}
}{{#dimensions.extra}}
{{#selector.dimensions}}{{expression}}{{^last}},
{{/last}}{{/selector.dimensions}} {
width: em({{width.outer}});
height: em({{height.outer}});
}{{/dimensions.extra}}
{{/shapes}}
I haven't tested it but it should to the trick.
@jkphl sure thing :)
Thanks for your help guys. I've implemented that. Had to change some stuff in the mustache template to get it to work in sass and it has basically done what i wanted to do now. Needs a bit of refining but on the right track now. It was tough getting around the Mustache syntax because i'm not familiar with that. :)
Glad it works for you now! :)