Subtracting blur value from box-shadow property through SCSS - css

I have been cogitating on this for a while now. In my SCSS I have the following:
$shadow: 0 0 25px rgb(46, 46, 46);
div {
box-shadow: $shadow;
}
How can I subtract the 25px of blur by, let's say 10 so that I may use a blur of 15 pixels? Furthermore, how do I select the blur value? Considering I want to apply a box-shadow on a div element:
<div>Lorem Ipsum</div>

The $shadow variable is simply a list of values. If the blur is always going to be the 3rd item in the list (such as in your example), then what you're looking at is something like this:
div {
box-shadow: nth($shadow, 1) nth($shadow, 2) nth($shadow, 3) - 15px nth($shadow, 4);
}
If the blur is in another valid position in the list (maybe it's an inset shadow), then you'll need to start doing things like checking the length of the list and/or examine the first element to see if it is inset:
div {
#if nth($shadow, 1) == inset {
box-shadow: nth($shadow, 1) nth($shadow, 2) nth($shadow, 3) nth($shadow, 4) - 15px nth($shadow, 5);
} #else {
box-shadow: nth($shadow, 1) nth($shadow, 2) nth($shadow, 3) - 15px nth($shadow, 4);
}
}
Alternately, you could do it programatically:
$shadow: 0 0 25px rgb(46, 46, 46);
#function adjust-shadow($shadow, $position, $adjustment) {
$x: ();
$shift: if(nth($shadow, 1) == inset, -1, 0);
#for $i from 1 through length($shadow) {
$p: $i + $shift;
#if $position == color and $i == length($shadow) {
$x: append($x, $adjustment);
} #else if ($position == x-offset and $p == 1) or ($position == y-offset and $p == 2) or ($position == blur and $p == 3) {
$x: append($x, nth($shadow, $i) + $adjustment);
} #else {
$x: append($x, nth($shadow, $i));
}
}
#return $x;
}
.foo {
box-shadow: adjust-shadow($shadow, blur, -15px);
}
.bar {
box-shadow: adjust-shadow($shadow, color, blue);
}
.baz {
box-shadow: adjust-shadow(adjust-shadow($shadow, blur, -15px), y-offset, -2), adjust-shadow($shadow, blur, 10px);
}

Make a new variable for the blur value:
$blur: 25px - 10;
$shadow: 0 0 $blur rgb(46, 46, 46);
div {
box-shadow: $shadow;
}
Depending on your overall needs, you might be better served by writing a mixin.

Related

Less - how to generate values in a loop

I'm trying to generate a variable in the loop:
box-shadow: 835px 1456px #FFF, 1272px 796px #FFF, 574px 1357px #FFFetc ...
It is basic:
box-shadow: x1 y1 #fff, x2 y2 #fff, x3 y3 #fff, x4 y4 #fff ... xn yn #fff.
I tried to do it like this:
#maxPiont: 2000;
#minPoint: 0;
.init() {
.make-point(`Math.random()`, `Math.random()`, ""); // set initial value - ignore for now
}
.init();
.make-point(#newX, #newY, #old) {
.redefine() {
#X: floor(#newX * (#maxPiont - #minPoint + 1));
#Y: floor(#newY * (#maxPiont - #minPoint + 1));
#point: '#{X} #{Y} #fff';
#allPoints: "#{point}, #{old}";
}
}
.make-stars(#i) when (#i >0) { // sadly in loop we are in same scope all the time and trick wont work
.redefine();
.make-point(`Math.random()`, `Math.random()`, #allPoints);
.test
{
box-shadow: #allPoints;
}
.make-stars(#i - 1);
}
.make-stars(1); // <- scope 1
.make-stars(1); // <- scope 2
.make-stars(1); // <- scope 3
.make-stars(100); // <- scope 4
.make-stars(1); // <- scope 5
.make-stars(1); // <- scope 6
.make-stars(1); // <- scope 7
I know why it is not working in the loop and why it is working outside of it (scopes and less lazy loading ;/) How it can be done in a different way?
Did I think about making a variable per every step and add it? Is this possible or crazy idea?
You can use less lang merge function to aggregate shadow values from multiple properties into a comma separated list. No need to store all shadows into one variable.
Less:
#min: 1; // Min random number
#max: 100; // Max
// Generate single shadow with random position
.random-shadow() {
#x: `Math.floor(Math.random() * (#{max} - #{min}))`;
#y: `Math.floor(Math.random() * (#{max} - #{min}))`;
box-shadow+: unit(#x, px) unit(#y, px) #fff;
}
// Loop to set #count shadows to the element
.multiple-shadow(#count) when (#count > 0) {
.random-shadow();
.multiple-shadow(#count - 1);
}
a {
.multiple-shadow(5);
}
Css output:
a {
box-shadow: 79px 81px #fff, 76px 98px #fff, 67px 97px #fff, 44px 25px #fff, 54px 11px #fff;
}

"Quoting" argument variable in LESS mixin

I have the following array of color definitions:
#colors: ~"black" #000, ~"white" #fff, ~"blue" #008FD6, ~"bluehover" #44A1E0, ~"grayborder" #DBDBDB;
And I use the following function to use those colors within CSS declarations.
.colorkey(#key) {
.-(length(#colors));
.-(#i) when (#i > 0) {.-((#i - 1))}
.-(#i) when (#key = extract(extract(#colors, #i), 1)) {
#colorkey: extract(extract(#colors, #i), 2);
}
.--() {#colorkey: #000} .--;
}
Usage:
.my-div {
.colorkey(~"black");
color: #colorkey
}
However I'd prefer to use the mixin like so:
.colorkey(black);
Without the quotes and tilde. Is it possible to modify the colorkey mixin to achieve this?
If your #colors can be defined without putting the color names in ~"...", you just need to make a minor change:
#colors: black #000, white #fff, blue #008FD6, bluehover #44A1E0, grayborder #DBDBDB;
.colorkey(#key:black) {
.-(length(#colors));
.-(#i) when (#key = extract(extract(#colors, #i), 1)) {
#colorkey: extract(extract(#colors, #i), 2);
}
.-(#i) when (#i > 0) {.-(#i - 1)}
}
.my-div {
.colorkey(bluehover);
color: #colorkey
}
Note that I
removed the extra set of parentheses in your .-(#i) when (#i > 0)
moved that recursive call to the end of .colorkey, and
dropped your .--() {#colorkey: #000} .--; and in its place used .colorkey(#key:black) {. (My guess is that was supposed to make .colorkey; color: #colorkey evaluate to color: #000 but actually it wasn't doing anything :) In the code you provided, to define that default you'd need instead to do .colorkey(#key: ~"black") { )

How do you check for unitless variables with multiple values SASS

I try to create a flexible mixin where you can set the space for padding or margin from the same mixin
I based it on a bourbon for positioning
mixin setSpace($setSpace: padding, $setSpaceValues: 0 0 0 0){
#if type-of($setSpace) == list{
$setSpaceValues :$setSpace;
$setSpace: padding;
}
$top: nth($setSpaceValues, 1);
$right: nth($setSpaceValues, 2);
$bottom: nth($setSpaceValues, 3);
$left: nth($setSpaceValues, 4);
#if unitless($top and $right and $bottom and $left){
#{$setSpace}: $top+px $right+px $bottom+px $left+px ;
}
}
But I try to get the flexibility to be able to add individual units to it as well so that I can do also
.test{
#include setSpace(margin, 10% 0 5 5);
}
You could use the Sass if() function on each value to check for unitless ... maybe make define a function that does this - something in this direction perhaps:
#function setUnit($val){
#return if(unitless($val), $val * 1px, $val);
}
And then you can use it in your mixin:
#mixin setSpace($setSpace: padding, $setSpaceValues: 0 0 0 0){
#if type-of($setSpace) == list{
$setSpaceValues: $setSpace;
$setSpace: padding;
}
$top: nth($setSpaceValues, 1);
$right: nth($setSpaceValues, 2);
$bottom: nth($setSpaceValues, 3);
$left: nth($setSpaceValues, 4);
#{$setSpace}: setUnit($top) setUnit($right) setUnit($bottom) setUnit($left) ;
}
DEMO
in addition you could also just set the values in a loop ( - a bit more flexible and shorter):
#mixin setSpace($setSpace: padding, $setSpaceValues: 0 0 0 0){
#if type-of($setSpace) == list{
$setSpaceValues: $setSpace;
$setSpace: padding;
}
$out: ();
#each $val in $setSpaceValues{
$out: append($out, if(unitless($val), $val * 1px, $val));
}
#{$setSpace}: $out;
}
DEMO
Hope this gives you some ideas.
Your mixin just might be better suited as a function:
#function spacing($values: 0) {
$collector: ();
#each $v in $values {
$collector: append($collector, if(unitless($v) and $v != 0, $v * 1px, $v));
}
#return $collector;
}
.test{
margin: spacing(10% 0 5 5);
}
Output:
.test {
margin: 10% 0 5px 5px;
}
If all you're doing is transforming a single value, functions make it a little more clear that's all that's happening when you come back to read the code later.

How to generate classes in LESS?

I need to generate all combinations the following classes:
.b-1-1-1-1 {
border:1px solid #000;
}
.b-0-1-1-1 {
border-right: 1px solid #000;
border-bottom: 1px solid #000;
border-left: 1px solid #000;
}
.
.
.
I need to use class names as border style likes, is it possible to make it in LESS automatically?
You could also just loop through binary numbers instead of a nested loop (makes everything a bit shorter) ... something like this perhaps:
.set-top() when (#t > 0) {
border-top: 1px solid #000;
}
.set-left() when (#l > 0) {
border-left: 1px solid #000;
}
.set-right() when (#r > 0) {
border-right: 1px solid #000;
}
.set-bottom() when (#b > 0) {
border-bottom: 1px solid #000;
}
.borders(#t:0, #r:0, #b:0, #l:1){
.b-#{t}-#{r}-#{b}-#{l} {
.set-top;
.set-right;
.set-bottom;
.set-left;
}
}
.loop(#i:16) when (#i < 32) {
.borders(~`(#{i}).toString(2)[1]`,
~`(#{i}).toString(2)[2]`,
~`(#{i}).toString(2)[3]`,
~`(#{i}).toString(2)[4]`);
.loop((#i + 1));
}
.loop();
In addition you can again add a check for which properties are set/same and combine them under a combined border property and set the border width/style/color like ScottS shows in his example.
(Update: I've been asked to rework my example to a complete snippet - so here we go).
Variant 1
Basically it's the same as in Martin Turjak answer but without inline javascript and with some further makeup:
// usage:
.borders(1px dashed wheat);
div {
.borders(3px, dotted, red);
}
// implementation:
.borders(#values...) {
.values(t, 1) {border-top: #values}
.values(r, 1) {border-right: #values}
.values(b, 1) {border-bottom: #values}
.values(l, 1) {border-left: #values}
.values(... ) {}
.trbl-(#t, #r, #b, #l) {
.b-#{t}-#{r}-#{b}-#{l} {
.values(t, #t);
.values(r, #r);
.values(b, #b);
.values(l, #l);
}
}
.-(#i: 15) when (#i > 0) {
.-((#i - 1));
.trbl-(mod(floor((#i / 8)), 2),
mod(floor((#i / 4)), 2),
mod(floor((#i / 2)), 2),
mod(floor((#i / 1)), 2));
}.-;
}
Variant 2
The magic one, no loops, minified CSS output:
// usage:
.borders(1px, dashed, wheat);
// implementation:
.borders(#values...) {
0, 1 {
.b-1-&-&-& {border-top: #values}
.b-&-1-&-& {border-right: #values}
.b-&-&-1-& {border-bottom: #values}
.b-&-&-&-1 {border-left: #values}
}
}
Doable
This code allows flexibility in setting style and color to the border, the unit value of the width, and defaults to max width of 1 unit (which is px by default). Note that setting the border width values to anything more than 1, the output CSS code is going to begin increasing at a dramatic rate (try running them at just 2, i.e. calling .generateBorderClasses(#t: 2, #r: 2, #b: 2, #l: 2);, and see the results);
.generateBorderClasses(#unit: px, #style: solid, #color: #000, #t: 1, #r: 1, #b: 1, #l: 1) {
.b() when (#check) {
border: unit(#t,#unit) #style #color;
}
.b() when (#sum = 0) {}
.b() when (#t > 0) and (#sum > 0) and not (#check) {
border-top: unit(#t, #unit) #style #color;
}
.b() when (#r > 0) and (#sum > 0) and not (#check) {
border-right: unit(#r, #unit) #style #color;
}
.b() when (#b > 0) and (#sum > 0) and not (#check) {
border-bottom: unit(#b, #unit) #style #color;
}
.b() when (#l > 0) and (#sum > 0) and not (#check) {
border-left: unit(#l, #unit) #style #color;
}
.t-loop (#t) when (#t > -1) {
.r-loop (#r) when (#r > -1) {
.b-loop (#b) when (#b > -1) {
.l-loop (#l) when (#l > -1) {
#sum: (#t + #r + #b + #l);
#check: e(`(#{t} == #{r}) && (#{t} == #{b}) && (#{t} == #{l}) ? "true" : "false"`);
.b-#{t}-#{r}-#{b}-#{l} {
.b();
}
.l-loop(#l - 1);
}
.l-loop (-1) {}
.l-loop(#l);
.b-loop(#b - 1);
}
.b-loop (-1) {}
.b-loop(#b);
.r-loop(#r - 1);
}
.r-loop (-1) {}
.r-loop(#r);
.t-loop(#t - 1);
}
.t-loop(-1) {}
.t-loop(#t);
}
.generateBorderClasses();
Still Not Recommended
Personally, I would just have four classes controlling the html (so something like class="bt br bb bl") and then do this:
.bt {
border-top: 1px solid #000;
}
.br {
border-right: 1px solid #000;
}
.bb {
border-bottom: 1px solid #000;
}
.bl {
border-left: 1px solid #000;
}
MUCH less (pun intended) css code and essentially the same control value in the class assigning of the html.

SASS Using a variable list to fill arguments in a mixin

I am building locally a mixin for linear gradients specific for a project. The idea is that I have 6 different gradient schemes going on. I am trying to pass all of the values for the arguments from a variable. Not sure if I am going beyond what SASS supports right now. Also all 3 are in separate files that are imported into the master site scss file.
Any guidance would be greatly appreciated.
$gradientBlue: #68bafa, #279bf2, #2891e2;
#mixin verticalGradient($color-1, $color-2, $color-3: "", $color-4: "", $color-5: "" ) {
background: $color-1;
#include pie;
#include filter-gradient($color-1, $color-2);
#include background-image(linear-gradient(top, $color-1 0%, $color-2 100%));
#if #{$color-3} != none {
text-shadow: 1px 1px 1px #{$color-3};
}
#if #{$color-4} != none {
&:hover {
#include pie;
background: $color-4;
text-shadow: 1px 1px 1px $color-5;
}
}
}
#include verticalGradient($gradientBlue);
Sure. Try something like this:
$gradientBlue: #68bafa, #279bf2, #2891e2;
#mixin vertical-gradient($colors) {
#include background(linear-gradient(nth($colors, 1), nth($colors, 2)));
#if length($colors) >= 3 {
text-shadow: 1px 1px 1px nth($colors, 3);
}
#if length($colors) >= 4 {
background: nth($colors, 4);
}
}
body {
#include vertical-gradient($gradientBlue);
}
i had a similar issue,
i wrote an mixin which should assign a list of parameters to a compass mixin.
and here is my solution ( with compass 0.12.2):
#mixin single-box-shadow-fallback( $color, $arg... ) {
#include single-box-shadow( $color, $arg... );
.lt-ie9 & {
border: 1px solid $color;
}
}
}
call
#include single-box-shadow-fallback( #CCC, 0, 0, 2px, 0, true );
these example output an wront css;
#mixin single-box-shadow-fallback( $color, $arg ) {
#include single-box-shadow( $color, $arg );
}
output:
box-shadow: 0, 0, 2px, 0, true 0px 5px #cccccc;

Resources