Compass sprite generating too much CSS classes - css

I am using compass to generate sprite images. And I have MANY sprite icons, and it is generating too much CSS code (too many class selectors for the background image). So lets analyze the compass sprite code:
as you can see here http://compass-style.org/help/tutorials/spriting/
#import "my-icons/*.png";
#include all-my-icons-sprites;
Will generate:
.my-icons-sprite,
.my-icons-delete,
.my-icons-edit,
.my-icons-new,
.my-icons-save { background: url('/images/my-icons-s34fe0604ab.png') no-repeat; }
.my-icons-delete { background-position: 0 0; }
.my-icons-edit { background-position: 0 -32px; }
.my-icons-new { background-position: 0 -64px; }
.my-icons-save { background-position: 0 -96px; }
If you see I use this way: <div class="my-icons-sprite my-icons-delete"></div>
I want Compass to generate this code:
.my-icons-sprite { background: url('/images/my-icons-s34fe0604ab.png') no-repeat; }
.my-icons-delete { background-position: 0 0; }
.my-icons-edit { background-position: 0 -32px; }
.my-icons-new { background-position: 0 -64px; }
.my-icons-save { background-position: 0 -96px; }
Else each new image, it'll add for background and background position. Causing too many selectors.
Is there a configuration for that?
Thanks

Have you tried this snippet for Compass?
$icons: sprite-map("icons/*.png");
i{
background: $icons;
display: inline-block; // or block
}
#each $i in sprite_names($icons){
.icn-#{$i}{
background-position: sprite-position($icons, $i);
#include sprite-dimensions($icons, $i);
}
}
This example uses the <i></i>-tag with a class containing the prefix icn- combined with the filename of the separate .png-files in your icons-folder. Like this:
<i class="icn-delete"></i>
The generated CSS looks like this:
i {
background: url('/path/to/generated/spritemap/my-icons-xxxxxxxxxxx.png');
display: inline-block;
}
.icn-delete {
background-position: 0 0;
height: 32px; // assuming the width is 32px
width: 32px; // assuming the height is 32px
}
.icn-edit{
background-position: 0 -32px;
height: 32px; // assuming the width is 32px
width: 32px; // assuming the height is 32px
}
.icn-new {
background-position: 0 -64px;
height: 32px; // assuming the width is 32px
width: 32px; // assuming the height is 32px
}
...
..
.
Still, I haven't quite figured out how to use this in combination with Compass' Magic Selectors.
Magic Selectors works very nice when you need different states (:hover, :active, :target). All you have to do is name your files like this: filename_state.png (delete_hover.png, delete_active.png etc). Compass' Magic Selectors then automatically generates css for :hover, :active and :target (delete:hover, delete_hover and delete-hover). This way you are quite free to choose how you would represent a state-change.
If you, in my first example, has filenames with the postfix for hover/ active states, the snippet only writes CSS like this:
.icn-edit_hover {
background-position: -32px -32px;
height: 32px;
width: 32px;
}
I'd really like to have it print this:
.icn-edit:hover, .icn-edit_hover, .icn-edit-hover{
background-position: 0 -32px;
height: 32px;
width: 32px;
}
like the traditional Compass' Magic Selectors does. Any idea?

In my opinion, it seems like the best of both worlds (less HTML and CSS) would be to have this code (using an attribute selector for the image):
HTML
<div class="my-icons-delete"></div>
CSS
[class^="my-icons-"] { background: url('/images/my-icons-s34fe0604ab.png') no-repeat; }
.my-icons-delete { background-position: 0 0; }
.my-icons-edit { background-position: 0 -32px; }
.my-icons-new { background-position: 0 -64px; }
.my-icons-save { background-position: 0 -96px; }
Unfortunately, I do not know how to get Compass to export like that. However, unless you are using Compass dynamically rather than just to build your back end static css, you could just change it once generated.

For anyone looking to the answer to ScottS question.
How can I use a css selector for anything starting with a baseclass
Try this:
http://codepen.io/Acts7/pen/nwsEb
I'm pasting the code below.
the spriteGen mixin requires two parameters
1) the baseclass you want to use (in ScottS case --- "myicons"
2) the second parameter is the folder location
Also DONT forget the "." before #{$mySpriteBaseClass}.
Otherwise you get >> myicons-home_icon{background-position:...}
(notice no . for class name selector)
// _custom.scss
// ---------------------------------------------------------
// Sprite Generation
--------------------- */
#include spriteGen('sprites','sprites');
// _mixins.scss
// ---------------------------------------------------------
// Sprite Generation Mixin with options
#mixin spriteGen($mySpriteBaseClass:'.spritebc',$mySpriteFolder:'sprites'){
$mySprites:$mySpriteFolder + "/*.png";
$spritefoldername-map: sprite-map($mySprites,
$spacing: 10px,
$layout: vertical
);
// if using base class as starter for sprite name class
[class^="#{$mySpriteBaseClass}"]{
/*// if using a separate base class
.#{$mySpriteBaseClass}{*/
// TODO:
// Add if/else to set width globally
// or let spriting assign it per each
//width: 48px;
//height: 48px;
display: inline-block;
vertical-align: middle;
background: $spritefoldername-map no-repeat;
}
#each $sprite in sprite_names($spritefoldername-map) {
// if using sprite base class as prefix to full sprite class name
.#{$mySpriteBaseClass}-#{$sprite} {
/*// if using separate base class and sprite name class
.#{$sprite} {*/
background-position: sprite-position($spritefoldername-map, $sprite);
#include sprite-dimensions($spritefoldername-map, $sprite);
}
}
}

What's wrong with the current output?
You can already assign my-icons-delete/edit/new/save only, this is semantic enough - it already says it's an icon and it's a delete icon.

This is what I'm currently doing, it requires Sass 3.3 though:
$icons: sprite-map('icons/*.png');
.icon {
background: $icons;
display: inline-block;
vertical-align: middle;
}
#each $i in sprite_names($icons) {
$underscore: str-index($i, _);
#if ($underscore < 1) {
.icon--#{$i} {
background-position: sprite-position($icons, $i);
#include sprite-dimensions($icons, $i);
}
} #else {
$prefix: str-slice($i, 0, $underscore - 1);
$postfix: str-slice($i, $underscore + 1);
.icon--#{$prefix}:#{$postfix} {
background-position: sprite-position($icons, $i);
}
}
}
I'm using BEM here so it assumes you'll use this like <i class="icon icon--star></i>, so if if you have a "star.png" and "star_hover.png" images it'll generate .icon--star and .icon--star:hover class names.

Related

img-replace with SASS

I created a mixin to manipulate easily images and replace, now my app it is growing and I don't know how to improve this code.
basically I have a include: #include img-replace("logo.png", 104px, 47px, inline-block); where I simple change the name of the image and define the pixels width and height.
I would like change it because now, some developers want just change that image name and not worry about the size anymore understand?
in that case the image has: width: 104px and height:47px, so they would like not to worry about it anymore since the next image can be bigger or smaller.
so guys any solution for this? thank you.
$path--rel : "../images";
#mixin img-replace($img, $w, $h, $disp: block) {
background-image: url('#{$path--rel}/#{$img}');
background-repeat: no-repeat;
width: $w;
height: $h;
display: $disp;
}
.site-logo {
#include img-replace("logo.png", 104px, 47px, inline-block);
margin-top: 8px;
margin-left: 6px;
}
Using SASS, you are able to set default values against parameters in a mixin; in your example for instance, I have specified the width to be 104px by default and the height to be 47px by default:
$path--rel: "../images";
#mixin img-replace($img, $w:104px, $h:47px, $disp:null) {
background-image: url('#{$path--rel}/#{$img}');
background-repeat: no-repeat;
width: $w;
height: $h;
#if ($disp) {display: $disp;}
}
.site-logo {
#include img-replace(
$img: "logo.png",
$disp: "inline-block"
);
margin-top: 8px;
margin-left: 6px;
}
If $w,$h or $disp are left off the default values get rendered. This essentially makes them optional.
The problem is that if you make the sizes optional, the element will have no width or height. This means the dev will still have to determine the elements' size or else it will just be 0x0 and the picture won't show!
If the problem is that the dev is too lazy to find and write the size of the images, you could always use a map to store all images and their sizes, so the function would insert the correct sizing depending on the image value. Read more here
So if i understand correctly, you want to use this mixin, by just passing the image path. But each image has a different size.
This cannot be done with SASS.
Instead, you should add your image inline, eg:
<img src="images/logo.png" alt="">
or
<img src="images/logo.png" alt="" width="104" height="74">
Otherwise the answer by #chris-spittles above is correct, meaning that you should pass the default width and height to your mixin.
And if you want to continue using the mixin you will need to pass the width and height for the images that have different dimensions.
As suggested before if you change your mixin to this -
#mixin img-replace($img, $w: null, $h: null, $disp: block) {
background-image: url('#{$path--rel}/#{$img}');
background-repeat: no-repeat;
display: $disp;
width: $w;
height: $h;
}
You can use your code flexibly without having any need to assign width and height arguments. So, now, if you write this -
.site-logo {
#include img-replace("logo.png");
margin-top: 8px;
margin-left: 6px;
}
it will get compiled to -
.site-logo {
background-image: url("../images/logo.png");
background-repeat: no-repeat;
display: block;
margin-top: 8px;
margin-left: 6px;
}
It will also preserve your previously written codes, without any changes.
Now, if you have any specific requirements, like providing default values to different types of images which a developer can assign, you can add maps in your code -
$small-img: ( w: 100px, h: 100px );
$medium-img: ( w: 200px, h: 200px );
Now you can call img-replace like this -
.site-logo {
#include img-replace("logo.png", $small-img...);
}
.site-medium-image {
#include img-replace("logo.png", $medium-img...);
}
This will get compiled to -
.site-logo {
background-image: url("../images/logo.png");
background-repeat: no-repeat;
display: block;
width: 100px;
height: 100px;
}
.site-medium-image {
background-image: url("../images/logo.png");
background-repeat: no-repeat;
display: block;
width: 200px;
height: 200px;
}
This ... makes arguments variable arguments
Sass supports "variable arguments," which are arguments at the end of
a mixin or function declaration that take all leftover arguments and
package them up as a list. These arguments look just like normal
arguments, but are followed by ...

LESS mixins with multiple parameters raises syntax error

I wrote this followed the documentation of the LESS website, the mixins part, which I thought would work but raises a syntax error:
SyntaxError: properties must be inside selector blocks, they cannot be in the
root. in less/style.less on line 3, column 3:
2 .bg (#x; #y) {
3 background-position: unit(#x, px) unit(#y, px);
4 }
Here is the Less:
.bg (#x; #y) {
background-position: unit(#x, px) unit(#y, px);
}
.mydiv (#x:0; #y:-52; #width:300px; #height: 155px) {
.bg(#x, #y);
width: #width;
height: #height;
opacity: 1;
}
.mydiv()
also if I just use only multiple parameters it cause the same error:
SyntaxError: properties must be inside selector blocks, they cannot be in the
root. in less/style.less on line 14, column 3:
13 .mydiv(#width:300px; #height: 155px) {
14 background-position: 0px -52px;
15 width: #width;
Less:
.mydiv (#width:300px; #height: 155px) {
background-position: 0px -52px;
width: #width;
height: #height;
opacity: 1;
}
.mydiv()
I don't know what's wrong with it...please help...
quote: i'm using less with grunt-contrib-less, and less 1.4.2, in windows 8.1 x64.
You're calling .mydiv() outside the scope of CSS block, that would (hypothetically) would output incorrect CSS. something like:
/* some arbitrary css: */
body { font-family: Arial; }
a { text-decoration: underline; }
/* your mixin (invalid): */
background-position: 0px -52px;
width: #width;
height: #height;
opacity: 1;
You have to wrap the mixin call within a CSS block, something like:
.bg (#x; #y) {
background-position: unit(#x, px) unit(#y, px);
}
.mydiv (#x:0; #y:-52; #width:300px; #height: 155px) {
.bg(#x, #y);
width: #width;
height: #height;
opacity: 1;
}
.myClassThatUsesMyDiv
{
.mydiv()
/* can be with some other directives: */
background-color: transparent;
}
Using mixin containing attributes outside any other elements will result in incorrect CSS, and the error you've come across is because LESS compiler wants to prevent that.
Q: So how do I use my mixin?
A: Make sure you understand what is a mixin definition, and what is a mixin call.
I'll use simplified examples to clearly explain this.
This is mixin definition:
.sample-mixin (#color; #width: 100px) {
color: #color;
display: block;
width: #width;
}
To use such a mixin, you just call it like a function:
.sample-mixin(#eeffee); // this line is actual mixin call
Mixin call is evaluated to whole mixin content (with variables evaluated):
color: #eeffee;
display: block;
width: 100px;
Q: When calling mixins outside other block is incorrect?
A: If your mixins contains at least one attribute:
.sample-mixin (#color) {
color: #color;
}
Then calling it outside block:
.sample-mixin(#eeffee);
Results in incorrect CSS:
color: #eeffee;
But calling it inside block:
p {
.sample-mixin(#eeffee);
}
Is allright, as it results in correct CSS:
p {
color: #eeffee;
}
Q: When calling mixins outside other block is correct?
A: Only if your mixins contains nothing but blocks:
.sample-mixin (#color) {
body {
color: #color;
}
}
Then calling it outside block:
.sample-mixin(#eeffee);
Results in correct CSS:
body {
color: #eeffee;
}
Sidenote: having blocks inside mixins is not a good practice, as it can effectively confuse readers and results in higher coupling inside your CSS.

Issue with background-position in SASS mixin

I'm in the midst of creating a SASS mixin that will let me take a spritesheet of social media icons and display them, but I'm having an issue with the background-position when it's hovered over, here's the SASS code:
#mixin social-button($imgurl,$xpos,$ypos,$height,$width) {
background-image: url($imgurl);
background-position: $xpos $ypos;
display: block;
float: left;
height: $height;
width: $width;
&:hover {
background-position: 0px -$height;
}
& span {
position: absolute;
top: -999em;
}
}
And my include:
a.facebook {
#include social-button("../img/social-buttons.png",0px,0px,26px,26px);
}
If you'd like to see/use the spritesheet in action, I've uploaded it here: http://i49.tinypic.com/2evtbwp.png
Here's the HTML as well:
<a class="facebook" href="#"><span>Facebook</span></a>
Essentially the CSS output for the hover is displaying as this:
a.facebook:hover {
background-position: -26px;
}
And in Firebug it displays as this:
a.facebook:hover {
background-position: -26px center;
}
Any help is greatly appreciated, I'm pretty stumped on what I'm doing wrong at this point.. thanks!
PS. I'm going to be creating 5 of these, so I wouldn't mind creating a loop that could auto generate that for me, but at the present time it's not a huge deal, just need to get the hovers working first!
You have to add parentheses around variables when you change them to negatives otherwise it just does the math (0px - $height):
background-position: 0px (-$height);
You probably want to fix the 0px, too.

Sass Background Image mixin

I'm kind of new to Sass, but I'm attempting to create a workflow for myself. I generate "color packs" for my theme designs and need to specify the following variables for my mixin. Is there a better way to do this?:
// folder,filename,extension,repeat,x-pos,y-pos
#mixin background ($folder:style1, $img:file, $type:png, $repeat:no-repeat, $x:0, $y:0) {
background-image: url(./images/#{$folder}/#{$img}.#{$type});
background-repeat: #{$repeat};
background-position: #{$x}px #{$y}px;
}
I'm inserting like so:
#nav {
#include background(style2,myimage,png,repeat-x,10,10);
}
which yields this:
#nav {
background-image: url(./images/style2/myimage.png);
background-repeat: repeat-x;
background-position: 10px 10px;
}
I'd prefer to use CSS shorthand when possible, but I ran into errors with the output. I'd appreciate any expert advice if this is not the best way to do it.
depending on how your packs are structured/applied you might be able to use a loop to generate a bunch of generic styles. See the documentation here: http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#id35
Do you really need 3 separate components to get your image url? wouldn't: $img and then setting that to /folder/img.ext be far easier?
Also, you don't need the #{} for repeat by the way.
I hope this is what you're after… the question is not very specific in terms of what you need the outcome to actually be.
Cheers,
Jannis
Update:
Okay, I see you've updated your question (thanks for that). I believe this could be a little better for general use:
#mixin background($imgpath,$position:0 0,$repeat: no-repeat) {
background: {
image: url($imgpath);
position: $position;
repeat: $repeat;
}
}
.testing {
#include background('/my/img/path.png');
}
This will then output:
.testing {
background-image: url("/my/img/path.png");
background-position: 0 0;
background-repeat: no-repeat;
}
Or you can use the shorthand version:
#mixin backgroundShorthand($imgpath,$position:0 0,$repeat: no-repeat) {
background: transparent url(#{$imgpath}) $repeat $position;
}
.testing2 {
#include backgroundShorthand('/my/img/path.png');
}
Which will generate:
.testing2 {
background: transparent url(/my/img/path.png) no-repeat 0 0;
}
Lastly if you want to specify your base path to your image directory separately you can do the following:
$imagedir:'/static/images/'; // define the base path before the mixin
#mixin backgroundShorthandWithExternalVar($filename,$position:0 0,$repeat: no-repeat) {
background: transparent url(#{$imagedir}#{$filename}) $repeat $position;
}
.testing3 {
#include backgroundShorthandWithExternalVar('filename.png');
}
This will then generate:
.testing3 {
background: transparent url(/static/images/filename.png) no-repeat 0 0;
}
Is this what you needed?
If not feel free to update the question or reply/comment.
some other sample:
path to the image:
$path--rel : "../images";
color
$black: #000000;
creating the mixin:
#mixin background-image($img, $background-position, $background-color) {
background-image: url('#{$path--rel}/#{$img}');
background-repeat: no-repeat;
background-position: $background-position;
background-color: $background-color ;
}
using the mixing:
.navbar-inverse {
#include background-image("header.png", right, $black);
}
result:
.navbar-inverse {
background-image: url("../images/header.png");
background-repeat: no-repeat;
background-position: right;
background-color: #000000;
}
take one $var and it will make it easier for you.
$list: pranav shah
=author-images
#each $author in $list
.photo-#{$author}
background: image-url("avatars/#{$author}.png") no-repeat
.author-bio
+author-images
css
.author-bio .photo-adam {
background: url('/images/avatars/adam.png') no-repeat;
}
.author-bio .photo-john {
background: url('/images/avatars/john.png') no-repeat;
}
.author-bio .photo-wynn {
background: url('/images/avatars/wynn.png') no-repeat;
}
.author-bio .photo-mason {
background: url('/images/avatars/mason.png') no-repeat;
}
.author-bio .photo-kuroir {
background: url('/images/avatars/kuroir.png') no-repeat;
}

How to use sprite css [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Best Way to Sprite Images?
I have the following image that I want to use for users to log into site.
http://dl.dropbox.com/u/7468116/facebook_signin.png
However I am not able to make css work properly.
.sprite {
background-image: url("pathto/facebook_signin.png");
background-position: 0 0;
}
.sprite:hover {
background-position: 0 16px /*or whatever the y position of the 2nd button is*/
}
.sprite:active {
background-position: 0 32px /*or whatever the y position of the 3rd button is*/
}
Something like this should work:
a.fb {
display: block;
background: ("/path/to/sprite.png") 0 0 no-repeat; /* start with normal state */
width: 150px;
height: 18px;
text-indent: -9999px; /* for image replacement */
}
a.fb:hover,
a.fb:focus {
/* hover and focus state */
background-position: 0 -20px;
}
a.fb:active {
/* click state */
background-position: 0 -40px;
}
If you are on mac, you can use some tools for writing your CSS file automatically. These tools are ordering your sprites in an effective way and also writes CSS files for you. You don't need to fight with ordering and calculating pixel coordinates, etc. I
suggest Sprite Master.
What exactly's not working in your CSS? Spriting is involves changing the background position of the image on hover (or other states).
So it's really just
#element {
background-position-y: 10px;
}
#element:hover {
background-position-y: 0px;
}
Would be helpful to see your CSS.

Resources