The power of mixins is not limited to inclusion in the CSS. Just like a variable can be assigned to another variable, a mixin can be included in another mixin allowing for another level of modularity in your stylesheet. As we build a module, for example a button, we are not only building a modular component that can be used as a variety of buttons are created but also we are breaking down our component into smaller components like gradient color, border, padding, and etc...
Let's take a closer look at the assembly of a button. Here are the rules for our .primary-button
selector:
.primary-button {
font-family: 'merriweather_sanslight', sans-serif;
-moz-box-shadow:inset 0px 1px 0px 0px #ebf5ff;
-webkit-box-shadow:inset 0px 1px 0px 0px #ebf5ff;
box-shadow:inset 0px 1px 0px 0px #ebf5ff;
background:-webkit-gradient( linear,
left top,
left bottom,
color-stop(0.05, #70d9ff),
color-stop(1, #3481cf) );
background:-moz-linear-gradient( center top,
#70d9ff 5%,
#3481cf 100% );
background-color: #70d9ff;
border-radius: 0;
text-indent: 0;
border: 1px solid #9cceff;
display: inline-block;
color: #ffffff;
font-size: 28px;
font-weight: normal;
font-style: normal;
line-height: 48px;
padding-left: 30px;
padding-right: 30px;
text-decoration: none;
text-align: center;
}
I have created some mixins in order to handle some of the rules that we use often:
$border-position-all: all !default;
$border-default-size: 1px !default;
$border-default-pattern: solid !default;
$border-default-color: $black !default;
// Mixin arguments set to specified variables as defaults
// This is a mixin that will allow the user to add border to an element.
// It is robust enough to allow the user to select a certain side where the border
// should be applied or it can applied on all sides.
@mixin add-border(
$border-position: $border-position-all,
$border-size: $border-default-size,
$border-pattern: $border-default-pattern,
$border-color: $border-default-color) {
@if $border-position == $border-position-all {
border: $border-size $border-pattern $border-color;
}
@else {
border-#{$border-position}: $border-size
$border-pattern $border-color;
}
}
// This function was created in order to be able to take a variable argument, in this case the number
// of color stops for the gradient, and return a comma separated list.
@function linearGradientColors($stop-colors...) {
$full: false;
@each $stop-color in $stop-colors{
@if $full {
$full: $full + ',' + $stop-color;
} @else {
$full: $stop-color;
}
}
$full: unquote($full);
@return $full;
}
// When creating a function, we place the functional name however for expediency sake, an overloaded
// function is created with a smaller name (usually an acronym of the functions name) so that re-use of the function would be easier.
@function lgc($stop-colors...) {
@return linearGradientColors($stop-colors...);
}
// This mixin will create a linear gradient using a variable argument for any number of color stops desired.
// The $pos variable allows use to set the gradient line.
@mixin linear-gradient($pos, $stop-colors...) {
// Detect what type of value exists in $pos
$pos-type: type-of(nth($pos, 1));
// If $pos is missing from mixin, reassign vars
// and add default position
@if ($pos-type == color) or (nth($pos, 1) == "transparent") {
$pos: top; // Default position
}
$pos: unquote($pos);
$full: lgc($stop-colors...);
// Set the first stop-color as the default fallback color
$fallback-color: nth(nth($stop-colors, 1), 1);
background: $fallback-color;
background: linear-gradient($pos, $full);
}
// This mixin allows us to add box shadows to an element handling the option for an inset box shadow.
@mixin box-shadow ($isInset: false,
$hOffset: 0,
$vOffset: 0,
$blur: 0,
$spread: 0,
$color: #ccc) {
@if $isInset {
box-shadow: inset $hOffset $vOffset $blur $spread $color;
} @else {
box-shadow: $hOffset $vOffset $blur $spread $color;
}
}
These mixins are useful for not only the CSS stylesheets but also can be used anywhere within our Sass environment. It can be used in mixins or functions (although the use in functions is uncommon). Let's take a look at our .primary-button
selector and see how I can improve it using some of the above mixins.
While examine the primary-button
style, I found the following aspects:
Let's optimize the .primary-button
selector using Sass. First I will add the colors of the button to our _config.scss
file. However, I will add the primary blue color of the button and all other shades/variations of the color will be used. For example, I could write the colors in the _config.scss
file as such:
... //some config variables here
// Primary colors
// -------------------------
$blue: #3481CF !default;
$white: #FFFFFF !default;
$black: #000000 !default;
$gray: #7F7F7F !default;
//button colors
// -------------------------
$primary-button-primary-color: $blue !default;
$primary-button-secondary-color: #70D9FF !default;
$primary-button-tertiary-color: #9cceff !default;
$primary-button-quaternary-color: #ebf5ff !default;
Although this is not wrong, it is inefficient and a common mistake many developers new Sass will make. The better approach is to use the color functions that come with Sass to your advantage which will also extend the color scheme so that if the color of the button changes from blue to green, for example, there is only one color to change.
I get the exact colors using Sass' color functions. However, this is also a good time to sit with the designer (if it is not you) and reign in the number of colors used on the site. It's helpful to make the different shades of a color, in this example the blue color of #3481CF
, an easy off shoot of the primary color being used. In this manner, I can re-write the above as such:
... //some config variables here
// Primary colors
// -------------------------
$blue: #3481CF !default;
$white: #FFFFFF !default;
$black: #000000 !default;
$gray: #7F7F7F !default;
//button colors
// -------------------------
$primary-button-primary-color: $blue !default;
$primary-button-secondary-color:
adjust-hue(lighten($blue, 11%), -14deg) !default;
$primary-button-tertiary-color: lighten($blue, 36%) !default;
$primary-button-quaternary-color: lighten($blue, 44%) !default;
This approach is advantageous in the following manner:
Now that I the colors set, I can start re-writing some of the elements of the .primary-button
selector. First step, incorporate our linear gradient mixin.
.primary-button {
@include linear-gradient(center top,
$primary-button-secondary-color 5%,
$primary-button-primary-color 100%);
//... remaining styles
}
Let's add the box shadow styling:
.primary-button {
@include linear-gradient(center top,
$primary-button-secondary-color 5%,
$primary-button-primary-color 100%);
@include box-shadow (@isInset: true,
$vOffset: 1px,
$color: $primary-button-quaternary-color);
//... remaining styles
}
Let's add the borders:
.primary-button {
@include linear-gradient(center top,
$primary-button-secondary-color 5%,
$primary-button-primary-color 100%);
@include box-shadow (@isInset: true,
$vOffset: 1px,
$color: $primary-button-quaternary-color);
//... remaining styles
}
Here is the final style as the mixins are incorporated:
.primary-button {
@include linear-gradient(center top,
$primary-button-secondary-color 5%,
$primary-button-primary-color 100%);
@include box-shadow (@isInset: true,
$vOffset: 1px,
$color: $primary-button-quaternary-color);
@include add-border($border-color: $primary-button-tertiary-color);
border-radius: 0;
display: inline-block;
color: #ffffff;
font: {
size: 28px;
weight: normal;
style: normal;
family: 'merriweather_sanslight', sans-serif;
}
line-height: 48px;
padding-left: 30px;
padding-right: 30px;
text-indent: 0;
text-decoration: none;
text-align: center;
}
By incorporating the mixins, I have not only re-used code, but also in further implementations of this button, whether it be a different type of button or the implementation of pseudo classes like :hover
, I can further use and extend this code base.