svg-sprite / grunt-svg-sprite

SVG sprites & stacks galore — Grunt plugin wrapping around svg-sprite that reads in a bunch of SVG files, optimizes them and creates SVG sprites and CSS resources in various flavours

Home Page:https://github.com/svg-sprite/svg-sprite

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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 ems. 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! :)