A Beginner's Guide to Sass with Shopify — Part 2: Making Stylesheets Smarter with Sass Mixins and Functions

A beginner's guide to building Shopify themes with Sass part 2

The use of Sass on compiled themes is being deprecated, and stylesheets should migrate to native CSS features. For more information on this change and how to use Sass locally in your theme development workflow, please read our announcement blog post on deprecating Sass.

In part one of this series, I introduced you to Sass in Shopify themes, explained variables and nesting, and discussed the limitations of the online store editor with Sass.

This article will focus on some of the more creative parts of Sass development — the things that can make your stylesheets smarter. We’ll take a look at using some of the operators built into Sass, as well as using some native Sass functions. We’ll also look at creating Sass mixins and extends.

This is part two in a three part beginner’s guide to Sass with Shopify.

Check out part one of this series, a beginner’s guide to Sass and Shopify themes.

Arithmetic operators

Sass has standard arithmetic operators baked in. These can be super helpful when trying to do calculations in your stylesheets, and have to support older browsers (IE8/IE9 reliably or Opera Mini) that don’t play nicely with the CSS calc() function. The calculations are done on compilation, and rendered as a specific value.

In Sass, we have access to the +, -, *, /, and % math operators.

For example:

.page-wrapper { 
  width: 100%;
}

.site-content {
  float: left;
  width: 600px / 960px * 100%;
}

.site-sidebar {
  float: right;
  width: 300px / 960px * 100%;
}

Compiles to:

.page-wrapper {
  width: 100%;
}

.site-content {
  float: left;
  width: 62.5%;
}

.site-sidebar {
  float: right;
  width: 31.25%;
}

When Sass gets compiled, the evaluation of the math we’ve done outputs to the final values in our stylesheet. This means that these values will work in browsers that don’t support the calc() CSS function.

Note that when Sass interpolation #{} is used near operators like /, those operators are treated as plain CSS rather than math operators.

For example:

p {
  $font-size: 100%;
  $line-height: 1.5;
  font: #{$font-size}/#{$line-height} Arial, Helvetica, sans-serif;
}

Compiles to:

p {
  font: 100%/1.5 Arial, Helvetica, sans-serif;
}

Where #{$font-size} and #{$line-height} resolve to 100%/1.5, instead of Sass trying to divide those two values by one another.

Mixins

Sometimes it can be tedious to write in CSS over and over. Mixins differ from functions in that a function’s main objective is to return a value, whereas a mixin enables the creation of a reusable chunk of CSS. Think of a @mixin like an include or snippet.

To create a mixin use the @mixin directive, and give it a name. Mixins can take multiple arguments in the form of variables, which are comma separated.

A simple example of this is to create a reusable button style. This mixin also includes a Sass function, which you can read more about in the next section of this article.

For example:

@mixin link($color-link) {
  text-decoration: none;
  color: $color-link;
}

Usage:

.link {
  @include link(#2980b9)
}

Output:

.link {
  text-decoration: none;
  color: #2980b9;
}

In the example above, @mixin link() is passed an argument of $color-link. Then, the $color-link argument is used throughout the mixin property values. To use the mixin you would use the @include directive, followed by the mixin name, and pass it the appropriate argument. In the case of this mixin, it’s a color value.

Below is a mixin I use to visually hide an element when I build themes, but still allows for that element to be read aloud by screen readers. Using a mixin for this makes it clear that the element is visually hidden in the styling. As a mixin, it then can be used multiple times throughout your styles, all while keeping accessibility in mind.

For example:

@mixin visually-hidden() {
  position: absolute !important;
  overflow: hidden;
  clip: rect(0 0 0 0);
  height: 1px;
  width: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
}

Usage:

.logo {
  background-image: url(logo.png);
}

.logo span {
  @include visually-hidden();
}

Output:

.logo {
  background-image: url(logo.png);
}

.logo span {
  position: absolute !important;
  overflow: hidden;
  clip: rect(0 0 0 0);
  height: 1px;
  width: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
}

You may also like: Developing Shopify Themes with Accessibility in Mind.

Functions

In Sass, you’ll hear about two types of functions, functions which you write yourself using the @function directive, and functions which are shipped with Sass.

Creating custom Sass functions

There are some pretty useful functions that you can create yourself. A function you create yourself uses the @function directive, followed by the name of the function. It must be declared first, and once declared, can be used later on in your stylesheet by calling on the name of your function.

The output of a function is a single value. This value can be any Sass data type, which includes: numbers, strings, colors, booleans, or lists. Functions can accept multiple arguments in the form of variables, which are comma separated.

I usually put custom Sass functions at the top of my stylesheet, just after variables, or in a separate file that’s imported after variables, but before all my other styles. We’ll talk more about file structure and workflow in part three of this series.

I often use an em() function. The function converts px values into em values ✨ auto-magically ✨ for you, based on a set base font size.

For example:

$browser-context: 16; // default

@function em($pixels, $context: $browser-context) {
  @return #{$pixels/$context}em
}

Usage:

h1 {
  font-size: em(72);
}

Output:

h1 {
  font-size: 4.5em;
}

This simple function converts to em values for you, which makes things much simpler than calculating them for yourself. Using em values for all sizing is especially helpful. If a user increases or decreases the size of their text, and you’ve used em sizing for layouts as well, things will automatically scale and flow appropriately.

Using native Sass functions

There are also a huge list of functions that ship with Sass, which come in handy when theming. These native Sass functions are super helpful when creating consistent variations for a specific color within your theme. For example, you might want to create a button, that uses your primary color as a background, but darkens that background when it’s hovered or active.

We’re going to use the Sass darken() function in the example below, to darken the $color-primary for our hover states.

The darken() function takes two parameters, a color (which can be of any format), and an amount to decrease the lightness by, which is a percentage from 0% - 100%.

darken($color, $amount)

In this example, we set the $color-primary as the background-color of the button. Using the Sass function darken(), we set the :hover and :focus state for the button to a darker background-color based on the $color-primary.

For example:

$color-primary: #2980b9;
$color-button-text: #ffffff;

.button {
  color: $color-button-text;
  background-color: $color-primary;
  font-weight: bold;
  padding: 1em 1.5em;
  display: inline-block;
  text-decoration:none;
  border-radius: 3px;
  
  &:hover,
  &:focus {
    background-color: darken($color-primary, 15%);
  }
}

Compiles to:

.button {
  background-color: #2980b9;
  color: #ffffff;
  font-weight: bold;
  padding: 1em 1.5em;
  display: inline-block;
  text-decoration:none;
  border-radius: 3px;
}

.button:hover, 
.button:focus {
    background-color: #1b557a;
}

There are a ton of other built-in Sass functions that you can access. You can check them out in the official Sass documentation, and try experimenting with different ones! Follow this tutorial to create dynamic color schemes using Sass functions and theme options.

You may also like: An Introduction to Theme Options.

Extend

The @extend directive lets you share a set of CSS properties from one selector to another. This can be incredibly useful if you don’t have access to update or change markup, but need to style an element. Note that when one uses the @extend selector, it extends all nested selectors as well.

For example:

.box {
  background-color: #f5f5f5;
  h2 {
    color: red;
  }
}

.block {
  @extend .box;
}

Compiles to:

.box, .block {
  background-color: #f5f5f5;
}

.box h2, .block h2 {
  color: red;
}

Notice that Sass doesn't "go get" the styles from .box, inserting them below into .block, then duplicating the styles. Instead, when Sass compiles it, the comma separates both selectors, applying the styles more efficiently.

Be careful not to abuse @extend. When you want to use @extend ask yourself if creating another class and adding it to your Liquid template might be more appropriate. There are some other gotchas that arise when you use @extend that you should be aware of, these include lengthy output, and selector order issues.

You’re on your way to making your theme smarter!

By using Sass operators, mixins, and functions, you can begin thinking about how you can make your styles more efficient. Already, you can start to see how much less typing you’ll have to do when styling.

Stay tuned for part three of this beginner’s guide to Sass with Shopify!

Do you know any helpful mixins or functions for Shopify Themes? Tell us about your favorite ones, and why you love using Sass in the comments below!

Grow your business with the Shopify Partner Program

Learn more