Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
SASS/Compass Typo Toolbox: Tackling vertical rhythm.
// A tidy house, a tidy mind.
@import "compass";
@import "numbers";
@import "vertical-rhythm";
@import "math";
// =Various functions and mixins
// -----------------------------------------------
// 1. strip() - function
// 2. px() - function
// 3. is-px() - function
// 4. px-to-rem() - function
// 5. px-rem() - mixin
// =Strip unit from a given value
// -----------------------------------------------
// Takes a value with any unit (px, em, rem…),
// strips the unit and returns the value.
//
// Props: http://stackoverflow.com/a/12335841
//
// $unitvalue - number + unit (20px, 3.5em…)
@function strip( $unitvalue ) {
@return $unitvalue / ( $unitvalue * 0 + 1 );
}
// =Convert unitless to px value
// -----------------------------------------------
// $unitless - unitless pixel value
@function px( $unitless-px ) {
@return 0px + $unitless-px;
}
// =Check if value is number and has unit "px"
// -----------------------------------------------
// unit() - required compass function
// type-of() - required compass function
// $value - generic value
@function is-px( $value ) {
@if "number" == type-of( $value ) and "px" == unit( $value ) {
@return true;
}
@else {
@return false;
}
}
// =Convert px to rem value
// -----------------------------------------------
// Returns rem value for any given px value.
// If unit "px" is passed with the value, it is stripped automatically.
//
// strip() - required function
// is-px() - required function
// $rem-base - required global var
// $px - px value, optionally unitless
@function px-to-rem( $px ) {
@if is-px( $px ) {
$unitless: strip( $px );
@return 0rem + $unitless / $rem-base;
}
@else {
@return $px;
}
}
// =Generate property in px and rem
// -----------------------------------------------
// Takes a px shorthand property, optionally unitless.
// Returns a shorthand property in px and rem.
// Values with units other than px are passed without modification.
//
// is-px() - required function
// strip() - required function
// px-to-rem() - required function
// round() - required compass function
// $property - the property (padding, margin…)
// $shorthand - px values separated by spaces
@mixin px-rem( $property, $shorthand ) {
// Define dummy vars
$px: "";
$rem: "";
// Loop through shorthand
@for $i from 1 through length( $shorthand ) {
// @each does not support indizes very well,
// so we use @for and this instead.
$value: nth( $shorthand, $i );
// Keep stylesheet clean: no space before first shorthand value
$sep: " ";
@if ( $i == 1 ) {
$sep: "";
}
// Check whether value has px unit
@if is-px( $value ) {
// Strip unit if value is 0 (zero)
@if 0 == strip( $value ) {
$px: #{ $px + $sep + strip( $value ) };
$rem: #{ $rem + $sep + strip( $value ) };
}
// Calculate rem value
@else {
$px: #{ $px + $sep + round( $value ) };
$rem: #{ $rem + $sep + px-to-rem( $value ) };
}
}
// Otherwise just pass through
@else {
$px: #{ $px + $sep + $value };
$rem: #{ $rem + $sep + $value };
}
}
// Return properties
#{$property}: $px;
// No need for two identical strings
@if $px != $rem {
#{ $property }: $rem;
}
}
/* =Numbers
-----------------------------------------------
Golden Ratio calculator:
http://www.pearsonified.com/typography/
$rem-base - assumed browser default (16px)
$base-line-height - golden ratio value for 16px
$content-width - optimal content width for 16px
// The 16px default scenario
$rem-base: 16;
$base-line-height: 26;
$content-width: 685;
$title-text: 2.265 * $rem-base; // 42
$headline-text: 1.625 * $rem-base; // 26
$sub-headline-text: 1.250 * $rem-base; // 20
$featured-text: 1.125 * $rem-base; // 18
$primary-text: 1 * $rem-base; // 16
$secondary-text: 0.8125 * $rem-base; // 13
$tiny-text: 0.6875 * $rem-base; // 11
// Font weights
$font-weight-normal: normal;
$font-weight-bold: bold;
// Transitions
$speed: 0.25s;
$easing: ease-out;
*/
// The 16px default scenario
$rem-base: 16;
$base-line-height: 26;
$content-width: 685; // can be used for grids
$title-text: 2.265 * $rem-base; // 42
$headline-text: 1.625 * $rem-base; // 26
$sub-headline-text: 1.250 * $rem-base; // 20
$featured-text: 1.125 * $rem-base; // 18
$primary-text: 1 * $rem-base; // 16
$secondary-text: 0.8125 * $rem-base; // 13
$tiny-text: 0.6875 * $rem-base; // 11
// Font weights
$font-weight-normal: 400; // depending on fonts used
$font-weight-bold: 700; // can also be set to normal and bold
// Transitions
$speed: 0.25s;
$easing: ease-out;
// =Font-sizes and line-heights
// -----------------------------------------------
// Calculate line-height based upon $rem-base
@function line-height( $font-size: $rem-base ) {
@return round( $base-line-height / $font-size * 10000 ) / 10000;
}
// =Vertical Rhythm
// -----------------------------------------------
//
// Props @StuRobson
// http://alwaystwisted.com/post.php?s=2013-12-30-not-your-average-vertical-rhythm-sass-mixin
//
// $font-size - font-size, unitless px value
// $margin - margin-bottom, none or unitless px value
// $line-height - line-height, none or unitless px value
@mixin vertical-rhythm( $font-size, $margin: false, $line-height: $base-line-height ) {
// Font-size in rem with fallback in px
font-size: px( $font-size );
font-size: px-to-rem( px( $font-size ) );
// Line-height
// $line-height specified
@if $line-height != $base-line-height and $line-height != 1 {
line-height: round( $line-height / $font-size * 10000 ) / 10000;
}
// $line-height: 1
@else if $line-height == 1 {
line-height: 1;
}
// no $line-height specified
@else {
line-height: line-height( $font-size );
}
// Margin-bottom
// zero margin explicitely
@if $margin == 0 {
margin-bottom: 0;
}
// margin specified
@else if $margin != false and $margin != 0 {
margin-bottom: 0px + $margin;
margin-bottom: px-to-rem( px( $margin ) );
}
// no margin specified
@else {
// silence
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment