Skip to content

Instantly share code, notes, and snippets.

@kjbrum
Last active October 23, 2021 11:38
Show Gist options
  • Save kjbrum/c13ac9ba177973f75bb161c94fd50047 to your computer and use it in GitHub Desktop.
Save kjbrum/c13ac9ba177973f75bb161c94fd50047 to your computer and use it in GitHub Desktop.
Helper files for writing Sass.
// Functions
// ------------------------
// Strip the units from a string
@function strip-units($value) {
@return $value / ($value * 0 + 1);
}
// Calculate px from a rem/em value
@function px-calc($rem, $base-val: 16) {
@if unit($rem) == px {
@return $rem;
}
@if not unitless($rem) {
$rem: strip-units($rem);
}
@if not unitless($base-val) {
$base-val: strip-units($base-val);
}
@return ($rem * $base-val) * 1px;
}
// Calculate rems from a px value
@function rem-calc($px, $base-val: 16) {
@if unit($px) == rem {
@return $px;
}
@if not unitless($px) {
$px: strip-units($px);
}
@if not unitless($base-val) {
$base-val: strip-units($base-val);
}
@return ($px / $base-val) * 1rem;
}
// Calculate ems from a px value
@function em-calc($px, $base-val: 16) {
@if unit($px) == em {
@return $px;
}
@if not unitless($px) {
$px: strip-units($px);
}
@if not unitless($base-val) {
$base-val: strip-units($base-val);
}
@return ($px / $base-val) * 1em;
}
// Mix white with another color
@function tint($color, $percent: 15%){
@return mix(white, $color, $percent);
}
// Mix black with another color
@function shade($color, $percent: 15%){
@return mix(black, $color, $percent);
}
// Create a random color
@function random-rgba($min: 0, $max: 255, $alpha: 1, $red: null, $green: null, $blue: null) {
@if $min < 0 {
$min: -1;
} @else {
$min: $min - 1;
}
@if $max > 255 {
$max: 256;
} @else {
$max: $max + 1;
}
$range: $max - $min;
@if not $red { $red: random($range) + $min; }
@if not $green { $green: random($range) + $min; }
@if not $blue { $blue: random($range) + $min; }
@return rgba($red, $green, $blue, $alpha);
}
// Generate a random number with a minimum/maximum
@function minmax($min: 0, $max: 100) {
$rand: random();
$number: $min + floor($rand * (($max - $min) + 1));
@return $number;
}
// Replace a string
@function str-replace($string, $search, $replace: '') {
$index: str-index($string, $search);
@if $index {
@return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
}
@return $string;
}
// Check if a list contains something
@function list-contains($list, $var) {
@if index($list, $var) {
@return true;
} @else {
@return false;
}
}
// Convert SVG to URL
// Source: https://codepen.io/jakob-e/pen/doMoML
@function svg-url($svg) {
$encoded: '';
$slice: 2000;
$index: 0;
$loops: ceil(str-length($svg) / $slice);
@for $i from 1 through $loops {
$chunk: str-slice($svg, $index, $index + $slice - 1);
$chunk: str-replace($chunk, '"', "'");
$chunk: str-replace($chunk, '<', '%3C');
$chunk: str-replace($chunk, '>', '%3E');
$chunk: str-replace($chunk, '&', '%26');
$chunk: str-replace($chunk, '#', '%23');
// Keep size and compile time down, only add on documented fail
// $chunk: str-replace($chunk, '|', '%7C');
// $chunk: str-replace($chunk, '[', '%5B');
// $chunk: str-replace($chunk, ']', '%5D');
// $chunk: str-replace($chunk, '^', '%5E');
// $chunk: str-replace($chunk, '`', '%60');
// $chunk: str-replace($chunk, ';', '%3B');
// $chunk: str-replace($chunk, '?', '%3F');
// $chunk: str-replace($chunk, ':', '%3A');
// $chunk: str-replace($chunk, '@', '%40');
// $chunk: str-replace($chunk, '=', '%3D');
$encoded: #{$encoded}#{$chunk};
$index: $index + $slice;
}
@return url("data:image/svg+xml;charset=utf8,#{$encoded}");
}
// Retrieve color from $colors map
@function color($color-name, $color-variant: null) {
// Check if color variant
@if ($color-variant != null) {
@return map-get(map-get($colors, $color-name), $color-variant);
} @else {
@return map-get($colors, $color-name);
}
}
// Retrieve breakpoint from $breakpoints map
@function breakpoint($breakpoint-name, $breakpoint-variant: null) {
// Check if breakpoint variant
@if ($breakpoint-variant != null) {
@return map-get(map-get($breakpoints, $breakpoint-name), $breakpoint-variant);
} @else {
@return map-get($breakpoints, $breakpoint-name);
}
}
// Check if a feature is enabled
@function feature($feature: null) {
@if ($feature == null) {
@warn "You must supply a value to the feature function.";
}
@return list-contains($enable-features, $feature);
}
// Colors loop helper
@function colors-loop-helper($colors: null) {
$colors-map: ();
@each $color, $types in $colors {
@each $type, $hex in $types {
$unique-selector: #{$color}-#{$type};
@if $type == normal {
$unique-selector: #{$color};
}
@if $color == other {
$unique-selector: #{$type};
}
$colors-map: map-merge($colors-map, (#{$unique-selector}: #{$hex}))
}
}
@return $colors-map;
}
// Mixins
// ------------------------
// Breakpoints
// ------------------------
@mixin bp($break, $viewport1: null, $isHeight: null) {
// Preset breakpoint
@if not $viewport1 {
@if map-has-key($bp-media-queries, $break) {
@media only screen and #{map-get($bp-media-queries, $break)} { @content; }
}
@else {
@warn "Couldn't find a breakpoint named #{$break}.";
}
}
@else {
// min-width breakpoint
@if $break == min {
@media screen and (min-width: $viewport1) { @content; }
}
// max-width breakpoint
@else if $break == max {
@media screen and (max-width: $viewport1) { @content; }
}
// min-height breakpoint
@else if $break == min-height {
@media screen and (min-height: $viewport1) { @content; }
}
// max-height breakpoint
@else if $break == max-height {
@media screen and (max-height: $viewport1) { @content; }
}
// min-height & max-height breakpoint
@else if $isHeight {
@media screen and (min-height: $break) and (max-height: $viewport1) { @content; }
}
// min-width & max-width breakpoint
@else {
@media screen and (min-width: $break) and (max-width: $viewport1) { @content; }
}
}
}
// Single side border radius
@mixin border-top-radius($radius: 3px) {
border-top-right-radius: $radius;
border-top-left-radius: $radius;
}
@mixin border-right-radius($radius: 3px) {
border-top-right-radius: $radius;
border-bottom-right-radius: $radius;
}
@mixin border-bottom-radius($radius: 3px) {
border-bottom-right-radius: $radius;
border-bottom-left-radius: $radius;
}
@mixin border-left-radius($radius: 3px) {
border-top-left-radius: $radius;
border-bottom-left-radius: $radius;
}
// Responsive Typography
// "min-font-size-px" + ("max-font-size" - "min-font-size") * (100vw - "min-screen-size-px") / ("max-screen-size" - "min-screen-size")
@mixin r-font-size($min-font, $max-font, $min-screen: $min-width, $max-screen: $max-width) {
$responsive-calc: calc(#{px-calc($min-font)} + (#{strip-units(px-calc($max-font))} - #{strip-units(px-calc($min-font))}) * (100vw - #{px-calc($min-screen)}) / (#{strip-units(px-calc($max-screen))} - #{strip-units(px-calc($min-screen))}));
font-size: rem-calc($min-font);
// Min width
@include bp(min, rem-calc($min-screen)) {
font-size: $responsive-calc;
}
// Halfway point
@include bp(min, ((rem-calc($max-screen) + rem-calc($min-screen)) / 2)) {
font-size: (rem-calc($max-font) + rem-calc($min-font)) / 2;
font-size: $responsive-calc;
}
// Max width
@include bp(min, rem-calc($max-screen)) {
font-size: rem-calc($max-font);
}
}
// Responsive property
@mixin r-property($property, $min-property, $mid-property, $max-property, $min-screen: $min-width, $max-screen: $max-width) {
// Min width
#{$property}: $min-property;
// Mid width
@include bp(min, rem-calc($min-screen)) {
#{$property}: $mid-property;
}
// Max width
@include bp(min, rem-calc($max-screen)) {
#{$property}: $max-property;
}
}
// Placeholder styles
@mixin placeholder {
&::placeholder {
@content;
}
}
// Sizing
@mixin size($width, $height: $width) {
width: $width;
height: $height;
}
// Normal & hover state
@mixin hoverer($property, $normal, $hovered) {
#{$property}: $normal;
&:hover {
#{$property}: $hovered;
}
}
// Advanced positioning
@mixin position($type, $top: null, $right: null, $bottom: null, $left: null) {
position: $type;
$allowed_types: absolute relative fixed;
@if not index($allowed_types, $type) {
@warn "Unknown position: #{$type}.";
}
@each $data in top $top, right $right, bottom $bottom, left $left {
#{nth($data, 1)}: nth($data, 2);
}
}
@mixin absolute($top: null, $right: null, $bottom: null, $left: null) {
@include position(absolute, $top, $right, $bottom, $left);
}
@mixin relative($top: null, $right: null, $bottom: null, $left: null) {
@include position(relative, $top, $right, $bottom, $left);
}
@mixin fixed($top: null, $right: null, $bottom: null, $left: null) {
@include position(fixed, $top, $right, $bottom, $left);
}
// Easily set an element's "trbl" values
@mixin trbl($top: null, $right: null, $bottom: null, $left: null) {
@each $data in top $top, right $right, bottom $bottom, left $left {
#{nth($data, 1)}: nth($data, 2);
}
}
@mixin top-left {
@include trbl(0,null,null,0);
}
@mixin top-right {
@include trbl(0,0);
}
@mixin bottom-left {
@include trbl(null,null,0,0);
}
@mixin bottom-right {
@include trbl(null,0,0,null);
}
// Helper Mixins
// ------------------------
// Clearfix
@mixin clearfix {
*zoom: 1;
&:before,
&:after {
content: " ";
display: table;
flex-basis: 0;
}
&:after {
clear: both;
}
}
// Center an element vertically and horizontally
@mixin centerer {
@include absolute(50%, null, null, 50%);
@include translate(-50%, -50%);
}
// Center an element vertically
@mixin vert-centerer {
@include relative(50%);
@include translateY(-50%);
}
// Cover everything
@mixin coverer {
@include absolute(0, 0, 0, 0);
}
// Center a block level element
@mixin center-block {
display: block;
margin-left: auto;
margin-right: auto;
}
// Clean an element
@mixin clean {
margin: 0;
padding: 0;
}
// Add a box fade (image fade)
@mixin box-fade($side: both, $color: #000000, $size: 100px) {
position: relative;
z-index: -1;
> * {
position: relative;
z-index: 1;
}
$selector: '&:before, &:after';
$top: 0;
@if $side == top {
$selector: '&:before';
} @else if $side == bottom {
$selector: '&:after';
$top: 100%;
}
#{$selector} {
content: '';
position: absolute;
top: $top;
left: 0;
width: 100%;
height: 0;
box-shadow: 0 0 $size $size*0.75 #{$color};
}
@if $side == both {
&:after {
top: 100%;
}
}
}
// Full background
@mixin full-bg($position: 'center center', $size: 'cover', $repeat: 'no-repeat') {
background-size: #{$size};
background-position: #{$position};
background-repeat: #{$repeat};
}
// Preload images using CSS
// Usage:
// // Add images to a list
// $images: ();
// @for $i from 1 through 10 {
// $image: '../img/example-#{$i}.jpg';
// $images: append($images, $image);
// }
// @include preload($images);
// // Load all the images (this can only be called once)
// @include preload;
@mixin preload($preload: run) {
@if not variable-exists(_preload-image-list) {
$_preload-image-list: ()!global;
}
@if not variable-exists(_preload-image-urls) {
$_preload-image-urls: ()!global;
}
@if not variable-exists(_preload-images-loaded) {
$_preload-images-loaded: false!global;
}
@if $preload == run and not $_preload-images-loaded {
$_preload-images-loaded: true!global;
html:after {
content: '';
display: none;
background-image: $_preload-image-urls;
}
} @else {
$_preload-image-list: join($preload, $_preload-image-list)!global;
$image-urls: ();
@if length($_preload-image-list) > 0 {
@for $i from 1 through length($_preload-image-list) {
$image-urls: join(url(#{nth($_preload-image-list,$i)}), $image-urls);
}
$result: ();
@each $item in $image-urls {
@if not index($result, $item) {
$result: append($result, $item, comma);
}
}
$_preload-image-urls: $result!global;
}
}
}
// Skew a section and unskew it's contents
@mixin skew-section($deg) {
transform: skewY($deg);
.container {
transform: skewY(-($deg));
}
}
// Debugging
// ------------------------
// Breakpoints
@mixin debug-breakpoints {
&:before {
@each $breakpoint, $query in $bp-media-queries {
@if str-index($breakpoint, '-') == null {
@include bp(#{$breakpoint}) {
content: '#{$breakpoint}: #{map-get(map-get($breakpoints, $breakpoint), min)} to #{map-get(map-get($breakpoints, $breakpoint), max)}';
@include fixed(null, null, 0, 0);
padding: 0.5rem 1rem;
background-color: $white;
border-top: 1px solid $black;
border-right: 1px solid $black;
font-family: $font;
font-size: 12px;
color: $black;
text-align: center;
}
}
}
}
}
// Variables
// ------------------------
// Features
// ------------------------
$enable-features: (
// ----- Grid -----
// grid-flexbox
// grid-offset
// grid-push-pull
// grid-block-grid
// grid-5-columns
// grid-halfs
// grid-first-last
// ----- Misc -----
// show-hide-helpers
// split-lists
// text-colors
// bg-colors
// scroll-animations
// debugging
);
// Colors
// ------------------------
$primary: #d9531e;
$secondary: #f78e1e;
$colors: (
'primary': (
'ultralight': tint($primary, 25%),
'light': tint($primary, 10%),
'normal': $primary,
'dark': shade($primary, 10%),
'ultradark': shade($primary, 25%)
),
'secondary': (
'ultralight': tint($secondary, 25%),
'light': tint($secondary, 10%),
'normal': $secondary,
'dark': shade($secondary, 10%),
'ultradark': shade($secondary, 25%)
),
'gray': (
'ultralight': #eeeeee,
'light': #cccccc,
'normal': #9b9b9b,
'dark': #666666,
'ultradark': #444444
),
'other': (
'white': #ffffff,
'black': #222222,
'green': #92f0a1,
'yellow': #f0e591,
'red': #ff676b
)
);
// Primary
$primary-ultralight: color('primary', 'ultralight');
$primary-light: color('primary', 'light');
$primary-dark: color('primary', 'dark');
$primary-ultradark: color('primary', 'ultradark');
// Secondary
$secondary-ultralight: color('secondary', 'ultralight');
$secondary-light: color('secondary', 'light');
$secondary-dark: color('secondary', 'dark');
$secondary-ultradark: color('secondary', 'ultradark');
// Grays
$gray-ultralight: color('gray', 'ultralight');
$gray-light: color('gray', 'light');
$gray: color('gray', 'normal');
$gray-dark: color('gray', 'dark');
$gray-ultradark: color('gray', 'ultradark');
// Misc
$white: color('other', 'white');
$black: color('other', 'black');
$green: color('other', 'green');
$yellow: color('other', 'yellow');
$red: color('other', 'red');
// Colors loop helper
$colors-loop-helper: colors-loop-helper($colors);
// Fonts
// ------------------------
// @import url(https://fonts.googleapis.com/css?family=Open+Sans:300,400,700|Roboto+Slab:300,400,700);
// Primary font
$helvetica: 'Helvetica Neue', Helvetica, Arial, sans-serif;
$open-sans: 'Open Sans', $helvetica;
$font: $open-sans;
// Secondary font
$georgia: Georgia, Times, serif;
$roboto: 'Roboto Slab', $georgia;
$font-secondary: $roboto;
// Monospaced
$consolas: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
$font-mono: $consolas;
// Font weights
$font-weight-normal: 400;
$font-weight-bold: 700;
// Layout/Grid
// ------------------------
$min-width: rem-calc(320);
$max-width: rem-calc(1200);
$num-columns: 12;
$grid-width: $max-width;
$grid-gutter: 1rem;
$grid-container-prefix: 'container';
$grid-row-prefix: 'row';
$grid-item-prefix: 'col';
// Breakpoint map
$breakpoints: (
xxs: (
min: rem-calc(0),
max: $min-width
),
xs: (
min: $min-width + rem-calc(1),
max: rem-calc(480)
),
s: (
min: rem-calc(481),
max: rem-calc(640)
),
m: (
min: rem-calc(641),
max: rem-calc(1024)
),
l: (
min: rem-calc(1025),
max: $max-width
),
xl: (
min: $max-width + rem-calc(1),
max: rem-calc(1920)
)
);
// Breakpoint variables
$bp-xxs: breakpoint(xxs, max);
$bp-xxs-min: breakpoint(xxs, min);
$bp-xxs-max: breakpoint(xxs, max);
$bp-xs: breakpoint(xs, max);
$bp-xs-min: breakpoint(xs, min);
$bp-xs-max: breakpoint(xs, max);
$bp-s: breakpoint(s, max);
$bp-s-min: breakpoint(s, min);
$bp-s-max: breakpoint(s, max);
$bp-m: breakpoint(m, max);
$bp-m-min: breakpoint(m, min);
$bp-m-max: breakpoint(m, max);
$bp-l: breakpoint(l, max);
$bp-l-min: breakpoint(l, min);
$bp-l-max: breakpoint(l, max);
$bp-xl: breakpoint(xl, max);
$bp-xl-min: breakpoint(xl, min);
$bp-xl-max: breakpoint(xl, max);
// Media Queries
$bp-media-queries: (
xxs-max: "(max-width: #{$bp-xxs-max})",
xxs-only: "(min-width: #{$bp-xxs-min}) and (max-width: #{$bp-xxs-max})",
xxs: "(min-width: #{$bp-xxs-min})",
xs-max: "(max-width: #{$bp-xs-max})",
xs-only: "(min-width: #{$bp-xs-min}) and (max-width: #{$bp-xs-max})",
xs: "(min-width: #{$bp-xs-min})",
s-max: "(max-width: #{$bp-s-max})",
s-only: "(min-width: #{$bp-s-min}) and (max-width: #{$bp-s-max})",
s: "(min-width: #{$bp-s-min})",
m-max: "(max-width: #{$bp-m-max})",
m-only: "(min-width: #{$bp-m-min}) and (max-width: #{$bp-m-max})",
m: "(min-width: #{$bp-m-min})",
l-max: "(max-width: #{$bp-l-max})",
l-only: "(min-width: #{$bp-l-min}) and (max-width: #{$bp-l-max})",
l: "(min-width: #{$bp-l-min})",
xl-max: "(max-width: #{$bp-xl-max})",
xl-only: "(min-width: #{$bp-xl-min}) and (max-width: #{$bp-xl-max})",
xl: "(min-width: #{$bp-xl-min})",
);
// Cubic-bezier timing functions
// Credit: http://github.com/jaukia/easie
// ------------------------
// EASE IN
$ease-in-quad: cubic-bezier(0.550, 0.085, 0.680, 0.530);
$ease-in-cubic: cubic-bezier(0.550, 0.055, 0.675, 0.190);
$ease-in-quart: cubic-bezier(0.895, 0.030, 0.685, 0.220);
$ease-in-quint: cubic-bezier(0.755, 0.050, 0.855, 0.060);
$ease-in-sine: cubic-bezier(0.470, 0.000, 0.745, 0.715);
$ease-in-expo: cubic-bezier(0.950, 0.050, 0.795, 0.035);
$ease-in-circ: cubic-bezier(0.600, 0.040, 0.980, 0.335);
$ease-in-back: cubic-bezier(0.600, -0.280, 0.735, 0.045);
// EASE OUT
$ease-out-quad: cubic-bezier(0.250, 0.460, 0.450, 0.940);
$ease-out-cubic: cubic-bezier(0.215, 0.610, 0.355, 1.000);
$ease-out-quart: cubic-bezier(0.165, 0.840, 0.440, 1.000);
$ease-out-quint: cubic-bezier(0.230, 1.000, 0.320, 1.000);
$ease-out-sine: cubic-bezier(0.390, 0.575, 0.565, 1.000);
$ease-out-expo: cubic-bezier(0.190, 1.000, 0.220, 1.000);
$ease-out-circ: cubic-bezier(0.075, 0.820, 0.165, 1.000);
$ease-out-back: cubic-bezier(0.175, 0.885, 0.320, 1.275);
// EASE IN OUT
$ease-in-out-quad: cubic-bezier(0.455, 0.030, 0.515, 0.955);
$ease-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1.000);
$ease-in-out-quart: cubic-bezier(0.770, 0.000, 0.175, 1.000);
$ease-in-out-quint: cubic-bezier(0.860, 0.000, 0.070, 1.000);
$ease-in-out-sine: cubic-bezier(0.445, 0.050, 0.550, 0.950);
$ease-in-out-expo: cubic-bezier(1.000, 0.000, 0.000, 1.000);
$ease-in-out-circ: cubic-bezier(0.785, 0.135, 0.150, 0.860);
$ease-in-out-back: cubic-bezier(0.680, -0.550, 0.265, 1.550);
// Misc
// ------------------------
$chevron-left: "&#x3008;";
$chevron-right: "&#x3009;";
$close: "&#x2715;";
$quote-left: "\201c";
$quote-right: "\201d";
# Sass Helpers
- Variables
- Functions
- Mixins
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment