Sass reusables

In my Should have kept it Sass-y article, I briefly mentioned and linked to a GitHub gist of Sass reusables that I wrote for my projects. While I’m sure most people who get far enough to see it will know what it’s all about, I wanted to include some explanations.

When I start a new project, I generally copy this gist into a Sass partial named _base.sass. Combined with importing Compass, I’m pretty much ready to go.

Defaults

Just some default variables for the arguments within the mixins and functions, they also happen to be what I use most often.

The base font size is set to 16px. Since I generally build mobile first, I set the “mobile” max-width to 767px, tablet’s portrait orientation (pretty much iPad) to a min-width of 768px, and finally “desktop” to a min-width of 769px.

// Defaults
$base-font-size: 16px !default
$base-respond-to-mobile: 767px !default
$base-respond-to-tablet: 768px !default
$base-respond-to-desktop: 769px !default

Relative units

I love using relative units, and without sounding too dogmatic, you should too. Check out Harry Robert‘s article on Measuring and Sizing UIs.

His key points sums it up perfectly, although I would definitely use unitless line-heights as recommended by Eric Meyer in 2006.

  • Set structure in percentages. This includes content areas, sidebars etc.
  • Set type in rems with a pixel fallback for older browsers. This gives us a great amount of control with added scalability.
  • Set type-related items in ems so that paddings et al scale with the font-size.
  • Set line-heights in relative units. Or, even better, with no units at all.
  • Don’t set measurements on components at all. They should remain fully fluid and ‘just work’ wherever you drop them.
Harry Robert, Measuring and sizing UIs, 2011-style (and beyond)

The problem is the real world. Designers typically send me font sizes and line-heights in pixels, not to mention it’s much easier to distinguish a pixel size (say 20px) versus a relative size (1.42857em). Thus I like to use pixels throughout and let Sass translate them into the appropriate relative unit. It’s also much less painful if you want to adjust font sizes but not layout.

// Function for calculating rem.
// Ensure both numbers use the same unit.
@function rem($size, $base: $base-font-size)
    @return #{$size/$base}rem

Since it’s a function you’d call it inline, like so:

p
    font-size: rem(20px)

With the default left at 16px, it would return:

p {
    font-size: 1.25rem;
}
// Function for calculating em.
// Ensure both numbers use the same unit.
@function em($size, $base: $base-font-size)
    @return #{$size/$base}em

The em function works exactly the same.

p
    font-size: em(20px)
p {
    font-size: 1.25em;
}

Unlike rems, ems are set relative to the parent instead of relative to the root. So if you wanted a paragraph with 20 pixels that’s inside of a parent with say 30 pixels, you’d have to use the $base argument to get the appropriate ems. Remember target / context = result.

p
    font-size: em(20px, $base: 30px)
p {
    font-size: 0.66667em;
}

I need to update these two a little bit to account for different units, since right now you need to ensure the units are matching so they cancel out.

Fonts

I hardly ever use the rem function on its own, the real power with it comes in the font mixin. (Although I don’t really know why I’m not using it for some margins and sizes.) It’s a little daunting when you first look at it, but only because of the conditional checks.

This mixin will let you use all of the font properties as well as line-height and letter-spacing, so you can put the majority of your typographic styles in one little place. If you’re using at least the size and family, then you can set the $shorthand argument to true and you’ll get your fonts in CSS shorthand. The variable $font-initial-value is set to normal to avoid errors, and output less CSS (excluding shorthand) than you might need.

// Font mixin
$font-intial-value: normal !default
@mixin font($family: false, $size: false, $style: $font-intial-value, $weight: $font-intial-value, $variant: $font-intial-value, $spacing: false, $height: false, $shorthand: false)
    @if $shorthand == true
        @if $height
            font: $style $variant $weight $size/#{$height} $family
            font-size: rem($size)
        @else
            font: $style $variant $weight $size $family
            font-size: rem($size)
        @if $spacing
            letter-spacing: $spacing   
    @else
        @if $family
            font-family: $family
        @if $size
            font-size: $size
            font-size: rem($size)
        @if $style != $font-intial-value
            font-style: $style
        @if $weight != $font-intial-value
            font-weight: $weight
        @if $variant != $font-intial-value
            font-variant: $variant
        @if $spacing
            letter-spacing: $spacing
        @if $height
            line-height: $height

Using the same example as earlier, if you wanted to get a 20 pixel paragraph you’d now include the font mixin.

p
    +font($size: 20px)

But this time it would also return a pixel fallback:

p {
    font-size: 20px;
    font-size: 1.25rem;
}

Now this time you might want to change more about the font, like the family, the line-height and the size. You could do this (and yes, I really should do something with the unquote in the function):

p
        +font($family: unquote("Arial, sans-serif"), $size: 20px, $height: 1.5)

Which would return:

p {
    font-family: Arial, sans-serif;
    font-size: 20px;
    font-size: 1.25rem;
    line-height: 1.5;
}

But since you have enough properties, why not use shorthand? All you’d have to do is set the $shorthand argument to true.

p
    +font($family: unquote("Arial, sans-serif"), $size: 20px, $height: 1.5, $shorthand: true)

And this time you’d get:

p {
    font: normal normal normal 20px/1.5 Arial, sans-serif;
    font-size: 1.25rem;
}

Voilà. The initial properties are somewhat annoying, but they really won’t hurt anything…unless of course you want to change them, then you can do that when you include the mixin.

Web fonts

The web fonts mixin works in exactly the same manner, but is for including web fonts like Google Web Fonts or Typekit using the WebFont Loader. If you want to hide FOUT then you can set the $wf-hide argument to true. Other than that, everything else is the same…that is until it outputs to CSS.

// Web font mixin
@mixin wf-font($wf-family: false, $wf-size: false, $wf-style: $font-intial-value, $wf-weight: $font-intial-value, $wf-variant: $font-intial-value, $wf-spacing: false, $wf-height: false, $shorthand: false, $wf-hide: false)
    @if $wf-hide == true
        .wf-loading &
            visibility: hidden
    .wf-active &
        @if $shorthand == true
            @if $wf-height
                font: $wf-style $wf-variant $wf-weight $wf-size/#{$wf-height} $wf-family
                font-size: rem($wf-size)
            @else
                font: $wf-style $wf-variant $wf-weight $wf-size $wf-family
                font-size: rem($wf-size)
            @if $wf-spacing
                letter-spacing: $wf-spacing   
        @else
            @if $wf-family
                font-family: $wf-family
            @if $wf-size
                font-size: $wf-size
                font-size: rem($wf-size)
            @if $wf-style != $font-intial-value
                font-style: $wf-style
            @if $wf-weight != $font-intial-value
                font-weight: $wf-weight
            @if $wf-variant != $font-intial-value
                font-variant: $wf-variant
            @if $wf-spacing
                letter-spacing: $wf-spacing
            @if $wf-height
                line-height: $wf-height

Maybe this time you want to use Open Sans as your font family.

p
    +font($family: unquote("Arial, sans-serif"), $size: 20px, $height: 1.5, $shorthand: true)
    +font($wf-family: "Open Sans", $wf-size: 20px, $wf-height: 1.5, $shorthand: true, $wf-hide: true)

You’d get:

p {
    font: normal normal normal 20px/1.5 Arial, sans-serif;
    font-size: 1.25rem;
}

.wf-loading p {
    visibility: hidden;
}

.wf-active p {
    font: normal normal normal 20px/1.5 "Open Sans";
    font-size: 1.25rem;
}

I’ll probably go into webfonts at another time; however, that time is not now.

Mobile first media query

As I mentioned previously, I tend to build mobile first so that’s what this mixin is geared towards. I often only include three breakpoints unless otherwise needed. For most instances I think mobile, tablet portrait, and desktop should cover your bases. (For mobile first, having a “mobile” media query isn’t that useful but the need might arise.

// Mobile first media query mixin
@mixin respond-to($device)
    @if $device == mobile
        @media only screen and (max-width: $base-respond-to-mobile)
            @content
    @if $device == tablet
        @media only screen and (min-width: $base-respond-to-tablet)
            @content
    @if $device == desktop
        @media only screen and (min-width: $base-respond-to-desktop)
            @content

In this instance let’s say you want your paragraph to float in tablet and above for some reason. So you’d include the mixin like so:

p
    +respond-to(tablet)
        float: left

Which will net you this sweet little media query for tablet portrait sizes and larger.

@media only screen and (min-width: 768px) {
  p {
    float: left;
  }
}

Hopefully these are somewhat useful for your projects. Feel free to fork, copy, modify, or otherwise do what you please with them. If you see something that I could improve upon then please let me know.