SASS foreach on li with certain classes - css

I've been searching all over for an answer to this question for a specific issue I am looking at with SASS. I am wanting to start with an li at 100% opacity but then have it loop through the li's with certain classes and subtract 5% opacity using the transparentize function. The issue though is the foreach loop, as I don't know how many li's with a certain class I'll have. Let me see if I can explain it with code, basically I'll show you the long form and if someone can help me convert it into a short foreach that would be great.
li {
... styles are here ...
&.Language {
background-color: $red
}
&.Language.comp-1 {
background-color: transparentize($red, 0.10);
}
&.Language.comp-2 {
background-color: transparentize($red, 0.20);
}
&.Language.comp-3 {
background-color: transparentize($red, 0.30);
}
&.Language.comp-4 {
background-color: transparentize($red, 0.40);
}
&.Language.comp-5 {
background-color: transparentize($red, 0.50);
}
}
If I was going to do this in PHP this is how I would do it, I just need the SASS version:
$transparency_increment = .10
foreach( $item as $li ) {
background-color: transparentize( $red, $transparency_increment);
$transparency_increment + .10;
}
Hopefully that makes sense, I'm sure I'll have to use the nth item somewhere since the exact count will be unknown. Thanks for help in advance!

What you're looking for is the #for control directive
This should do what you want:
$red: #ff0000;
#mixin foo($prefix, $num, $step){
#for $i from 1 through $num {
#{$prefix}-#{$i} {
background-color: transparentize($red, $i * $step);
}
}
}
li {
#include foo('&.Language.comp', 10, 0.1);
}

Untested and extracted from bootstrap-sass
#mixin transparent_steps_bg($bg_color, $amount, $tranparancy_amount) {
#while $amount> 0 {
.comp-#{$amount} { background-color: transparentize($bg_color, $amount * tranparancy_amount); }
$amount: $amount - 1;
}

Related

Syntax for if/else condition in SCSS mixins

I created a SASS #mixin which contains #if conditions to assign styling to elements based on their z-index property to create some sort of elevation.
However what ever I am trying it will not work out.
I'm pretty sure I am doing something just slightly wrong that affects everything else.
I'd appreciate your feedback. Thanks in advance!
$background: #121212;
$surface: #1f1f1f;
$surface-shade_1: #282828;
$surface-shade_2: #303030;
%surface {
background-color: $surface;
}
%surface-shade_1 {
background-color: $surface-shade_1;
}
%surface-shade_2 {
background-color: $surface-shade_2;
}
#mixin elevation($elevationValue) {
#if $elevationValue>0 {
#extend %surface;
}
#else if $elevationValue>4 or $elevationValue=4 {
#extend %surface-shade_1;
}
#else if $elevationValue>8 or $elevationValue=8 {
#extend %surface-shade_2;
}
z-index: $elevationValue * 50;
}
nav {
#mixin elevation(4);
}
If you want to use #mixin inside the CSS files you can use like #include mixin-name and also use directly $elevationValue >= 4 instead of $elevationValue>4 or $elevationValue=4 it becomes much cleaner.
$background: #121212;
$surface: #1f1f1f;
$surface-shade_1: #282828;
$surface-shade_2: #303030;
%surface {
background-color: $surface;
}
%surface-shade_1 {
background-color: $surface-shade_1;
}
%surface-shade_2 {
background-color: $surface-shade_2;
}
#mixin elevation($elevationValue) {
#if $elevationValue > 0 {
#extend %surface;
}
#else if $elevationValue >= 4 {
#extend %surface-shade_1;
}
#else if $elevationValue >= 8 {
#extend %surface-shade_2;
}
z-index: $elevationValue * 50;
}
nav {
#include elevation(4);
}

Using SASS's #for for multiple selectors and 1 body [duplicate]

I'm working with the SCSS syntax of SASS to create a dynamic grid system but I've hit a snag.
I'm trying to make the grid system completely dynamic like this:
$columns: 12;
then I create the columns like this:
#mixin col-x {
#for $i from 1 through $columns {
.col-#{$i} { width: $column-size * $i; }
}
}
Which outputs:
.col-1 {
width: 4.16667%;
}
.col-2 {
width: 8.33333%;
}
etc...
This works well but what I want to do next is dynamically generate a long list of column classes separated by commas based on the number of $columns chosen - e.g I want it to look like this:
.col-1,
.col-2,
.col-3,
.col-4,
etc... {
float: left;
}
I've tired this:
#mixin col-x-list {
#for $i from 1 through $columns - 1 {
.col-#{$i}-m { float: left; }
}
}
but the output is this:
.col-1 {
float: left;
}
.col-2 {
float: left;
}
etc...
I'm a little stuck on the logic here as well as the SCSS syntax required to create something like this.
Does anyone have any ideas?
I think you may want to take a look at #extend. If you set that up something like:
$columns: 12;
%float-styles {
float: left;
}
#mixin col-x-list {
#for $i from 1 through $columns {
.col-#{$i}-m { #extend %float-styles; }
}
}
#include col-x-list;
It should render in your css file as:
.col-1-m, .col-2-m, .col-3-m, .col-4-m, .col-5-m, .col-6-m, .col-7-m, .col-8-m, .col-9-m, .col-10-m, .col-11-m, .col-12-m {
float: left;
}
#extend in the docs.
There's also a way to do what your question is specifically asking for: generate (and use) a list of classes with commas separating them. D.Alexander's response totally works in your situation, but I'm posting this alternative in case there's another use case for someone looking at this question.
Here's a Pen demonstrating: http://codepen.io/davidtheclark/pen/cvrxq
Basically, you can use Sass functions to achieve what you want. Specifically, I'm using append to add classes to my list, separated by commas, and unquote to avoid compilation conflicts with the period in the classnames.
So my mixin ends up looking like this:
#mixin col-x {
$col-list: null;
#for $i from 1 through $columns {
.col-#{$i} {
width: $column-size * $i;
}
$col-list: append($col-list, unquote(".col-#{$i}"), comma);
}
#{$col-list} {
float: left;
}
}
thnx to #davidtheclark here is a more generic version:
#mixin attr-x($attr, $attr-count: 10, $attr-steps: 10, $unit: '%') {
$attr-list: null;
#for $i from 1 through $attr-count {
$attr-value: $attr-steps * $i;
.#{$attr}#{$attr-value} {
#{$attr}: #{$attr-value}#{$unit};
}
$attr-list: append($attr-list, unquote(".#{$attr}-#{$attr-value}"), comma);
}
#{$attr-list} {
//append style to all classes
}
}
Use it like this:
#include attr-x('margin-left', 6, 5, 'px');
//or
#include attr-x('width');
The result looks like this:
.margin-left5 {
margin-left: 5px; }
.margin-left10 {
margin-left: 10px; }
...
.margin-left30 {
margin-left: 30px; }
.width10 {
width: 10%; }
.width20 {
width: 20%; }
...
.width100 {
width: 100%; }

Sass and libraries for theming [duplicate]

I'm refactoring some of my Sass code and I came across a weird issue. My code currently looks like this:
// household
$household_Sector: 'household';
$household_BaseColor: #ffc933;
// sports
$sports_Sector: 'sports';
$sports_BaseColor: #f7633e;
// the mixin to output all sector specific css
#mixin sector-css($sector_Sector,$sector_BaseColor) {
.sector-#{$sector_Sector} {
&%baseColor {
background-color: $sector_BaseColor;
}
}
}
// execute the mixin for all sectors
#include sector-css($household_Sector, $household_BaseColor);
#include sector-css($sports_Sector, $sports_BaseColor);
.product-paging {
h2 {
#extend %baseColor;
}
}
DEMO
The compiled result looks like this:
.product-paging h2.sector-household {
background-color: #ffc933;
}
.product-paging h2.sector-sports {
background-color: #f7633e;
}
But what I need is this:
.sector-household.product-paging h2 {
background-color: #ffc933;
}
.sector-sports.product-paging h2 {
background-color: #f7633e;
}
What I don't understand is why my placeholder (&%baseColor) isn't attached to the parent selector (&%baseColor) as I added the ampersand right in front of it?
Is this maybe a bug when combining & and %? Is there another solution on how to achieve what I want?
EDIT
Alright I figured out why this isn't possible. Anyway is there a workaround for what I'd like to achieve?
Extends, as you've already discovered, can get rather messy. I would go about solving your problem by using an #content aware mixin in combination with global variables (this uses mappings, which are part of 3.3... you can do it with lists of lists, but it's a little less elegant):
$base-color: null; // don't touch
$accent-color: null; // don't touch
$sections:
( household:
( base-color: #ffc933
, accent-color: white
)
, sports:
( base-color: #f7633e
, accent-color: white
)
);
// the mixin to output all sector specific css
#mixin sector-css() {
#each $sector, $colors in $sections {
$base-color: map-get($colors, base-color) !global;
$accent-color: map-get($colors, accent-color) !global;
&.sector-#{$sector} {
#content;
}
}
}
.product-paging {
#include sector-css() {
h2 {
background-color: $base-color;
}
}
}
Output:
.product-paging.sector-household h2 {
background-color: #ffc933;
}
.product-paging.sector-sports h2 {
background-color: #f7633e;
}
Update: Since you want to guarantee that the sector class is always at the top, you just need to switch around a little.
#mixin sector-css() {
#each $sector, $colors in $sections {
$base-color: map-get($colors, base-color) !global;
$accent-color: map-get($colors, accent-color) !global;
.sector-#{$sector} {
#content;
}
}
}
#include sector-css() {
&.product-paging {
h2 {
background-color: $base-color;
}
h3 {
background-color: #CCC;
}
h2, h3 {
color: $accent-color;
}
}
}

Lighten individual background-color with hover by scss - how?

I have some blocks with different background-colors (which are set in variables) and if a user hovers one of them, the color shall light/fade a bit.
Therefore I use this one:
.block1:hover,.block2:hover{
background-color:lighten($color1,40%);
}
But this just fades one static color - $color1 - to 40%. How would I do that, if .block1 had $color1 and .block2 had $color2 as background colors set? So the result should be
.block1:hover{
background-color:lighten($color1,40%);
}
.block2:hover{
background-color:lighten($color2,40%);
}
What do I need to use therefore?
Use a mixin, like so:
.block1 {
.backgroundsetup($color1);
}
.block2 {
.backgroundsetup($color2);
}
.backgroundsetup($color, $amt: 40%) {
background-color: $color;
&:hover {
background-color: lighten($color, $amt);
}
}
There's no special way to write the CSS you have in your example in SCSS, that would be the way you do it. But if you want to optimize and write less code, then you could take advantage of SASS' hashmaps and the foreach loop to do this for you.
SASS
$color1: #4e9bac;
$color2: #248cff;
$color3: #3b5998;
$blocks: (
block1: $color1,
block2: $color2,
block3: $color3,
);
#each $block, $color in $blocks {
.#{$block} {
background-color: $color;
&:hover {
background-color: lighten($color, 40%);
}
}
}
CSS Output
.block1 {
background-color: #4e9bac;
}
.block1:hover {
background-color: #d8eaee;
}
.block2 {
background-color: #248cff;
}
.block2:hover {
background-color: #f0f7ff;
}
.block3 {
background-color: #3b5998;
}
.block3:hover {
background-color: #bbc8e4;
}

Sass: Change color with #for loop

I try to darken a variable number of divs like that
with following code:
#mixin color-divs ($count, $baseName, $startcolor) {
$color: $startcolor;
#for $i from 0 through $count {
$color: darken($color, 9%);
##{$baseName}_#{$i} { background-color:$color; }
}
}
With that code I was expecting, that the variable $color is changed with every iteration but this didn't work as expected. The value is fix after the fist initialisation and every element has the same color.
Is there a way to workarround that problem or is there another way to solve that problem with a mixing?
You can darken the color using $i inside #for and apply respective classes to the divs. Hope this helps.
SCSS
#mixin color-divs ($count, $baseName, $startcolor) {
#for $i from 0 through $count {
$background-color: darken($startcolor, $i * $i);
.colored-div#{$i} {
background: $background-color;
height:100px;
width:200px;
float: left;
margin-right: 5px;
}
}
}
#include color-divs(5,'a',#ffd8b1);
HTML
<div class="colored-div1">a</div>
<div class="colored-div2">b</div>
<div class="colored-div3">c</div>
<div class="colored-div4">d</div>
<div class="colored-div5">e</div>
Demo
See demo
I created this example based on your mixin:
#mixin color-divs ($count, $baseName, $startcolor) {
$loop_color: $startcolor;
#for $i from 0 through $count {
$loop_color: darken($loop_color, 9%);
.#{$baseName}-#{$i} { background-color: $loop_color; }
}
}
div {
width: 100px;
height: 100px;
float: left;
}
#include color-divs(6,'div',#faa)
Used with the following markup:
<div class="div-1"></div>
<div class="div-2"></div>
<div class="div-3"></div>
<div class="div-4"></div>
<div class="div-5"></div>
<div class="div-6"></div>
Output: http://jsfiddle.net/jdtvF/
http://uk.omg.li/P0dF/by%20default%202013-05-16%20at%2010.10.43.png
div {
width: 100px;
height: 100px;
float: left; }
.div-0 {
background-color: #ff7c7c; }
.div-1 {
background-color: #ff4e4e; }
.div-2 {
background-color: #ff2020; }
.div-3 {
background-color: #f10000; }
.div-4 {
background-color: #c30000; }
.div-5 {
background-color: #960000; }
.div-6 {
background-color: #680000; }
To just go from one color to another, for say, a number of consecutive <div>:
#for $i from 0 through 11
&:nth-child(#{$i})
transform: rotate(#{30*$i}deg)
background-color: mix($gray1, $gray2, $i / 12 * 100% )
Notes
Note, that you don't need any #{…} inside the mix(), because it's a sass function, so it's clear that any variables and computations used insides are to be resolved before turning it into CSS.
The transform is just my use case (for demonstration). Here, one does need #{…}
and note the +/-1 issue (like in every for-loop, in any language): going from 0/12 to 11/12
lastly, turning it into a percentage to please the mix function
as you see: could be done in a mixin, but doesn't have to be!

Resources