My Sass Extends, Mixins, and Functions

Last Updated February 17, 2017

Let’s cut to the chase, here’s my Sass broilerplate with some of the mixins, functions, and extends that I use.

NOTE:

As you’ll notice in the comments of this post, Danny Lewandowski and I had a good back and forth about mixins vs. extends. I’m working on a blog post to explain, but in the meantime, I’ve gone ahead and updated all my code to reflect the preferred mixin.

Naming Breakpoints

In my Sass breakpoints file, I’m using Chris Coyier’s Breakpoint trick. — It’s a mixin within _2_helpers / _breakpoints.scss file. It takes a breakpoint name and builds out the media query for me.

NOTE:

I updated my breakpoints. Before I was using max-width which is a desktop first mentality. min-width supports mobile first.

I also updated my class names. Previously, I referenced Zurb Foundation, the framework I was using, as well as specific devices. I’ve moved on from both of these practices, become more devices (and framework) agnostic.

@mixin breakpoint($point) 		{
	@if $point == retina {
		@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { @content; }
	}
	@if $point == xxlarge {
		@media (min-width: 1921px) { @content; }
	}
	@if $point == xlarge {
		@media (min-width: 1600px) { @content; }
	}
	@if $point == large {
		@media (min-width: 1441px) { @content; }
	}
    @else if $point == regular-screen {
	    @media (min-width: 1200px) { @content; }
  	}
  	@else if $point ==  medium {
	    @media (min-width: 1024px)  { @content; }
  	}
	@else if $point ==  landscape {
	    @media (min-width: 1024px)  { @content; }
  	}
    @else if $point ==  smaller-screen {
	    @media (min-width: 800px)  { @content; }
  	}
	@else if $point ==  portrait {
		@media (min-width: 768px)  { @content; }
	}
	@else if $point ==  small {
		@media (min-width: 640px)  { @content; }
	}
	@else if $point ==  large-mobile {
		@media (min-width: 480px)  { @content; }
	}
	@else if $point ==  mobile {
		@media (min-width: 360px)  { @content; }
	}
}

When I want to implement these breakpoints within my SASS, it looks like this:

.something {
	padding: 100px;

	@include breakpoint(small) {
		padding: 10px;
	}
}

I have a snippet set up within Sublime Text 3 that makes this really easy to implement.


Arrows

On CSS-Tricks, there’s a post about creating triangles in pure CSS. I decided to turn that into a mixin.

@mixin arrow ($direction, $size, $color) {
	@if $direction == up {
		border-left: $size solid transparent;
		border-right: $size solid transparent;
		border-bottom: $size solid $color;
	} @else if $direction == down {
		border-left: $size solid transparent;
		border-right: $size solid transparent;
		border-top: $size solid $color;
	} @else if $direction == right {
		border-top: $size solid transparent;
		border-bottom: $size solid transparent;
		border-left: $size solid $color;
	} @else if $direction == left {
		border-top: $size solid transparent;
		border-bottom: $size solid transparent;
		border-right:$size solid $color;
	}
}

Then, when I want to implement it:

.read-more { 
		&:before {
			@include arrow (right, 3px, black);
		}
}

That’s easy enough.


Color

I have a set of functions for dealing with color:

@function darkest( $color ) 	{ @return darken($color,20%); }
@function darker( $color ) 		{ @return darken($color,13.333%); }
@function dark( $color ) 		{ @return darken($color,6.667%); }
@function light( $color ) 		{ @return lighten($color,16.667%); }
@function lighter( $color ) 	{ @return lighten($color,33.333%); }
@function lightest( $color ) 	{ @return lighten($color,50%); }

I can easily make the rollover color, a shade darker by using:

a {
	&:hover {
		color: darker($red);
	}
}

I don’t have to open Photoshop or create an additional variable.


Black and White (and Color)

@mixin black-and-white() {
	filter: grayscale(100%);
}

@mixin color() {
	filter: grayscale(0%);
}

Now, I can easily convert anything to black and white:

.my-image {
	@include black-and-white;
}

Then, if I want to give it color, say on rollover:

.my-image {
		&:hover {
			@include color;
		}
	}

Columns

@mixin columns ($columns: 2, $gap: 90px) {
	column-count: $columns;
	column-gap: $gap;
}

This mixin makes it easy to implement columns. You can tell from the code that I have defaults set for 2 columns with 90px between each column. Meaning, I can implement it without adding any parameters:

.two-columns {
	@include columns();
}

Or if I want to override it I can:

.three-columns {
		@include columns(3, 30px);
}

If I want to get crazy, I can even use some of my mixins together:

.two-columns {
	@include columns();

	@include breakpoint(zurb-small) {
		@include columns(1);
	}
}

This just says that the two column class will display 2 columns, unless we’re on mobile. Then, display 1 column.

path

I have a path function that makes it easy to include images within my SCSS:

@function path($src, $dir: img) {
	$src: unquote($src);
	@return url(unquote("..")/$dir/$src);
}

When I set a background image, it might look like this:

.background-image {
	background: path("my-background-image.jpg") center top no-repeat;
}

By default, it puts my images within a img directory. I can override that, either by passing in another parameter or adjusting the function.


List Styling

@mixin no-bullets {
	list-style: none;
}

This is great when I’m working on site navigation:

nav ul {
	@include no-bullets;
}

No Margin, No Padding

@mixin no-margin-padding() {
		margin: 0;
		padding: 0;
}

Just as the name suggests, using this will remove any margin and padding from the element:

nav ul {
	@include no-margin-padding;
}

Circles

@mixin circle() {
	border-radius: 50em;
}

This turns any item into a circle:

.circle-thumbnail {
		@extend %circle;
}

Conclusion

These are all great, but what’s the point? Well, instead of having to write these styles every time I sit down to work on a project, I have a starting point. Don’t reinvent the wheel every time if you don’t have to. Make it easier on yourself!

Second, any project that I work on, I know I have certain classes available to me. I don’t have to look up the class names. I’ve established a set of standards. Remember, work smarter not harder.


The Conversation

  • Just stumbled on your article while working on extending the Foundation framework. Excellent work and ideas! I wonder what your thoughts on the debate over mixins vs extends is? Seems that extends are very unpopular.

    • Amy Dutton

      …so… instead of just answering your question with my personal preferences, I decided to do a little research to validate my thoughts and make sure the information I’m providing is relevant, educated, and (most importantly) correct

      The top results on Google are by Harry Roberts, on the CSS Wizardry. I’m familiar with his work. He’s a great thought leader when it comes to CSS / Sass. — Check out http://cssguidelin.es/, it’s one of his resources, and one of my favorites.

      Anyway, he’s written two posts on the topic:

      When to Use @extend; when to use a mixin
      https://csswizardry.com/2014/11/when-to-use-extend-when-to-use-a-mixin/

      Mixins are Better for Performance
      https://csswizardry.com/2016/02/mixins-better-for-performance/

      I had always favored @extends, thinking that my code would be smaller. Technically it is. But, it’s not better (because you’re linking unrelated items) and it’s not smaller when gzipping. (In the second article I listed, Harry did some performance tests.) There is a time and place, for @extends, but only when you’re linking related items together (i.e. button states and styles).

      Thanks for the comment and bringing this to my attention. I’ll be updating my broiler plate and this post.

      • Thanks, Amy! Yeah, I was just reading those same articles when I came across yours. I agree, @extends are great, but full of pitfalls. Seems that everyone is moving away from them in favor of mixins.

        Would love to know how you refactor your code when you get it to a place you’re happy with.

        Thanks!

      • Hi Amy-
        I’ve been looking into this more and found this article on CSS Wizardry which references exactly the style you’re using. Seems like it’s ok to do as long as you only use the %placeholder class once:

        https://csswizardry.com/2014/01/extending-silent-classes-in-sass/

        Any other thoughts or progress on your framework?

        Thanks again!

  • mtsweir

    Great solutions here, how would you be able to define multiple paths for images? I have a project with multiple directories under the ‘img’ folder, so I’d like to use a default path then be able to override this when I need to point to another sub folder e.g img/icons

    • Amy Dutton

      If you look at the path function, it accepts 2 parameters:

      @function path($src, $dir: img)

      The first $src is the image name, the second is the directory. A default is provided (img), so you don’t always have to include the directory.

      In your case, you could use this to your advantage:

      @include path("facebook.png", "img/icons");

      or I believe this would also work:

      @include path("icons/facebook.png");