Grow your CSS skills. Land your dream job.

Custom User @mixins

Published by Chris Coyier

Mixins are one of the most useful and compelling reasons to use a CSS preprocessor. The typical way they are presented is for helping with CSS3 vendor prefix stuff. Indeed that is a compelling use case. No more tedious writing of all the prefixes and even more tedious updating of them over time.

However, if you are using Sass, you can use Compass, and Compass already has all those CSS3 mixins ready to go for you. Want to use the new CSS filters but want to be all future proof about it? No problem:

img {
  @include filter(grayscale(100%));
  &:hover {
    @include filter(grayscale(0));
  }
}

And you're good to go.

But handcrafted @mixins can be useful too! That is, @mixins that you author yourself to benefit your specific project. I enjoyed a post by Sacha Greif where he outlaid some @mixins he uses sometimes for specific projects.

For instance, he has some for the embossing & letterpress effects found on some sites.

@mixin box-emboss($outerOpacity, $innerOpacity) {
  box-shadow:
    rgba(white, $outerOpacity) 0 1px 0, 
    rgba(black, $innerOpacity) 0 1px 0 inset;
}

And then you could call that on any selector you wish to have that effect.

.module, header[role="banner"] {
  @include box-emboss(0.3, 0.6);
}

If you wanted to get super clever with this, you could also make a placeholder selector in which to @extend. That way you aren't repeating any code in the compiled CSS but you can separate your selectors and organize them however you want.

%box-emboss {
  @include box-emboss(0.3, 0.6);
}

header[role="banner"] {
  @extend %box-emboss;
}

...

.module {
  @extend %box-emboss;
}

Here's an example of that on CodePen:

I thought I'd share other custom @mixins I've used on some of my own projects.

Font Stacks

On this site I have four font stacks:

  1. Brand
  2. Headers
  3. Body
  4. Code

If you're properly careful with fonts, you probably aren't setting font-family too many different times in your stylesheet. If you're setting the same stack a dozen times, there is something wrong going on. But, you might have to more than once. For instance, you might have a default body font set literally on the <body>, but that won't cascade into form elements, so if you want to use the same font there you'll need to set that again on those elements. Now that you're setting it in two places, a @mixin is already useful.

I like using @mixins for this rather than a string variable set to the font families themselves, because the @mixin allows you to set other properties too if you wish. For instance, you might be using an @font-face font where you're only loading one particular weight and thus you want to set that weight whenever you set that font-family.

Here's the @mixins at the moment for this site:

@mixin font-stack-brand {
  font-family: 'Gotham Rounded A', 'Gotham Rounded B', "proxima-nova-soft", sans-serif;
}
@mixin font-stack-headers {
  font-family: 'Whitney Cond A', 'Whitney Cond B', "ronnia-condensed", sans-serif;
  font-weight: 700;
  font-style: normal;
}
@mixin font-stack-body {
  font-family: 'Whitney SSm A', 'Whitney SSm B', "ff-meta-web-pro", sans-serif;
}
@mixin font-stack-code {
  font-family: Menlo, "inconsolata", Monaco, "Courier New", Courier, monospace;
}

Media Query Mixin

You can create mixins that output the content that you pass after it in curly braces. This allows for a couple of neat possibilites. For instance, you can "name" a media query and then use it wherever you want. Meaning updating that media query only has to happen in one place. For instance:

@mixin breakpoint($point) {
  @if $point == mama-bear {
    @media (max-width: 1250px) { @content; }
  }
  @if $point == baby-bear {
    @media (max-width: 800px) { @content; }
  }
  @if $point == reverso-baby-bear {
    @media (min-width: 800px) { @content; }
  }
  @if $point == reverso-mama-bear {
    @media (min-width: 1250px) { @content; }
  }
}

And a simple usage example:

.page-wrap {
  width: 80%;
  @include breakpoint(baby-bear) {
    width: 100%;
  }
}

.footer {
  a {
    display: inline-block;
    @include breakpoint(baby-bear) {
      display: block;
    }
  }
}

You can learn more about this idea here.

Example of this on CodePen.

Animation Mixin

Compass doesn't have a @mixin for keyframe animations yet, but this is very easy to add on your own. It uses the same @content idea that the media query mixin uses above.

@mixin keyframes($name) {
  @-webkit-keyframes #{$name} {
    @content
  }
  @-moz-keyframes #{$name} {
    @content
  }
  @-ms-keyframes #{$name} {
    @content
  }
  @-o-keyframes #{$name} {
    @content
  }
  @keyframes #{$name} {
    @content
  }
}

And one to set the animation...

@mixin animation($value) {
  -webkit-animation: $value;
  -moz-animation: $value;
  -ms-animation: $value;
  -o-animation: $value;
  animation: $value;
}

Using it then becomes easy:

@include keyframes(move) {
  0%   { left: 0; }
  100% { left: 100px; }
}

.box {
  @include animation(move 0.5s ease infinite alternate);
}

You can learn more about CSS animation here.

Example of this on CodePen:

Toolbox Mixins

There are some simple helper classes that I've used on countless projects over the years. Things like an accessible hiding class and typography helping classes. If you make a mixin for these things, you can get double the bang for your buck.

// Accessible hiding
@mixin screen-reader-text() {
  position: absolute;
  top: -9999px;
  left: -9999px;
}
.screen-reader-text {
  @include screen-reader-text;
}
// Overflow Ellipsis
@mixin ellipsis() {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.ellipsis {
  @include ellipsis;
}
// Word Wrapping
@mixin word-wrap() {
  -ms-word-break: break-all;
  word-break: break-all;
  word-break: break-word;
  -webkit-hyphens: auto;
  -moz-hyphens: auto;
  hyphens: auto;
}
.word-wrap {
  @include mixin word-wrap;
}

Now you have a class name you can use in markup if you need to apply these properties. But you also have a mixin you can use to apply these properties to other declarations if you can't or don't want to touch the markup.

Note that I generally don't advise having your mixins and classes right next to each other like this. I prefer mixins to be in a separate file like _bits.scss which compiles to nothing and thus can be included on any other Sass file.

Yours?

It's always fun to share.

Comments

  1. I’ve started a series of post on my blog with some mixins not included in Compass that I’ve found helpful.

    One for CSS triangles is probably my favorite: blackbe.lt/useful-sass-mixins-css-trangle/

    • While triangles are not built into Compass, they are built into Zurb Foundation’s Compass extension. While not a huge fan of Foundation for large sites (it gets cumbersome), I do use it frequently for small sites that are one or two pages and the triangle mixin very helpful.

  2. Travis
    Permalink to comment#

    I love using SASS to style website, I could never imagine going back to straight CSS! I use mixins for media queries, font stacks, and backgrounds the most. My recent one is when I need to clear any parent styling to a div, which comes up a lot when working with drupal. So what I like to use is this:

    @mixin clear($style) {
        @if $style == 'clear-all' {
            padding:0;
            background-image:none;
            background-color:transparent;
            margin:0;
            height:auto;
            width:auto;
            float:none;
            border:none;
        }
    }
    
  3. I’ve only been using Sass for a week, and loving it! Put together me a little gradient mixin in which I can specify on which property I want it used:

    /* 
      Example:
      @include gradient(background-image, linear,
                      ( top,
                        transparent,
                        hsla(0, 0%, 100%, .1)
                      )
                    );;
    */
    
    @mixin gradient($prop, $type, $val) {
    #{$prop}: -webkit-#{$type}-gradient($val);
    #{$prop}:    -moz-#{$type}-gradient($val);
    #{$prop}:     -ms-#{$type}-gradient($val);
    #{$prop}:      -o-#{$type}-gradient($val);
    #{$prop}:         #{$type}-gradient($val);
     }
    

    I’m growing a collection of utilities, some largely based on Bourbon, in a styleguide I’m slowly building and cleaning up.

  4. stu
    Permalink to comment#

    Excellent, I was going to post these on my site – http://www.alwaystwisted.com and I still might… A pair of custom mixins for vertical rhythm – w/ REMs/PX – http://jsfiddle.net/sturobson/vYYn5/ w/ Ems – http://jsfiddle.net/sturobson/3KfUL/

  5. stu
    Permalink to comment#

    Oh, and there’s the lt-IE mixin I had help in creating that I’ve talked about here – http://alwaystwisted.com/post.php?s=2012-08-06-a-sass-mixin-for-media-queries-and-ie

  6. Permalink to comment#

    Media query + Retina Mixin (Mucho, thanks to chris’ tweet yesterday.)

    SCSS Media Queries with HiDpi (Retina) Support – Gist

  7. Permalink to comment#

    I’m using these mixins too, but I didn’t build it myself. I use a gem which extends SASS called Bourbon (for styling) and Neat (for positioning) and they have those awesome features. I really recommend using those gem’s, because they’re all prefixed so everything you want (like those examples), is inside those gems! And because they’re awesome :)

  8. Cooked up a mixin for creating directional arrows (triangles) on boxes that have borders. Nothing revolutionary CSS-wise but nice to put in a mixin. Still a newbie so any feedback is welcome.

    Bordered Box Arrow (Gist) »

  9. Stephan
    Permalink to comment#

    I’m using straight CSS and love it, and I could never imagine to seriously load such a lot of abstract bloat to my projects.

    Plain CSS all the way!

    • Oliver
      Permalink to comment#

      1) SCSS compiles to plain CSS
      2) The abstraction is the opposite of bloat: it allows you to keep your code modular and so reduces repetition

  10. Permalink to comment#

    After gathering lots of CSS tricks, I’ve decided to published all this mixins (using Sass & Compass) under this project: Compass Recipes. This is still WIP, but there is lots of interesting stuffs.
    Hope you enjoy it.

  11. stu@alwaystwisted.com
    Permalink to comment#

    And I’ve just created a Sass/SCSS mixin of that retina/non-retina media queries you created a gist with yesterday –

    http://codepen.io/sturobson/pen/plcks

  12. Permalink to comment#

    Write gradient in new syntax and get older.
    Because the mixin should make new code compatible to old code.

    
    @mixin prefix($prop, $value, $prefixes...) {
        @each $prefix in $prefixes {
            @if($prefix != spec) {
                -#{$prefix}-#{$prop}: $value;
            }
            @if($prefix == spec) {
                #{$prop}: $value;
            }
        }
    }
    
    @mixin prefix_val($prop, $value, $prefixes...) {
        @each $prefix in $prefixes {
            @if($prefix != spec) {
                #{$prop}: -#{$prefix}-$value;
            }
            @if($prefix == spec) {
                #{$prop}: $value;
            }
        }
    }
    
    @mixin linear-gradient($angle, $stops...) {
        $ang: "#{$angle}";
        @if ( type-of( $angle ) !="number" )        {
    
            @if      ($ang == "to top"          )   { @include prefix_val(background-image, linear-gradient(bottom,       $stops), webkit, moz, o);   }
            @else if ($ang == "to bottom"       )   { @include prefix_val(background-image, linear-gradient(top,          $stops), webkit, moz, o);   }
            @else if ($ang == "to left"         )   { @include prefix_val(background-image, linear-gradient(right,        $stops), webkit, moz, o);   }
            @else if ($ang == "to right"        )   { @include prefix_val(background-image, linear-gradient(left,         $stops), webkit, moz, o);   }
            @else if ($ang == "to top right"    )   { @include prefix_val(background-image, linear-gradient(bottom left,  $stops), webkit, moz, o);   }
            @else if ($ang == "to right top"    )   { @include prefix_val(background-image, linear-gradient(bottom left,  $stops), webkit, moz, o);   }
            @else if ($ang == "to top left"     )   { @include prefix_val(background-image, linear-gradient(bottom right, $stops), webkit, moz, o);   }
            @else if ($ang == "to left top"     )   { @include prefix_val(background-image, linear-gradient(bottom right, $stops), webkit, moz, o);   }
            @else if ($ang == "to bottom right" )   { @include prefix_val(background-image, linear-gradient(top left,     $stops), webkit, moz, o);   }
            @else if ($ang == "to right bottom" )   { @include prefix_val(background-image, linear-gradient(top left,     $stops), webkit, moz, o);   }
            @else if ($ang == "to bottom left"  )   { @include prefix_val(background-image, linear-gradient(top right,    $stops), webkit, moz, o);   }
            @else if ($ang == "to left bottom"  )   { @include prefix_val(background-image, linear-gradient(top right,    $stops), webkit, moz, o);   }
    
            background-image: linear-gradient($angle, $stops);
        }
    
        @else if( type-of( $angle ) =="number" ) {
    
            $old-angle: abs(450deg - $angle)%360;
            @include prefix_val(background-image, linear-gradient($old-angle, $stops), webkit, moz, o);
            background-image: linear-gradient($angle, $stops);
        }
    }
    
    @mixin linear-gradient($angle, $stops...) {
        $ang: "#{$angle}";
        @if ( type-of( $angle ) !="number" )        {
    
            @if      ($ang == "to top"          )   { @include prefix_val(background-image, linear-gradient(bottom,       $stops), webkit, moz, o);   }
            @else if ($ang == "to bottom"       )   { @include prefix_val(background-image, linear-gradient(top,          $stops), webkit, moz, o);   }
            @else if ($ang == "to left"         )   { @include prefix_val(background-image, linear-gradient(right,        $stops), webkit, moz, o);   }
            @else if ($ang == "to right"        )   { @include prefix_val(background-image, linear-gradient(left,         $stops), webkit, moz, o);   }
            @else if ($ang == "to top right"    )   { @include prefix_val(background-image, linear-gradient(bottom left,  $stops), webkit, moz, o);   }
            @else if ($ang == "to right top"    )   { @include prefix_val(background-image, linear-gradient(bottom left,  $stops), webkit, moz, o);   }
            @else if ($ang == "to top left"     )   { @include prefix_val(background-image, linear-gradient(bottom right, $stops), webkit, moz, o);   }
            @else if ($ang == "to left top"     )   { @include prefix_val(background-image, linear-gradient(bottom right, $stops), webkit, moz, o);   }
            @else if ($ang == "to bottom right" )   { @include prefix_val(background-image, linear-gradient(top left,     $stops), webkit, moz, o);   }
            @else if ($ang == "to right bottom" )   { @include prefix_val(background-image, linear-gradient(top left,     $stops), webkit, moz, o);   }
            @else if ($ang == "to bottom left"  )   { @include prefix_val(background-image, linear-gradient(top right,    $stops), webkit, moz, o);   }
            @else if ($ang == "to left bottom"  )   { @include prefix_val(background-image, linear-gradient(top right,    $stops), webkit, moz, o);   }
    
            background-image: linear-gradient($angle, $stops);
        }
    
        @else if( type-of( $angle ) =="number" ) {
    
            $old-angle: abs(450deg - $angle)%360;
            @include prefix_val(background-image, linear-gradient($old-angle, $stops), webkit, moz, o);
            background-image: linear-gradient($angle, $stops);
        }
    }
    
    
    • Permalink to comment#

      Ah, Heck the linear-gradient mxin was double posted chris can you please remove that.
      I can’t understand one thing a have seen compass using

      
      @mixin X(v1,v2,v3,v4,v5){ } to v10
      
      Why not @mixin X($v...) { } ?????????
      
      
  13. I’ve found these SASS/SCSS mixins really useful when you don’t have access/can’t get Compass installed:

    https://github.com/matthieua/sass-css3-mixins

    Lots of CSS3 goodness in there.

  14. Permalink to comment#

    I’m still in transition to SASS, but these are some LESS mixins I’m currently using in a project. The best use I’ve found for mixins is the ability to set your fallbacks for IE and older browsers, as well as pass in your values for browser prefixes.

    
    /*Make your element a circle.  Remember to set height and width to an equal value.*/
    .radius-circle {
      -webkit-border-radius: 50%;
            -moz-border-radius: 50%;
                border-radius: 50%;
    }
    
    /*A more advanced border-radius where you pass in 4 value, thus emabling you to set the radius on 2 corners (for example)  Follows the clockwise TRBL. */
    .border-radius2( @topleft: 0, @topright: 0, @bottomright: 0, @bottomleft: 0,) {
          -webkit-border-top-right-radius: @topright;
          -webkit-border-bottom-right-radius: @bottomright;
          -webkit-border-bottom-left-radius: @bottomleft; 
          -webkit-border-top-left-radius: @topleft;
              -moz-border-radius-topright: @topright;
              -moz-border-radius-bottomright: @bottomright;
              -moz-border-radius-bottomleft: @bottomleft;
              -moz-border-radius-topleft: @topleft;
                    border-top-right-radius: @topright;
                    border-bottom-right-radius: @bottomright;
                    border-bottom-left-radius: @bottomleft;
                    border-top-left-radius: @topleft;
          -moz-background-clip: padding;
            -webkit-background-clip: padding-box;
                background-clip: padding-box;
    }
    
    /*I use a global transition, but can pass in the 3 values to change the animation*/
    .transition(
        @what : all,
        @duration : .5s,
        @easing : ease-in-out
        ) {
        -webkit-transition: @what @duration @easing;
           -moz-transition: @what @duration @easing;
             -o-transition: @what @duration @easing;
                transition: @what @duration @easing;
    }
    
    /*Mixin to set fallback and compatible rgba*/
    .rgb_a(@color, @alpha) {
        @alpha_color: hsla(hue(@color), saturation(@color), lightness(@color), @alpha); /* you can use HEX as your color ! */
        @ie_alpha_color: argb(@alpha_color);
        background-color: @color; // Fallback for older browsers
        background-color: @alpha_color;
        // IE hacks
        zoom: 1; // hasLayout
        background-color: transparent\9;
        -ms-filter:  "progid:DXImageTransform.Microsoft.gradient(startColorstr=@{ie_alpha_color}, endColorstr=@{ie_alpha_color})";
        filter: ~"progid:DXImageTransform.Microsoft.gradient(startColorstr=@{ie_alpha_color}, endColorstr=@{ie_alpha_color})";
    
        }
    
    /*Simple mixin for a gradient, setting the beginning color, end color, and when to switch*/
    .gradient(
        @begin: black,
        @end: white,
        @switch : 100%
        ) {
        background:  @begin;
        background: -webkit-gradient(linear, 0 0, 0 100%, from(@begin), color-stop(@switch, @end));
        background: -moz-linear-gradient(top, @begin, @end @switch);
        background: -o-linear-gradient(top, @begin, @end @switch);
        background: linear-gradient(top, @begin, @end @switch);
        }
    
    /*Another compatibility mixin with fallback*/
    .opacit_y(@opacity: 0.5) {
      -webkit-opacity: @opacity;
           -moz-opacity: @opacity;
              -khtml-opacity: @opacity;
                  opacity: @opacity;
                  @ie: @opacity*100;
                        filter: alpha(opacity=@ie);
    }
    
    
  15. Trevor
    Permalink to comment#

    I’ve always used an inset for creating double borders, rather than a nested span or div, so mixins were the perfect vehicle:

    @mixin box-shadow-inset ($horizontal, $vertical, $spread, $color) {
        -webkit-box-shadow: $horizontal $vertical $spread $color inset;
        -moz-box-shadow: $horizontal $vertical $spread $color inset;
        -ms-box-shadow: $horizontal $vertical $spread $color inset;
        -o-box-shadow: $horizontal $vertical $spread $color inset;
        box-shadow: $horizontal $vertical $spread $color inset;
    }
  16. Might be useful (@see http://snipplr.com/view.php?codeview&id=66966):

    /**
     * CSS3 Image Filter Tools
     */ 
    
    @mixin if-blur($amt: 4px) {
      -o-filter: blur($amt);
      -ms-filter: blur($amt);
      -moz-filter: blur($amt);
      -webkit-filter: blur($amt);
    }
    
    @mixin if-brightness($amt: 0.35) {
      -o-filter: brightness($amt);
      -ms-filter: brightness($amt);
      -moz-filter: brightness($amt);
      -webkit-filter: brightness($amt);
    }
    
    @mixin if-contrast($amt: 140%) {
      -o-filter: contrast($amt);
      -ms-filter: contrast($amt);
      -moz-filter: contrast($amt);
      -webkit-filter: contrast($amt);
    }
    
    @mixin if-grayscale($amt: 100%) {
      -o-filter: grayscale($amt);
      -ms-filter: grayscale($amt);
      -moz-filter: grayscale($amt);
      -webkit-filter: grayscale($amt);
    }
    
    @mixin if-huerotate($deg: 180deg) {
      -o-filter: hue-rotate($deg);
      -ms-filter: hue-rotate($deg);
      -moz-filter: hue-rotate($deg);
      -webkit-filter: hue-rotate($deg);
    }
    
    @mixin if-invert($amt: 100%) {
      -o-filter: invert($amt);
      -ms-filter: invert($amt);
      -moz-filter: invert($amt);
      -webkit-filter: invert($amt);
    }
    
    @mixin if-opacity($amt: 60%) {
      -o-filter: opacity($amt);
      -ms-filter: opacity($amt);
      -moz-filter: opacity($amt);
      -webkit-filter: opacity($amt);
    }
    
    @mixin if-saturate($amt: 4) {
      -o-filter: saturate($amt);
      -ms-filter: saturate($amt);
      -moz-filter: saturate($amt);
      -webkit-filter: saturate($amt);
    }
    
    @mixin if-sepia($amt: 100%) {
      -o-filter: sepia($amt);
      -ms-filter: sepia($amt);
      -moz-filter: sepia($amt);
      -webkit-filter: sepia($amt);
    }
    
  17. Why are you using the the -ms- prefixes for the animations?

    Since no stable version of IE ever shipped with these prefixes, it is generally understood that there’s no need to include them.

    While compass is still churning them out (hopefully that’ll change soon), we shouldn’t be using them in our own mixins.

  18. I extented a mixin for dealing with rem. I wrote it down in german:
    http://typo3-wuppertal.de/post/33835337756/sass-plugin-fur-die-nutzung-von-rem

    Here is an example of usage:

    .element
      @include rem('padding',10px 0 2px 5px)
    
    .element2
      @include rem('border', 1px solid red)
      @include rem('padding', 10px !important)
    

    This becomes to:

    .element {
      padding: 10px 0 2px 5px;
      padding: 1rem 0 0.2rem 0.5rem;
    }
    .element2 {
      border: 1px solid red;
      border: 0.1rem solid red;
      padding: 10px !important;
      padding: 1rem !important;
    }
    

    If you just want the code, you might look here:
    https://github.com/SimonWpt/rem

  19. nickhempsey
    Permalink to comment#

    I posted this in the Lodge yesterday, but I’m going to post it here as well.

    Here’s a @mixin for font-stacks that has an !important option. This is super handy for those stubborn inserted divs, I’m looking at you Google Custom Search Engine.

    
    @mixin font-stack($important) {
        $stack: Arial, Tahoma, Sans-Serif;
        @if $important == 1 {
            font-family: $stack !important; 
        } @else  if $important == 0 {
            font-family: $stack;
        }
    }
    
    // Use it!
    
    .important {
         @include  font-stack(1);
    }
    
    .not-important {
         @include  font-stack(0);
    }
    
This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".