Using multiple box-shadow declarations in Sass

I'm struggling to create a Sass mixin for the box-shadow property. Here's a snippet of the existing code:

#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 consolidate all this into one mixin is proving challenging as I navigate the limited documentation on using logic within mixins.

I want to create a mixin like this:

@mixin boxShadow($xOffSet, $yOffSet, $blur, $red, $green, $blue, $opacity, $inset : 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 causing errors because Sass seems unable to evaluate the $inset variable.

The example above highlights the challenge I face in dealing with whether the box-shadow should be inset or not. Another issue arises when multiple box-shadows are declared on a single element, as seen in #theLastDiv.

@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);
  }

At times, an element may have just one box-shadow, while other times it requires two separate box-shadows. Is it possible that Sass can't handle this scenario and would necessitate separate mixins (one for elements with one shadow, another for those with two)?

To make things more complex, how does the opacity issue described earlier play into this? I'd appreciate any insights or corrections if my understanding of the problem is off base. Thank you!

Answer №1

To create box shadows with multiple values, use a variable argument in the following way:

// Box shadows
@mixin box-shadow($shadow...) {
  -webkit-box-shadow: $shadow;
     -moz-box-shadow: $shadow;       
          box-shadow: $shadow;
}

This allows you to include commas in the argument passed, enabling you to specify as many shadows as needed.

Here's an example of how to utilize this method:

@include box-shadow(2px 2px 2px rgba(#ccc, .8), -2px -2px 2px rgba(#ccc, 0.8)) ;

You can also pass color variables like so:

$shadow-color: red;  // This could alternatively be a hex color code like #F9F8F6
@include box-shadow(0 2px 2px rgba($shadow-color, .9));

UPDATE

$shadow-color: red;  // This could alternatively be a hex color code like #F9F8F6
@include box-shadow(0 2px 2px rgba($shadow-color, .9));

If you're unfamiliar with using arguments with ellipses for a variable number of arguments (similar to splats), you can review the documentation at: http://sass-lang.com/documentation/file.SASS_CHANGELOG.html#variable_keyword_arguments

Answer №2

I have a personal preference for writing CSS parameters without commas, like this: 0 0 1px rgba(0, 0, 0, .5), rather than using commas, such as 0, 0, 5, 0, 0, 0, .25.

Here is the customized solution I came up with:

@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), ...

Answer №3

Utilizing collections can streamline your code by condensing it to just one parameter:

@mixin box-shadow($values) {
  -webkit-box-shadow: $values;
  -moz-box-shadow: $values;
  box-shadow: $values;
}

$shadows: 0px 0px 5px rgba(0, 0, 0, 0.25), 0px 1px 0px #000 inset;

.myclass { 
   @include box-shadow($shadows);
}

Answer №4

I have implemented a logic to address the scenarios you specified. Below 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 accepts 17 parameters. I understand it may seem like a lot, but SASS lacks support for arrays or objects. However, 10 of these parameters are optional. They include:

  1. $xOffSet - x offset of the first shadow
  2. $yOffSet - y offset of the second shadow
  3. $blur - blur of the first shadow
  4. $red - red value of the first shadow
  5. $blue - blue value of the first shadow
  6. $green - green value of the first shadow
  7. $opacity - opacity of the first shadow
  8. $inset (Optional) - True or False. Indicates if the first shadow should be inset (defaults to false)
  9. $two (Optional) - True or False - To define two shadows (defaults to false)
  10. $xOffSet2 (Optional) - x offset of the second shadow
  11. $yOffSet2 (Optional) - y offset of the second shadow
  12. $blur2 (Optional) - blur of the second shadow
  13. $red2 (Optional)- red value of the second shadow
  14. $blue2 (Optional) - blue value of the second shadow
  15. $green2 (Optional) - green value of the second shadow
  16. $opacity2 (Optional) - opacity of the second shadow
  17. $inset2 (Optional) - True or False. Indicates if the second shadow should be inset (defaults to false)

You can set your styles as follows:

#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);
}

This will generate the corresponding 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;
}

Answer №5

I encountered a similar issue while theming sass (source: How to properly generate Sass Themes).

To resolve it, I utilized a variable for box-shadow and incorporated that variable into the 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,
  ),
);

Answer №6

Exploring the compass code found here could be beneficial:

Interestingly, they also utilize server-side helpers.

@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
  );
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Uniformly sized text containers and buttons

Seeking assistance to align a text field and a button in a way that they appear as a combined element. The desired look is shown below (screenshot taken from Chrome Linux): However, when viewed in Firefox Linux, the button is slightly taller by two pixels ...

What is causing the inconsistency in the widths of these HTML elements?

I recently created multiple div elements with a uniform width of 5px. Here is the CSS code I used: div { background-color: black; width: 5px; height: 100px; display: inline-block; } To my surprise, despite setting the same width for all divs, som ...

Achieving responsive design for div tags: Automatically adjust the width of left and right div tags to fit the screen, while maintaining the static

I need help figuring out how to automatically adjust the width of div 'one' and div 'three' to the screen side while keeping the width of div 'two' static using CSS. All three divs should be in the same row. Here is my HTML c ...

The second entry is not being styled by CSS, is there an issue with the code in this section?

I am facing a challenge while trying to set the same background image for two div elements: .abc { background: url('images/autogen.png') no-repeat 0px -133px; width: 256px; height: 256px; }; .def { background: url('images/autogen.png' ...

Utilize styling only when both classes are actively used within media queries or bootstrap

Despite specifying to apply the text-align to 'md-3' instead of 'sm', it still applies when the browser is resized to use the 'sm' style. Simply put, I only want the style to be applied if the media queries interpret my devic ...

Expand the width of the navbar brand icon

Currently working on a landing page project and noticed that my logo appears too small, utilizing Bootstrap 5 style.css ... .navbar-brand { width: 3.5rem; padding: 0 0; margin: 0.3rem 0; position: relative; } .navbar-brand img { width: 100%; ...

Footer that sticks to the bottom of the page across various pages

Having trouble printing a 2-page document on Chrome. The first page has fixed content while the second page has dynamic content in an extended table. The problem I'm facing is keeping the footer at the bottom of the second page. The CSS code below wo ...

Experimenting with media queries but struggling to make them function properly

I am relatively new to CSS and I am experimenting with media queries. Despite following advice on various Stackoverflow posts and other websites, I am unable to make them work. My goal is simple - to change the color of boxes when the screen width falls be ...

Unusual problem arises with styling and element measurement (scrollWidth / scrollWidth) in Gatsby framework

Currently, I am working on a component that splits lines based on the parent container's width without overflowing. Despite successfully implementing this in a sandbox or pure react application (even with custom fonts), I encountered issues when using ...

Is there a way to set a custom background image for a specific Vaadin view?

I am developing a view in Vaadin that looks something like this... public class PosAppPickerView extends VerticalLayout implements View { Everything is functioning smoothly, but I am interested in incorporating an image as the background for the body/mai ...

Issue with React-Native FlatList's scrolling functionality

Struggling with implementing a scrolling FlatList in React Native. Despite trying various solutions found on Stack Overflow, such as adjusting flex properties and wrapping elements in views, the list still refuses to scroll. Snippet of code (issue is with ...

Struggling to fully load all content/images upon initial load in Next.js

next.config.json const withLess = require("@zeit/next-less"); const lessToJS = require("less-vars-to-js"); const withSass = require("@zeit/next-sass"); const withCSS = require("@zeit/next-css"); const withFonts = req ...

Adjust the opacity of certain elements to be semi-transparent, with the exception of the one currently

I'm attempting to implement the :not selector in conjunction with :hover to create a visual effect where elements that are not being hovered over become semitransparent. My goal is as follows: 1) All elements start at 100% opacity 2) When an elemen ...

Having trouble with the numbering system - any suggestions on how to resolve this issue?

I am experiencing an issue with numbering a list .content ol { padding-left: 0px; counter-reset: item; } .content ol > li { display: block; } .content ol > li::before { content: counters(item, ". ") " " ; counter-increment: ...

I'm puzzled by the continuous sass error output that I am experiencing after upgrading to Node.js 16.13.0, along with its npm 8. Can anyone help me troub

After upgrading to Node.js 16.13.0 along with npm 8, I encountered an issue with Sass. To resolve this, I had to update gulp-sass to version 5.0.0, install [email protected], and make changes in my gulpfile.js by requiring sass as sass = require(&apos ...

What exactly is the significance of "hash" in terms of Internet Explorer style

After downloading a sample CSS file, I noticed the following entry: #text-align: right; The comment beside the entry mentioned that this expression is specifically for justifying it in IE, while text-align: right; works for Safari and Chrome. My questi ...

"Is there a way to alter the background color of the second span within a Bootstrap row

I currently have 4 WordPress services in a loop, and I am trying to change the background color of the second service. However, when I try to apply the CSS background property, it ends up affecting all of the services. Here is my template code: <div ...

Material-UI icons refusing to show up on the display

I've been working on creating a sidebar component and importing various icons to enhance the UI, but for some reason they are not displaying on the screen. I even tried other suggested solutions without success. <SidebarOption Icon = {InsertComment ...

CodeIgniter functionality for generating auto-incrementing IDs that are accessible in both the view and within JavaScript's Window.Print() method

While working on creating an invoice, I encountered a few issues. First, I want the Invoice No: to be displayed in my view (receipt.php) as 0001 and use it as the primary key in my tbl_payment table. However, I'm unsure how to have an auto-incremented ...

Exploring ways to integrate Javascript and CSS into a Bootstrap lightbox modal dialog?

Can someone help me figure out how to use the bootstrap lightbox to display a form with specific CSS style and JavaScript code for the form? I'm having some trouble implementing it. I specifically need this setup because I am using Selectize.JS to cr ...