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;
}
Related
What I basically want to do
#gradientType: radial-gradient;
background: #gradientType(to bottom, ...)
I want to put a CSS Function, a gradient in this case (btw: are these called functions? I'm not sure) in a Less variable and call it later with the variable like #variable()?
Why? Maintainability!
I have a file variables.less where I want to change to gradient (ie) for a couple of places on the fly.
So instead of
.a { background: linear-gradient(..) }
.b { background: linear-gradient(..) }
.c { background: linear-gradient(..) }
I would have something like
.a { background: #myGradient(..) }
.b { background: #myGradient(..) }
.c { background: #myGradient(..) }
Linear gradients (linear-gradient(to bottom, red, blue)) and Radial gradients (radial-gradient(circle, red, blue)) kind of have the same syntax. So I would have four variables like gradientType, gradientOpts, gradientStart, gradientStop and change the gradient type based on the variable. This is just a simplified example.
To answer your question directly, you can use variable interpolation to achieve this.
#myGradient: radial-gradient;
.a { background: ~"#{myGradient}(to bottom, red, blue)"; }
.b { background: ~"#{myGradient}(to bottom, green, yellow)"; }
.c { background: ~"#{myGradient}(to bottom, orange, gold)"; }
But I would suggest using something like a parameterized mixin to handle things like this. Below is the code for a sample mixin which creates either a radial-gradient or linear-gradient depending on the input variable.
#gradType: linear-gradient;
.a { .background(#gradType; to bottom; red; blue); }
.b { .background(#gradType; to bottom; green; yellow); }
.c { .background(#gradType; to bottom; orange; gold); }
.background(#gradType; #gradOpts; #gradStart; #gradEnd){
& when (#gradType = linear-gradient){
background: linear-gradient(#gradOpts, #gradStart, #gradEnd);
}
& when (#gradType = radial-gradient){
background: radial-gradient(#gradOpts, #gradStart, #gradEnd);
}
}
The catch with using guarded mixins (like the above) is that when the #gradType variable has a value outside of the two possible ones (say conical-gradient was the value) then the code would just fail and will not cause any errors to be thrown. This would be a problem when you're writing a library that is going to be used by others (and so want to throw an error when the value is invalid). In such cases, you could change the code like given below. When this approach is used, Less compiler would throw an error when an invalid input value is provided for the #gradType variable.
#gradType: linear-gradient;
.a { .background(#gradType; to bottom; red; blue); }
.b { .background(#gradType; to bottom; green; yellow); }
.c { .background(#gradType; to bottom; orange; gold); }
.background(linear-gradient; #gradOpts; #gradStart; #gradEnd){
background: linear-gradient(#gradOpts, #gradStart, #gradEnd);
}
.background(radial-gradient; #gradOpts; #gradStart; #gradEnd){
background: radial-gradient(#gradOpts, #gradStart, #gradEnd);
}
I'm trying to create a LESS mixin into which I can pass a text string to be used to construct an svg file name and a png file name.
My first attempt is below. Perhaps you can see what I'm trying to do.
.make-bg-svg(#name){
#svg: ~"../images/#{name}.svg";
#png: ~"../images/#{name}.png";
height: 200px;
background: transparent url(~"#{svg}");
.no-svg & {
background: transparent url(~"#{png}") no-repeat;
}
}
// usage
.out-of-business {
.make-bg-svg('out-of-business');
}
Any help would be appreciated.
Updated
I just figured it out and updated the example above.
Just in case you don't need that many quotes, the following is equal:
.make-bg-svg(#name) {
#svg: ~"../images/#{name}.svg";
#png: ~"../images/#{name}.png";
height: 200px;
background: transparent url(#svg);
.no-svg & {
background: transparent url(#png) no-repeat;
}
}
// usage
.out-of-business {
.make-bg-svg(out-of-business);
}
I am looking to develop this mixin further, so I can pass multiple arguements through the mixin without having to re-create the include every time e.g:
NOT THIS:
#include main-container(red);
#include main-container(blue);
BUT THIS:
#include main-container(red, blue);
Current Code
#mixin main-container-bg($name){
&.#{$name}-bg{
background:url("/images/"#{$name}"-angle-bg.png") center 78px no-repeat;
}
}
I believe I need a for statement alongside an each statement to loop my mixin though all of the arguments in the #include later in the scss.
Any idea's?
Any help is welcomed.
-Neil
You could use the #each directive and pass a list to the mixin in this way
#mixin main-container-bg($listcolours) {
#each $colour in $listcolours {
&.#{$colour}-bg{
background:url(/images/#{$colour}-angle-bg.png) center 78px no-repeat;
}
}
}
div {
#include main-container-bg((red, blue));
}
The generated CSS is
div.red-bg {
background: url(/images/red-angle-bg.png) center 78px no-repeat;
}
div.blue-bg {
background: url(/images/blue-angle-bg.png) center 78px no-repeat;
}
In my CSS I have to create classes that make reference to a 'hair colour' and 'hairstyle'
I have written a mixin to help make my CSS writing more efficient:
#mixin hair($hair, $colour) {
.hair-#{$colour} .#{$hair} {
background:image-url("xsppsfhair#{$hair}#{$colour}.svg") center top no-repeat,
image-url("xsppsheadgrey.svg") center top no-repeat,
image-url("xsppsbhair#{$hair}#{$colour}.svg") center top no-repeat;
}
}
#include hair(spikyboy, blonde);
#include hair(curlyafroboy, blonde);
This produces the following CSS
.hair-blonde .spikyboy {
background: url('../images/xsppsfhairspikyboyblonde.svg?1348681869') center top no-repeat, url('../images/xsppsheadgrey.svg?1348834673') center top no-repeat, url('../images/xsppsbhairspikyboyblonde.svg?1348682005') center top no-repeat;
}
.hair-blonde .curlyafro {
background: url('../images/xsppsfhaircurlyafroblonde.svg?1348681869') center top no-repeat, url('../images/xsppsheadgrey.svg?1348834673') center top no-repeat, url('../images/xsppsbhaircurlyafroblonde.svg?1348682005') center top no-repeat;
}
This is great, but as I have a total combination of 35 hair colours and hair styles, I still end up with way too many #includes.
On this page, it says SASS has an #each which can be used to loop through lists. There is a further example here. However, both these examples only show looping through 1 list. Is it possible to loop through two lists?
I have tried many variations of my code, but none seem to work. I thought the following would definitely work, but I just get an error message about $colour being undefined.
$hairstyle: (red, blonde, ltbrown);
$haircolour: (red, blonde, ltbrown);
#each $hair in $haircolour, $colour in $haircolour {
.hair-#{$colour} .#{$hair} {
background:image-url("xsppsfhair#{$hair}#{$colour}.svg") center top no-repeat,
image-url("xsppsheadgrey.svg") center top no-repeat,
image-url("xsppsbhair#{$hair}#{$colour}.svg") center top no-repeat;
}
.girl.hair-#{$colour} #eyelash {
background: image-url("xsppseyelash#{$colour}.svg") center top no-repeat;
}
}
Could someone please give me some pointers as to what I am doing wrong?
What you need to do is create a loop inside the first loop (I've simplified a bit so it's easier to see):
#mixin style-matrix($colors, $styles) {
#each $s in $styles {
#each $c in $colors {
.#{$s} .#{$c} {
background:image-url("xsppsfhair-#{$s}-#{$c}.svg");
}
}
}
}
$colors: blonde, brunette, auburn;
$styles: beehive, pixie, bob;
#include style-matrix($colors, $styles);
You get this output:
.beehive .blonde {
background: image-url("xsppsfhair-beehive-blonde.svg");
}
.beehive .brunette {
background: image-url("xsppsfhair-beehive-brunette.svg");
}
.beehive .auburn {
background: image-url("xsppsfhair-beehive-auburn.svg");
}
.pixie .blonde {
background: image-url("xsppsfhair-pixie-blonde.svg");
}
.pixie .brunette {
background: image-url("xsppsfhair-pixie-brunette.svg");
}
.pixie .auburn {
background: image-url("xsppsfhair-pixie-auburn.svg");
}
.bob .blonde {
background: image-url("xsppsfhair-bob-blonde.svg");
}
.bob .brunette {
background: image-url("xsppsfhair-bob-brunette.svg");
}
.bob .auburn {
background: image-url("xsppsfhair-bob-auburn.svg");
}
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.