Search code examples
csssassmixinstypography

Fluid typography Sass mixin creating multiple rules for same element


I am using Indrek Pass' Sass mixin for fluid typography as per Mike Riethmuller's post.

When you look at the compiled CSS from that mixin you can see that it creates more than one rule for the chosen element if one uses the mixin for more than one breakpoint. And I sure do like to have the typography exactly as I want it and not be limited to having the typography scale up or down in just one media query.

SASS

html {
  @include fluid-type(font-size, 0px, 400px, 12px, 40px);
  @include fluid-type(font-size, 401px, 800px, 20px, 80px);
  @include fluid-type(font-size, 801px, 1400px, 80px, 12px);
}

CSS

html {
  font-size: 12px;
  font-size: 20px;
  font-size: 80px;
}
@media screen and (min-width: 0px) {
  html {
    font-size: calc(12px + 28 * (100vw - 0px) / 400);
  }
}
@media screen and (min-width: 400px) {
  html {
    font-size: 40px;
  }
}
@media screen and (min-width: 401px) {
  html {
    font-size: calc(20px + 60 * (100vw - 401px) / 399);
  }
}
@media screen and (min-width: 800px) {
  html {
    font-size: 80px;
  }
}
@media screen and (min-width: 801px) {
  html {
    font-size: calc(80px + -68 * (100vw - 801px) / 599);
  }
}
@media screen and (min-width: 1400px) {
  html {
    font-size: 12px;
  }
} 

How do you deal with the multiple font-size declarations in the compiled CSS, in this example the very first HTML tag?

a)
Do you go in with a grunt task/postCSS package to get rid of the multiple declarations?? If so what grunt task/postCSS package?

b)
Do you do this by hand if must be?? I can see myself already spending hours on checking compiled CSS for this, not really what I like to do..

c)
Is there a way to edit the Sass mixin to take care of the multiple declarations per element?

Besides this I am really happy with this mixin and find it works great! Being able to get rid of this issue without editing each affected selector in the compiled CSS would be great.


Solution

  • I assume what you are trying to achieve is a fluid transition in 2 parts. Something like this: not a very good illustration?

    The example you have would not do this exactly because the values overlap 12-40, 20-80 & 80-12. Each of these transitions would occur in order, meaning that at a screen resolution of 401 pixels the font size would jump from 40 to 20px.

    That aside, if this is what you are trying to do, you can simply remove the sum of the resulting code from the html tag and keep the smallest value:

    html {
      font-size: 12px;
    }
    @media screen and (min-width: 0px) {
      html {
        font-size: calc(12px + 28 * (100vw - 0px) / 400);
      }
    }
    @media screen and (min-width: 401px) {
      html {
        font-size: calc(20px + 60 * (100vw - 401px) / 399);
      }
    }
    @media screen and (min-width: 801px) {
      html {
        font-size: calc(80px + -68 * (100vw - 801px) / 599);
      }
    }
    @media screen and (min-width: 1400px) {
      html {
        font-size: 12px;
      }
    } 
    

    This mixin was not designed to do multi-part transitions like this. If you'd like to write one that does I will happily share it. You might find this blog post helpful: madebymike.com.au/writing/precise-control-responsive-typography/

    Update:

    I've recently written something more about this: http://madebymike.com.au/writing/non-linear-interpolation-in-css/ and developed a new Sass mixin that allows the use of animation-timing-functions to define 'bending points'. It works like this:

    .classic-linear {
        @include interpolate('font-size', 600px, 12px, 1000px, 24px); 
    }
    
    .easy-peasy {
      @include interpolate('font-size', 600px, 12px, 1000px, 24px, 'ease-in');
    }
    
    .cubic-bezier {
      @include interpolate('font-size', 600px, 12px, 1000px, 24px, 'cubic-bezier(0.75, 0.05, 0.85, 0.06)');
    }
    
    .bloat-my-css {
      @include interpolate('font-size', 600px, 12px, 1000px, 24px, 'ease-in-ease-out', 10);
    }
    

    It has 5 required parameters, including the target property, initial screen size, initial value, final screen size and final value.

    It has two optional parameters which include an easing property, which is a string representation of a CSS animation-timing-function, and finally a number of bending points that determines how many interpolation steps are applied along the easing function.

    I hope that helps!