Sass and Responsive Typography

Share this article

As web fonts have grown (in number, quality, and ease of use), web typography has become a necessary part of web design. Web typography is a complex topic including many smaller aspects like font pairing, performance, FOUT, ligatures, and type scales.

As you make typographic choices when building websites, it is essential to keep responsive design in mind. It’s frustrating to read a page on a phone with huge desktop-sized headings; it’s also dull to see all the font sizes on a site stuck between 14px and 20px on a wide-screen monitor. These problems have helped me define responsive web typography with three components:

  1. Base font-size that changes at breakpoints
  2. Vertical rhythm that changes at breakpoints
  3. Consistent type scales that change at breakpoints

These three things are an important part of normal web typography: making them adjustable at a given breakpoint gives us the ability to tailor typography to the user’s viewport.

Organizing Data with Sass Maps

If you’ve never used a map in Sass before, this article is a great introduction. In Sass, maps are arrays of data. You can nest maps for detailed, multi-layer data organization. Let’s take a look at a map we can base responsive typography on:

$rwd-typography: (
  default: (
    base-font-size: 16px,
    vertical-rhythm: 1.414,
    type-scale: 1.2,
    min-width: null
  ),
  medium: (
    base-font-size: 18px,
    vertical-rhythm: 1.5,
    type-scale: 1.414,
    min-width: 480px
  ),
  large: (
    base-font-size: 20px,
    vertical-rhythm: 1.618,
    type-scale: 1.5,
    min-width: 960px
  ),
  xlarge: (
    base-font-size: 24px,
    vertical-rhythm: 1.618,
    type-scale: 1.618,
    min-width: 1300px
  )
);

That map has the three typographic details we need for responsive typography spread across four breakpoints. It also has a min-width measurement for the media query used at each breakpoint. Note: the media query value can be whatever your project needs. After all, breakpoints should be determined by content, not by framework defaults!

The base-font-size value in each nested map sets the normal font-size for body text. The vertical rhythm value sets the line-height for normal body text and is used to create vertical rhythm for headings and other non-<p> elements. The type-scale value determines how much larger each step up the type scale gets. For example, on our default size, paragraph text will be 16px, the next size up (let’s call it “block quote” for now) will be 16px × 1.2, or 19.2px. The next size up “subheading” perhaps?) will be 19.2px × 1.2, or 23px.

Now that I’ve introduced paragraph, sub-sub-heading, and sub-heading (and presumably, heading and hero sizes too), we’ll need to generate those sizes. Let’s put our type scale labels into a Sass list:

$rwd-scale-labels: (p, bq, sh, h, hero);

Now that we’ve got all our data stored, let’s write some Sass to build our sizes automatically!

Generating Sizes with Sass Loops and Mixins

We can use some loops and mixins to generate responsive font-sizes now. We’ll start by writing a loop that goes through each of the font scale labels and generates a Sass placeholder selector for each one.

@each $label in $rwd-scale-labels {
  %#{$label} {
    // we’ll put more code here soon…
  }
}

Inside each of those placeholders, we’ll nest another @each statement to loop through the breakpoints and generate our typography:

@each $breakpoint, $data in $rwd-typography {
  // $breakpoint represents the breakpoint’s key,
  // $data is the nested map containing its data
}

Inside that loop, the first thing we’ll do is find out if we need a media query or not. The default / first breakpoint doesn’t need a media query; the others do.

@if map-get($data, min-width) != null { //CHECK != syntax
  @media screen and (min-width: map-get($data, min-width)) {
    // generate CSS output here
  }
} @else {
  // generate CSS output here
}

Let’s leave all that nested code alone for now and write some helper functions to generate our CSS values. The first function we’ll write will get the font-size for the current label at the current breakpoint:

@function rwd-generate-font-size($label, $breakpoint) {
  $label-position: index($rwd-scale-labels, $label);
  $breakpoint-base-font-size: map-get(map-get($rwd-typography, $breakpoint), base-font-size);
  $breakpoint-type-scale: map-get(map-get($rwd-typography, $breakpoint), type-scale);
  $return: $breakpoint-base-font-size;
  @for $i from 1 to $label-position {
    $return: $return * $breakpoint-type-scale;
  }
  @return $return;
}

There are several advanced Sass functions used above:

  • index($item, $list) gets the position of an item in a list
  • map-get($map, $key) returns the value that matches the specified key in a given map

The @for loop roughly mimics a power() function / exponential math.

We’ll plug that into our loop right above our media query check:

$current-font-size: rwd-generate-font-size($label, $breakpoint);

Now, let’s expand the function above to generate the line-height to match our vertical rhythm:

@function rwd-generate-font-size($label, $breakpoint) {
  $label-position: index($rwd-scale-labels, $label);
  $breakpoint-base-font-size: map-get(map-get($rwd-typography, $breakpoint), base-font-size);
  $breakpoint-type-scale: map-get(map-get($rwd-typography, $breakpoint), type-scale);
  $breakpoint-vertical-rhythm: map-get(map-get($rwd-typography, $breakpoint), vertical-rhythm);
  $font-size: $breakpoint-base-font-size;
  @for $i from 1 to $label-position {
    $font-size: $font-size * $breakpoint-type-scale;
  }
  $base-vertical-rhythm: $breakpoint-base-font-size * $breakpoint-vertical-rhythm;
  $line-height: round($font-size / $base-vertical-rhythm) * $base-vertical-rhythm / $font-size;
  $return: join($font-size, $line-height);
  @return $return;
}

Now the $return value of this function is a list with two values: the font-size and the line-height. We’ll need to update the variable assignment in our loop to match that:

$generated-values: rwd-generate-font-size($label, $breakpoint);
  $font-size: nth($generated-values, 1);
  $line-height: nth($generated-values, 2);

The nth() function in Sass returns the list value at the given index position.

Now let’s put everything in our loop together:

@each $label in $rwd-scale-labels {
  %#{$label} {
    @each $breakpoint, $data in $rwd-typography {
      $generated-values: rwd-generate-font-size($label, $breakpoint);
      $font-size: nth($generated-values, 1);
      $line-height: nth($generated-values, 2);

      @if map-get($data, min-width) != "null" {
        @media screen and (min-width: map-get($data, min-width) {
          font-size: $font-size;
          line-height: $line-height;
        }
      } @else {
        font-size: $font-size;
        line-height: $line-height;
      }
    }
  }
}

Now to use those styles, extend them from actual selectors. For example:

body {
  @extend %p;
}

blockquote {
  @extend %bq;
}

h1 {
  @extend %h;
}

h2 {
  @extend %sh;
}

.hero-title {
  @extend %hero;
}

Now each of those selectors gets all the media-query based output we generated with our loops and function above! You can set all your data in the initial map and list, then extend the labels you created to create responsive typography with the automatically generated CSS output from the loops.

Frequently Asked Questions (FAQs) about SASS Responsive Typography

How can I use SASS for responsive typography?

SASS, or Syntactically Awesome Stylesheets, is a powerful tool for creating responsive typography. It allows you to define variables, mixins, and functions that can be used to create flexible, scalable typography. To use SASS for responsive typography, you need to first install it in your project. Then, you can define variables for your font sizes and line heights, and use these variables in your stylesheets. You can also use mixins to create reusable styles, and functions to calculate font sizes based on the viewport size.

What are the benefits of using SASS for responsive typography?

SASS offers several benefits for responsive typography. It allows you to create scalable, flexible typography that adapts to different screen sizes. With SASS, you can define variables for your font sizes and line heights, which makes your code more maintainable and easier to update. You can also use mixins and functions to create reusable styles and perform calculations, which can save you time and reduce code duplication.

How can I use the ‘for’ control directive in SASS?

The ‘for’ control directive in SASS allows you to create loops in your stylesheets. This can be useful for generating repetitive styles. To use the ‘for’ directive, you need to specify a start and end value, and SASS will iterate over this range, executing the code block for each iteration. For example, you could use the ‘for’ directive to generate a series of classes with different font sizes.

How does the ‘each’ control directive work in SASS?

The ‘each’ control directive in SASS allows you to iterate over a list or map. This can be useful for applying styles to a series of elements. To use the ‘each’ directive, you need to specify a list or map, and SASS will iterate over this collection, executing the code block for each item. For example, you could use the ‘each’ directive to apply a different color to each item in a list.

Can I use loops in SASS?

Yes, you can use loops in SASS using the ‘for’, ‘each’, and ‘while’ control directives. These directives allow you to iterate over a range, list, or until a condition is met, respectively. This can be useful for generating repetitive styles or applying styles to a series of elements. For example, you could use a ‘for’ loop to generate a series of classes with different font sizes, or an ‘each’ loop to apply a different color to each item in a list.

How can I increment by a value other than 1 in a SASS loop?

In SASS, you can increment by a value other than 1 in a loop by using the ‘for’ control directive with a step value. The step value determines how much the loop counter is incremented by in each iteration. For example, if you wanted to increment by 2, you could write ‘@for $i from 1 through 10 by 2’, and SASS would iterate over the numbers 1, 3, 5, 7, and 9.

What is iteration control in SASS?

Iteration control in SASS refers to the use of control directives like ‘for’, ‘each’, and ‘while’ to create loops in your stylesheets. These directives allow you to iterate over a range, list, or until a condition is met, respectively. This can be useful for generating repetitive styles or applying styles to a series of elements. For example, you could use a ‘for’ loop to generate a series of classes with different font sizes, or an ‘each’ loop to apply a different color to each item in a list.

How can I use SASS to create a responsive typography scale?

To create a responsive typography scale with SASS, you can use variables, mixins, and functions. First, define variables for your base font size and line height. Then, use these variables in a mixin to create a reusable style for your text elements. Finally, use a function to calculate the font size based on the viewport size. This will create a typography scale that adapts to different screen sizes.

Can I use SASS with CSS frameworks like Bootstrap?

Yes, you can use SASS with CSS frameworks like Bootstrap. In fact, Bootstrap uses SASS for its source stylesheets. This means you can customize Bootstrap’s styles using SASS variables, mixins, and functions. For example, you could change the base font size or color scheme by overriding Bootstrap’s default SASS variables.

How can I compile my SASS code into CSS?

To compile your SASS code into CSS, you need to use a SASS compiler. There are several SASS compilers available, including the official SASS compiler and third-party tools like Node-sass and Dart-sass. These compilers will take your SASS code and generate a CSS file that can be included in your HTML. Most SASS compilers also offer a watch mode, which will automatically compile your SASS code whenever it changes.

James SteinbachJames Steinbach
View Author

James is a Senior Front-End Developer with almost 10 years total experience in freelance, contract, and agency work. He has spoken at conferences, including local WordPress meet-ups and the online WP Summit. James's favorite parts of web development include creating meaningful animations, presenting unique responsive design solutions, and pushing Sass’s limits to write powerful modular CSS. You can find out more about James at jamessteinbach.com.

responsive typographyresponsive web designRWDsasssass functionssass mapsStuRWeb Typography
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week