Skip to content

Instantly share code, notes, and snippets.

@samuel-holt
Last active November 23, 2016 18:58
Show Gist options
  • Save samuel-holt/07eb0aa44a60e3b3be9a to your computer and use it in GitHub Desktop.
Save samuel-holt/07eb0aa44a60e3b3be9a to your computer and use it in GitHub Desktop.
Responsive typography
// STRIP UNIT
// It strips the unit of measure and returns it
@function strip-unit($num) {
@return $num / ($num * 0 + 1);
}
// Media queries mixin
// Default widths
$default-medium: 768px !default;
$small-max: $default-medium - 1px;
$default-large: 960px !default;
$medium-max: $default-large - 1px;
$default-x-large: 1280px !default;
$large-max: $default-x-large - 1px;
$default-xx-large: 1920px !default;
$x-large-max: $default-xx-large - 1px;
//Aliases
$default-tablet: $default-medium;
$default-desktop: $default-large;
$default-query: "only screen" !default;
@function get-query($min, $max:false, $dimension:"width", $default:$default-query) {
@if not $min and not $max {
@warn "Minimum or maximum pixel value required!";
@return false;
}
$range: "";
@if $min and unitless($min) {
$min: $min * 1px;
}
@if $max and unitless($max) {
$max: $max * 1px;
}
@if $min {
$range: "(min-#{$dimension}:#{$min})";
}
@if $max {
$range: "#{$range} and (max-#{$dimension}:#{$max})";
}
@return "#{$default} and #{$range}";
}
$small-only: get-query(false, $small-max);
$default-medium-up: get-query($default-medium) !default;
$default-large-up: get-query($default-large) !default;
$default-x-large-up: get-query($default-x-large) !default;
$default-xx-large-up: get-query($default-xx-large) !default;
@mixin media($query,
$medium-up: $default-medium-up,
$large-up: $default-large-up,
$x-large-up: $default-x-large-up,
$xx-large-up: $default-xx-large-up,
$min-value: false,
$max-value: false
) {
$query: unquote($query);
// Human-friendly media query names :)
@if index( (s, small, small-up, mobile-up), $query) {
@media only screen {
@content;
}
}
@else if index(small-only, mobile-only) {
@media #{$small-only} {
@content;
}
}
@else if index( (m, medium, medium-up, tablet-up), $query) {
@media #{$medium-up} {
@content;
}
}
@else if index( (l, large, large-up, desktop-up), $query) {
@media #{$large-up} {
@content;
}
}
@else if index( (xl, x-large, x-large-up, large-desktop-up), $query) {
@media #{$x-large-up} {
@content;
}
}
@else if index( (xxl, xx-large, xx-large-up), $query) {
@media #{$xx-large-up} {
@content;
}
}
@else if custom == $query {
$custom-query: get-query($min-value, $max-value);
@media #{$custom-query} {
@content;
}
}
@else {
@error "Invalid media query: #{$query}";
}
}
$global-legacy-support: ie8 ie9 !default;
// This is the default html and body font-size for the base rem value.
$rem-base: 16px !default;
$line-height-base: 1.8 !default;
// REM calculation courtesy of Zurb Foundation :)
// CONVERT TO REM
@function convert-to-rem($value, $base-value: $rem-base) {
$value: strip-unit($value) / strip-unit($base-value) * 1rem;
@if ($value == 0rem) { $value: 0; } // Turn 0rem into 0
@return $value;
}
// REM CALC
@function rem-calc($values, $base-value: $rem-base) {
$max: length($values);
@if $max == 1 { @return convert-to-rem(nth($values, 1), $base-value); }
$remValues: ();
@for $i from 1 through $max {
$remValues: append($remValues, convert-to-rem(nth($values, $i), $base-value));
}
@return $remValues;
}
// Simple REM font values
// The idea is you put in pixel values (safe, familiar)
// and you get rem values (strange, mysterious)
@mixin rem-font($pixel-value, $base:$rem-base, $legacy-support: $global-legacy-support) {
@if unitless($pixel-value) {
$pixel-value: $pixel-value * 1px;
}
// $legacy-support is set as global variable
@if index($legacy-support, ie8) {
font-size: $pixel-value;
}
font-size: rem-calc($pixel-value, $base);
}
// --------------------------------------------
// Typography generator
// --------------------------------------------
// Modular scale, many thanks to Bourbon
// See: http://bourbon.io/docs/#modular-scale
// Scaling Variables
$golden: 1.618;
$minor-second: 1.067;
$major-second: 1.125;
$minor-third: 1.2;
$major-third: 1.25;
$perfect-fourth: 1.333;
$augmented-fourth: 1.414;
$perfect-fifth: 1.5;
$minor-sixth: 1.6;
$major-sixth: 1.667;
$minor-seventh: 1.778;
$major-seventh: 1.875;
$octave: 2;
$major-tenth: 2.5;
$major-eleventh: 2.667;
$major-twelfth: 3;
$double-octave: 4;
$modular-scale-ratio: $perfect-fourth !default;
$modular-scale-base: 16px !default;
@function modular-scale($increment, $value: $modular-scale-base, $ratio: $modular-scale-ratio) {
$v1: nth($value, 1);
$v2: nth($value, length($value));
$value: $v1;
// scale $v2 to just above $v1
@while $v2 > $v1 {
$v2: ($v2 / $ratio); // will be off-by-1
}
@while $v2 < $v1 {
$v2: ($v2 * $ratio); // will fix off-by-1
}
// check AFTER scaling $v2 to prevent double-counting corner-case
$double-stranded: $v2 > $v1;
@if $increment > 0 {
@for $i from 1 through $increment {
@if $double-stranded and ($v1 * $ratio) > $v2 {
$value: $v2;
$v2: ($v2 * $ratio);
} @else {
$v1: ($v1 * $ratio);
$value: $v1;
}
}
}
@if $increment < 0 {
// adjust $v2 to just below $v1
@if $double-stranded {
$v2: ($v2 / $ratio);
}
@for $i from $increment through -1 {
@if $double-stranded and ($v1 / $ratio) < $v2 {
$value: $v2;
$v2: ($v2 / $ratio);
} @else {
$v1: ($v1 / $ratio);
$value: $v1;
}
}
}
@return $value;
}
$my-base-font-size: 16px !default;
// Set the defaults
$default-scale: 0.9 !default;
$small-font-factor: 80% !default;
// Set minimum readable size
$minimum-font-size: 12px !default;
$default-base: $my-base-font-size !default;
// Desktop first approach :-/
// Smaller sizes
$medium-base: $default-base * $default-scale;
$small-base: $medium-base * $default-scale;
// Larger sizes
$x-large-base: $default-base + ( (1 - $default-scale) * $default-base );
$xx-large-base: $x-large-base + ( (1 - $default-scale) * $x-large-base );
$default-ratio: $golden !default;
$default-media-queries: (($small-base, small-up),
($medium-base, medium-up),
($default-base, large-up),
($x-large-base, x-large-up),
($xx-large-base, xx-large-up)) !default;
// Helper functions
// Helper function for calculating heading sizes
@function minor-heading($size, $base, $scale) {
$heading-size: $scale * $size;
// Set base as the smallest heading size
// Make sure the heading is larger than or equal to the base
@return max($heading-size, $base);
}
@mixin generate-typography(
$base:$default-base,
$scale:$default-scale,
$media-queries:$default-media-queries,
$ratio:$default-ratio,
$line-height-ratio:$default-ratio
) {
// Generate base font
@each $base, $query in $media-queries {
@include media($query) {
html, body {
@debug max($minimum-font-size, $base);
font-size: max($minimum-font-size, $base);
}
}
}
// Basic style defaults
body {
font-family: Helvetica, Arial, sans-serif;
}
// Set line-height to golden ratio
h1, h2, h3, h4, h5, h6, p, li, dt, dd, blockquote, td, th {
line-height: $line-height-ratio;
}
// Inline elements inherit font size from parent
a, span, strong, em, b, i, input, select, textarea, button {
font-size: inherit;
line-height: inherit;
}
small, figcaption, sup, sub {
font-size: $small-font-factor;
}
// Use the modular scale to generate our main headings
$default-heading-1: modular-scale(2, $base, $ratio);
$default-heading-2: modular-scale(1, $base, $ratio);
// Use a simple linear scale to generate minor headings
$default-heading-3: minor-heading($default-heading-2, $base, $scale);
$default-heading-4: minor-heading($default-heading-3, $base, $scale);
$default-heading-5: minor-heading($default-heading-4, $base, $scale);
$default-heading-6: minor-heading($default-heading-5, $base, $scale);
blockquote {
font-size: $default-heading-2;
}
h1 {
@include rem-font( $default-heading-1, $base );
}
h2 {
@include rem-font( $default-heading-2, $base );
}
h3 {
@include rem-font( $default-heading-3, $base );
}
h4 {
@include rem-font( $default-heading-4, $base );
}
h5 {
@include rem-font( $default-heading-5, $base );
}
h6 {
@include rem-font( $default-heading-6, $base );
}
}
// Call the mixin (example)
@include generate-typography();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment