Skip to content

Instantly share code, notes, and snippets.

@dinocarl
Last active June 27, 2019 19:05
Show Gist options
  • Save dinocarl/c903a5ad01e95ace41fa6e7d55a0775e to your computer and use it in GitHub Desktop.
Save dinocarl/c903a5ad01e95ace41fa6e7d55a0775e to your computer and use it in GitHub Desktop.
// https://codepen.io/anon/pen/LgJPmv
// https://codepen.io/anon/pen/qJMaER
// https://codepen.io/anon/pen/vQNxaN
// https://codepen.io/anon/pen/mQrbQV
// https://codepen.io/anon/pen/wLPxOV
// Functions
// convenience type-checking functions
@function is_null( $val ) { @return type-of( $val ) == 'null'; }
@function is_map( $val ) { @return type-of( $val ) == map; }
// inverses
@function isnt_null( $val ) { @return not is_null( $val ); }
@function isnt_map( $val ) { @return not is_map( $val ); }
// allows for getting at nested attributes in a Sass map
// ensures a null return for any unrecognized paths
// $colors: (header:(one: #333, two: #444), footer: #666);
// path(('header', 'two'), $colors); => #444
@function path( $keys, $map ) {
@each $key in $keys {
@if isnt_map( $map ) {
$map: ( _mt_: null );
}
$map: map-get( $map, $key );
}
@return $map;
}
// accepts a function name and a list.
// outputs a new list where each member has had the function run against it
@function map( $fn, $list ) {
$accumulated: ();
@for $i from 1 through length( $list ) {
$accumulated: append( $accumulated, call( $fn, nth( $list, $i ) ), comma );
}
@return $accumulated;
}
@function single-column-calc( $num-cols, $gutter ) {
@return ( 100 - ( $gutter * ( $num-cols - 1 ) ) ) / $num-cols;
}
@function column-width-calc( $span, $num-cols, $gutter ) {
$single-column: single-column-calc( $num-cols, $gutter );
@return $single-column + ( ( $single-column + $gutter ) * ( $span - 1 ) );
}
@function offset-width-calcc( $span, $num-cols, $gutter ) {
$single-column: single-column-calc( $num-cols, $gutter );
@return ( $single-column + $gutter ) * $span;
}
@function single-col-px($gutter-width, $total-width, $total-span) {
@return ( $total-width - ( ( $total-span - 1 ) * $gutter-width ) ) / $total-span;
};
@function span-width-calc( $span, $gutter-width, $total-width, $total-span ) {
$single-col: single-col-px( $gutter-width, $total-width, $total-span );
$col-margin-ratio: $single-col / $gutter-width;
@return ( $span * ( $gutter-width * $col-margin-ratio ) ) + ( ( $span - 1 ) * $gutter-width );
}
@function offset-width-calc( $span, $gutter-width, $total-width, $total-span ) {
$single-col: single-col-px( $gutter-width, $total-width, $total-span );
$col-margin-ratio: $single-col / $gutter-width;
@return ( $span * ( $gutter-width * $col-margin-ratio ) ) + ( $span * $gutter-width );
}
@function create-col-selector( $props ) {
@return unquote( '.col-#{path(('size'), $props)}-#{path(('span'), $props)}' );
}
@function create-offset-selector( $props ) {
@return unquote( '.col-#{path(('size'), $props)}-offset-#{path(('span'), $props)}' );
}
@function create-order-selector( $props ) {
@return unquote( '.ord-#{path(('size'), $props)}-#{path(('span'), $props)}' );
}
// Data
$column-data: (
cols: 12,
widths: (
xs: (
max: 480,
gutter: 8
),
sm: (
max: 768,
gutter: 12
),
md: (
max: 992,
gutter: 12
),
lg: (
max: 1200,
gutter: 14
),
),
);
// Mixins
@mixin col-media-query( $width, $idx ) {
@if $idx > 1 {
@media only screen and (min-width: #{$width + 1}px) {
@content;
}
}
@else {
@content;
}
}
@mixin generate-columns( $props ) {
$widths: path( ('widths'), $props );
$num-cols: path( ('cols'), $props );
$custom-cols: $num-cols - 1;
$width-types: map-keys( $widths );
// Create mobile-first variations
// of the larger sized columns.
// Include the xs last variation b/c
// it will always be 100% width
$classnames: create-col-selector( (
size: 'xs',
span: $num-cols
) );
@for $i from 2 through length( $width-types ) {
$item: nth( $width-types, $i );
@for $s from 1 through $num-cols {
$classnames: append( $classnames, create-col-selector( (
size: $item,
span: $s
) ), comma );
}
}
#{$classnames} {
width: 100%;
}
// Generate permutations
$curr-items: ();
@for $i from 1 through length( $width-types ) {
$item: nth( $width-types, $i );
$curr-item-data: (
size: $item
);
$curr-width: path( ( $item, 'max' ), $widths );
$curr-gutter: path( ( $item, 'gutter' ), $widths );
$curr-gutter-size: ( $curr-gutter / $curr-width ) * 100%;
$curr-items: append( $curr-items, $curr-item-data );
// Encase the permutations inside an optional media query
$order-data: ();
@include col-media-query( $curr-width, $i ) {
@for $p from 1 through length( $curr-items ) {
$curr-size: path( ('size'), nth( $curr-items, $p ) );
// Create an Offset 0
#{create-offset-selector((
size: $curr-size,
span: 0
))} {
margin-left: 0;
}
@for $span from 1 through $custom-cols {
$curr-permutation-data: (
size: $curr-size,
span: $span
);
$curr-px-width: span-width-calc( $span, $curr-gutter, $curr-width, $num-cols );
$curr-permutation-name: create-col-selector( $curr-permutation-data );
$curr-permutation-offset: create-offset-selector( $curr-permutation-data );
$curr-permutation-order: create-order-selector( (
size: $item,
span: $span
) );
$order-data: map-merge( $order-data, (#{$curr-permutation-order}: $span) );
// Output the class
#{$curr-permutation-name} {
// width: column-width-calc( $span, $num-cols, $curr-gutter-size );
width: percentage( $curr-px-width / $curr-width );
}
// Output the offset
#{$curr-permutation-offset} {
margin-left: percentage( offset-width-calc( $span, $curr-gutter, $curr-width, $num-cols ) / $curr-width );
}
// Output the nests
@for $nest from 1 through $span {
$nest-selector: create-col-selector( (
size: 'xs',
span: $nest
) );
#{$curr-permutation-name} #{$nest-selector} {
width: percentage( span-width-calc( $nest, $curr-gutter, $curr-px-width, $span ) / $curr-px-width );
}
}
}
}
@each $selector, $order in $order-data {
#{ $selector } { order: $order; }
}
}
}
}
// output CSS
body {
margin: 0;
padding: 0;
font-family: monospace;
line-height: 1.2
}
.bgo {
background-color: orange;
}
.bgs {
background-color: silver;
}
.row {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
& > * {
box-sizing: border-box;
margin-top: .5em;
}
}
@include generate-columns($column-data);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment