Multiple box-shadow declarations in Sass
I would like to create a Sass mixin for the box-shadow property but am running into some trouble. Some of the existing code looks like this.
#someDiv {
-moz-box-shadow:0 0 5px rgba(0,0,0,.25);
}
#someOtherDiv {
-moz-box-shadow:0 0 5px rgba(0,0,0,.25) inset;
}
#theLastDiv {
-moz-box-shadow: 0 0 5px rgba(0,0,0,.25), 0 1px 0 rgba(255,255,255,.2) inset;
}
Trying to roll all of this into 1 mixin is becoming problematic. The documentation for using logic within mixins is pretty sparse.
I would like to create some mixin along the lines of:
@mixin boxShadow($xOffSet, $yOffSet, $blur, $red, $green, $blue, $opacity, $inset开发者_C百科 : false) {
@if $inset == true {
-moz-box-shadow: #{$xOffSet}px #{$yOffSet}px #{$blur}px rgba($red,$green,$blue) inset;
} @else {
-moz-box-shadow: #{$xOffSet}px #{$yOffSet}px #{$blur}px rgba($red,$green,$blue);
}
}
This is throwing errors because I guess Sass can't evaluate the $inset variable.
The previous example only demonstrates the problem I am having when it comes to to box-shadow being inset or not. The other problem I am having is when there are multiple box-shadows being declared on a single element. Refer to #theLastDiv described above if for reference.
@mixin boxShadow($declarations : 2, $xOffSet1, $yOffSet1, $blur1, $red1, $green1, $blue1, $opacity1 $xOffSet2, $yOffSet2, $blur2, $red2, $green2, $blue2, $opacity2) {
@if $declarations == 1 {
-moz-box-shadow: #{$xOffSet}px #{$yOffSet}px #{$blur}px rgba($red,$green,$blue);
} @else if $declarations == 2 {
-moz-box-shadow: #{$xOffSet1}px #{$yOffSet1}px #{$blur1}px rgba($red1,$green1,$blue1), #{$xOffSet2}px #{$yOffSet2}px #{$blur2}px rgba($red2,$green2,$blue2);
}
Sometimes an element has one box-shadow and other times it has to separate box-shadows. Am I mistaken that Sass lacks the ability to decipher this logic and that to accomplish this would require separate Mixins (one for elements with one box shadow, another for mixins with two box shadows).
And to complicate the matter, how does the opacity problem described above factor into this? Would love to get some feedback on this. Let me know if I'm mistaken or the way I'm thinking about the problem is flawed in general. Thanks!
You can use a variable argument like this:
// Box shadows
@mixin box-shadow($shadow...) {
-webkit-box-shadow: $shadow;
-moz-box-shadow: $shadow;
box-shadow: $shadow;
}
That allows you to have commas in the argument passed. so you can pass all the shadows you want.
An example using it:
@include box-shadow(2px 2px 2px rgba(#ccc, .8), -2px -2px 2px rgba(#ccc, 0.8)) ;
Pass in color variables like this:
$shadow-color: red; // could also be a #F9F8F6 type color
@include box-shadow(0 2px 2px rgba($shadow-color, .9));
UPDATE
$shadow-color: red; // could also be a hex (like #F9F8F6) type color
@include box-shadow(0 2px 2px rgba($shadow-color, .9));
In case you haven't seen arguments with the elipsis allowing a variable number of arguments before (ie splats) check this link: http://sass-lang.com/documentation/file.SASS_CHANGELOG.html#variable_keyword_arguments
I prefer to keep basic CSS parameter without commas: 0 0 1px rgba(0, 0, 0, .5)
rather than with commas: 0, 0, 5, 0, 0, 0, .25
.
This is my solution:
@mixin box-shadow($shadow1, $shadow2:false, $shadow3:false, $shadow4:false, $shadow5:false) {
$params: $shadow1;
@if $shadow2
{ $params: $shadow1, $shadow2; }
@if $shadow3 != false
{ $params: $shadow1, $shadow2, $shadow3; }
@if $shadow4 != false
{ $params: $shadow1, $shadow2, $shadow3, $shadow4; }
@if $shadow5 != false
{ $params: $shadow1, $shadow2, $shadow3, $shadow4, $shadow5; }
-webkit-box-shadow: $params;
-moz-box-shadow: $params;
box-shadow: $params;
}
@include box-shadow(-1px -1px 2px rgba(0, 0, 0, .05), 0 1px 1px white inset), ...
You could use collections and only have one parameter:
@mixin box-shadow($params) {
-webkit-box-shadow: $params;
-moz-box-shadow: $params;
box-shadow: $params;
}
$shadows: 0px 0px 5px rgba(0, 0, 0, 0.25), 0px 1px 0px #000 inset;
.myclass {
@include box-shadow($shadows);
}
I've added a bit of logic to handle the cases you described. Here is the mixin:
@mixin boxShadow($xOffSet, $yOffSet, $blur, $red, $green, $blue, $opacity, $inset : false, $two : false, $xOffSet2 : 0, $yOffSet2 : 0, $blur2 : 0, $red2 : 0, $green2 : 0, $blue2 : 0, $opacity2 : 0, $inset2 : false) {
@if $inset {
@if $two {
@if $inset2 {
-moz-box-shadow: #{$xOffSet}px #{$yOffSet}px #{$blur}px rgba($red,$green,$blue, $opacity) inset, #{$xOffSet2}px #{$yOffSet2}px #{$blur2}px rgba($red2,$green2,$blue2, $opacity2) inset;
} @else {
-moz-box-shadow: #{$xOffSet}px #{$yOffSet}px #{$blur}px rgba($red,$green,$blue, $opacity) inset, #{$xOffSet2}px #{$yOffSet2}px #{$blur2}px rgba($red2,$green2,$blue2, $opacity2);
}
} @else {
-moz-box-shadow: #{$xOffSet}px #{$yOffSet}px #{$blur}px rgba($red,$green,$blue, $opacity) inset;
}
} @else {
@if $two {
@if $inset2 {
-moz-box-shadow: #{$xOffSet}px #{$yOffSet}px #{$blur}px rgba($red,$green,$blue, $opacity), #{$xOffSet2}px #{$yOffSet2}px #{$blur2}px rgba($red2,$green2,$blue2, $opacity2) inset;
} @else {
-moz-box-shadow: #{$xOffSet}px #{$yOffSet}px #{$blur}px rgba($red,$green,$blue, $opacity), #{$xOffSet2}px #{$yOffSet2}px #{$blur2}px rgba($red2,$green2,$blue2, $opacity2);
}
} @else {
-moz-box-shadow: #{$xOffSet}px #{$yOffSet}px #{$blur}px rgba($red,$green,$blue, $opacity);
}
}
}
The mixin takes 17 parameters. Sorry for having so many, but SASS does not handle arrays or objects. In any event, 10 are optional. They are:
- $xOffSet - the x offset of the first shadow
- $yOffSet - the y offset of the second shadow
- $blur - the blur of the first shadow
- $red - the red value of the first shadow
- $blue - the blue value of the first shadow
- $green - the green value of the first shadow
- $opacity - the opacity of the first shadow
- $inset (Optional) - True or False. Indicates if the first shadow should be inset (defaults to false)
- $two (Optional) - True or False - True if you want to define two borders (defaults to false)
- $xOffSet2 (Optional) - the x offset of the second shadow
- $yOffSet2 (Optional) - the y offset of the second shadow
- $blur2 (Optional) - the blur of the second shadow
- $red2 (Optional)- the red value of the second shadow
- $blue2 (Optional) - the blue value of the second shadow
- $green2 (Optional) - the green value of the second shadow
- $opacity2 (Optional) - the opacity of the second shadow
- $inset2 (Optional) - True or False. Indicates if the second shadow should be inset (defaults to false)
You could set your styles like this:
#someDiv {
@include boxShadow(0, 0, 5, 0, 0, 0, .25);
}
#someOtherDiv {
@include boxShadow(0, 0, 5, 0, 0, 0, .25, true);
}
#theLastDiv {
@include boxShadow(0, 0, 5, 0, 0, 0, .25, false, true, 0, 1, 0, 255, 255, 255, .2, true);
}
Which generates the following CSS:
/* line 9, ../src/screen.scss */
#someDiv {
-moz-box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.25);
}
/* line 12, ../src/screen.scss */
#someOtherDiv {
-moz-box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.25) inset;
}
/* line 16, ../src/screen.scss */
#theLastDiv {
-moz-box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.25), 0px 1px 0px rgba(255, 255, 255, 0.2) inset;
}
Compass code might be worth studying:
However, they seem to use some server side helpers as well.
@mixin box-shadow(
$shadow-1 : default,
$shadow-2 : false,
$shadow-3 : false,
$shadow-4 : false,
$shadow-5 : false,
$shadow-6 : false,
$shadow-7 : false,
$shadow-8 : false,
$shadow-9 : false,
$shadow-10: false
) {
@if $shadow-1 == default {
$shadow-1 : -compass-space-list(compact(if($default-box-shadow-inset, inset, false), $default-box-shadow-h-offset, $default-box-shadow-v-offset, $default-box-shadow-blur, $default-box-shadow-spread, $default-box-shadow-color));
}
$shadow : compact($shadow-1, $shadow-2, $shadow-3, $shadow-4, $shadow-5, $shadow-6, $shadow-7, $shadow-8, $shadow-9, $shadow-10);
@include experimental(box-shadow, $shadow,
-moz, -webkit, not -o, not -ms, not -khtml, official
);
}
I was facing same issue when themifying sass (ref: How to properly generate Sass Themes).
I figured it out by using variable for box-shadow and then using that variable in code:
$btn-shadow-light: rgba(15, 15, 15, 0.1) 0px 0px 0px 1px, rgba(15, 15, 15, 0.1) 0px 2px 4px;
$btn-shadow-dark: rgba(15, 15, 15, 0.2) 0px 0px 0px 1px, rgba(15, 15, 15, 0.2) 0px 2px 4px;
$themes: (
light: (
color: rgba(55, 53, 47, 0.6),
fill: rgba(55, 53, 47, 0.6),
background: rgba(55, 53, 47, 0.08),
floating-btn-shadow: $btn-shadow-light,
),
dark: (
color: rgba(255, 255, 255, 0.6),
fill: rgba(255, 255, 255, 0.6),
background: rgb(71, 76, 80),
floating-btn-shadow: $btn-shadow-dark,
),
);
精彩评论