Upgrade to Susy 3 (#42)

Most of Susy's mixins have been deprecated, `@include container()`, `@include full()`, `@include span()`, `@include prefix()`, `@include suffix()`, `@include gallery()`, etc replace with new functions.

Fixes #21
This commit is contained in:
Michael Rose 2018-01-05 14:25:42 -05:00 committed by GitHub
parent eeebb7e4ff
commit 628629d268
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
83 changed files with 2557 additions and 4139 deletions

View File

@ -1,16 +0,0 @@
---
engines:
duplication:
enabled: false
eslint:
enabled: false
fixme:
enabled: false
scss-lint:
enabled: true
ratings:
paths:
- "**.js"
- "**.rb"
- "_sass/**/*.scss"
exclude_paths: []

View File

@ -2,7 +2,6 @@
[![Gem](https://img.shields.io/gem/v/jekyll-theme-basically-basic.svg?style=flat-square)](https://rubygems.org/gems/jekyll-theme-basically-basic)
[![license](https://img.shields.io/github/license/mmistakes/jekyll-theme-basically-basic.svg?style=flat-square)](LICENSE.md)
[![Code Climate](https://img.shields.io/codeclimate/github/mmistakes/jekyll-theme-basically-basic.svg?style=flat-square)](https://codeclimate.com/github/mmistakes/jekyll-theme-basically-basic)
Basically Basic is a [Jekyll theme](https://jekyllrb.com/docs/themes/) meant as
a substitute for the default --- [Minima](https://github.com/jekyll/minima).

View File

@ -5,14 +5,12 @@
* https://github.com/mmistakes/jekyll-theme-basically-basic/blob/master/LICENSE.md
*/
/* Mixins and functions */
@import "basically-basic/vendor/susy";
@import "basically-basic/vendor/breakpoint";
@include breakpoint-set("to ems", true);
@import "basically-basic/mixins";
/* Variables */
@import "basically-basic/functions";
@import "basically-basic/variables";
@import "basically-basic/mixins";
@import "basically-basic/vendor/breakpoint/breakpoint";
@include breakpoint-set("to ems", true);
@import "basically-basic/vendor/susy/susy";
/* Core CSS */
@import "basically-basic/reset";

View File

@ -36,7 +36,6 @@
}
.byline-item {
&:not(:first-child) {
margin-left: 1.5rem;
}
@ -53,7 +52,6 @@
========================================================================== */
.entries {
.entry-title {
word-wrap: break-word; /* break long words that could overflow */
@ -64,7 +62,7 @@
.entry-excerpt {
@include breakpoint($medium) {
@include span(11 of 16);
width: span(11 of 16);
}
/* normalize font sizes */
@ -80,7 +78,7 @@
.entry-content {
@include breakpoint($medium) {
@include span(11 of 16);
width: span(11 of 16);
}
/* remove space after last child element */
@ -91,8 +89,9 @@
.entry-meta {
@include breakpoint($medium) {
@include span(5 of 16 last);
@include prefix(1 of 16);
float: right;
width: span(5 of 16 last);
padding-left: gutter(1 of 16);
}
ul {
@ -114,7 +113,6 @@
}
> .summary {
> p:first-child {
font-size: 1.125em;
line-height: 1.625;
@ -123,7 +121,6 @@
}
.entry-content {
> p:first-child {
font-size: 1.125em;
line-height: 1.625;

View File

@ -0,0 +1,2 @@
@import "functions/color";
@import "functions/fluid-type";

View File

@ -23,7 +23,6 @@
.intro,
main {
> .inner {
padding: 0 0.5rem;
@ -50,9 +49,10 @@ main {
}
main {
section {
@include container;
margin-left: auto;
margin-right: auto;
max-width: 100%;
}
}
@ -66,9 +66,7 @@ main {
.layout--post,
.layout--page {
.entry-content {
@include breakpoint($large) {
width: span(14 of 16);
}
@ -76,7 +74,6 @@ main {
}
.layout--about {
.entry-wrap {
display: -ms-flexbox;
display: flex;
@ -90,7 +87,6 @@ main {
}
.entry-content {
@include breakpoint($medium) {
-ms-flex: 1;
flex: 1;
@ -118,14 +114,11 @@ main {
}
.layout--cv {
.entries {
.entry-header {
@include breakpoint($medium) {
@include span(5 of 16);
@include suffix(1 of 16);
width: span(5 of 16);
padding-right: gutter(1 of 16);
/* remove space after last child element */
> *:last-child {
@ -136,13 +129,13 @@ main {
.entry-content {
@include breakpoint($medium) {
@include span(11 of 16 last);
float: right;
width: span(11 of 16);
}
}
}
.entry {
a {
color: $accent-color;
}
@ -179,7 +172,6 @@ main {
}
.taxonomy {
+ .taxonomy {
margin-top: 0.5rem;
}

View File

@ -1,7 +1,5 @@
@import 'mixins/color';
@import 'mixins/clearfix';
@import 'mixins/fluid-type';
@import 'mixins/float';
@import 'mixins/image';
@import 'mixins/lists';
@import 'mixins/text-truncate';
@import "mixins/clearfix";
@import "mixins/float";
@import "mixins/image";
@import "mixins/lists";
@import "mixins/text-truncate";

View File

@ -19,11 +19,15 @@ $max-font-size: 18px !default;
$modular-scale-1: 1.067 !default; /* small */
$modular-scale-2: 1.296 !default; /* large */
/* Heading 1 */
$h1-min: $modular-scale-1 * $modular-scale-1 * $modular-scale-1 * $modular-scale-1 * $base-font-size !default;
$h1-max: $modular-scale-2 * $modular-scale-2 * $modular-scale-2 * $modular-scale-2 * $base-font-size !default;
$h1-min: $modular-scale-1 * $modular-scale-1 * $modular-scale-1 *
$modular-scale-1 * $base-font-size !default;
$h1-max: $modular-scale-2 * $modular-scale-2 * $modular-scale-2 *
$modular-scale-2 * $base-font-size !default;
/* Heading 2 */
$h2-min: $modular-scale-1 * $modular-scale-1 * $modular-scale-1 * $base-font-size !default;
$h2-max: $modular-scale-2 * $modular-scale-2 * $modular-scale-2 * $base-font-size !default;
$h2-min: $modular-scale-1 * $modular-scale-1 * $modular-scale-1 *
$base-font-size !default;
$h2-max: $modular-scale-2 * $modular-scale-2 * $modular-scale-2 *
$base-font-size !default;
/* Heading 3 */
$h3-min: $modular-scale-1 * $modular-scale-1 * $base-font-size !default;
$h3-max: $modular-scale-2 * $modular-scale-2 * $base-font-size !default;
@ -41,7 +45,8 @@ $h6-max: ($base-font-size / $modular-scale-2) !default;
$base-font-family: "Fira Sans", sans-serif !default;
/* Other font families */
$headline-font-family: $base-font-family !default;
$monospace-font-family: Menlo, Consolas, Monaco, "Courier New", Courier, monospace !default;
$monospace-font-family: Menlo, Consolas, Monaco, "Courier New", Courier,
monospace !default;
/* Colors */
$base-color: #393e46 !default;
@ -79,6 +84,3 @@ $navicon-content-bg: $text-color !default;
/* Site image */
$site-image-width: 50px !default;
$site-image-height: 50px !default;
/* Susy grid settings */
$susy: (columns: 16, gutters: 0, math: fluid, output: float) !default;

View File

@ -1,4 +0,0 @@
// Su
// ==
@import 'susy/su';

View File

@ -1,4 +0,0 @@
// Susy
// ====
@import 'susy/language/susy';

View File

@ -1,4 +0,0 @@
// Susy
// ====
@import 'susy/language/susyone';

View File

@ -23,15 +23,15 @@ $breakpoint: () !default;
//////////////////////////////
// Imports
//////////////////////////////
@import "breakpoint/settings";
@import 'breakpoint/context';
@import 'breakpoint/helpers';
@import 'breakpoint/parsers';
@import 'breakpoint/no-query';
@import "settings";
@import "context";
@import "helpers";
@import "parsers";
@import "no-query";
@import 'breakpoint/respond-to';
@import "respond-to";
@import "breakpoint/legacy-settings";
@import "legacy-settings";
//////////////////////////////
// Breakpoint Mixin

View File

@ -1,7 +1,4 @@
// Su
// ==
@import "su/utilities";
@import "su/settings";
@import "su/validation";
@import "su/grid";
@import 'susy/su';

View File

@ -0,0 +1,13 @@
// Susy (Prefixed)
// ===============
$susy-version: 3;
@import 'susy/utilities';
@import 'susy/su-validate';
@import 'susy/su-math';
@import 'susy/settings';
@import 'susy/normalize';
@import 'susy/parse';
@import 'susy/syntax-helpers';
@import 'susy/api';

View File

@ -0,0 +1,5 @@
// Susy (Un-Prefixed)
// ==================
@import 'susy-prefix';
@import 'susy/unprefix';

View File

@ -1,24 +0,0 @@
// Susy Next Syntax
// ================
$susy-version: 2.1;
@import "../su";
@import "../output/float";
@import "susy/settings";
@import "susy/validation";
@import "susy/grids";
@import "susy/box-sizing";
@import "susy/context";
@import "susy/background";
@import "susy/container";
@import "susy/span";
@import "susy/gutters";
@import "susy/isolate";
@import "susy/gallery";
@import "susy/rows";
@import "susy/margins";
@import "susy/padding";
@import "susy/bleed";
@import "susy/breakpoint-plugin";

View File

@ -1,13 +0,0 @@
// ---------------------------------------------------------------------------
// Partials
$susy-version: 1.5;
@import "susyone/settings";
@import "susyone/functions";
@import "susyone/grid";
@import "susyone/isolation";
@import "susyone/padding";
@import "susyone/margin";
@import "susyone/media";
@import "susyone/background";

View File

@ -1,385 +0,0 @@
// Background Grid Syntax
// ======================
$susy-overlay-grid-head-exists: false;
// Show Grid/s
// -----------
// Show grid on any element using either background or overlay.
// - [$grid] : <settings>
@mixin show-grid(
$grid: $susy
) {
$inspect: $grid;
$_output: debug-get(output, $grid);
@include susy-inspect(show-grid, $inspect);
@if $_output == overlay and susy-get(debug image, $grid) != hide {
@include overlay-grid($grid);
} @else {
@include background-grid($grid);
}
}
@mixin show-grids(
$grid: $susy
) {
@include show-grid($grid);
}
// Background Grid
// ---------------
// Show a grid background on any element.
// - [$grid] : <settings>
@mixin background-grid(
$grid: $susy
) {
$inspect : $grid;
$_output : get-background($grid);
@if length($_output) > 0 {
$_flow: susy-get(flow, $grid);
$_image: ();
@each $name, $layer in map-get($_output, image) {
$_direction: if($name == baseline, to bottom, to to($_flow));
$_image: append($_image, linear-gradient($_direction, $layer), comma);
}
$_output: map-merge($_output, (image: $_image));
@include background-grid-output($_output...);
@include susy-inspect(background-grid, $inspect);
}
}
// Overlay Grid
// ------------
// Generate an icon to trigger grid-overlays on any given elements.
// $grids... : <selector> [<settings>] [, <selector>]*
@mixin overlay-grid (
$grid: $susy
) {
@if not($susy-overlay-grid-head-exists) {
@at-root head { @include overlay-head($grid); }
@at-root head:before { @include overlay-trigger; }
@at-root head:hover { @include overlay-trigger-hover; }
$susy-overlay-grid-head-exists: true !global;
}
head:hover ~ &,
head:hover ~ body & {
position: relative;
&:before {
@include grid-overlay-base;
@include background-grid($grid);
}
}
}
// [Private] Overlay Trigger
// -------------------------
@mixin overlay-trigger {
content: "|||";
display: block;
padding: 5px 10px;
font: {
family: sans-serif;
size: 16px;
weight: bold;
}
}
// [Private] Overlay Trigger Hover
// -------------------------------
@mixin overlay-trigger-hover {
background: rgba(white, .5);
color: red;
}
// [Private] Overlay Head
// ----------------------
// <head> styles to create grid overlay toggle
@mixin overlay-head (
$grid: $susy
) {
$_toggle: debug-get(toggle, $grid);
$_horz: null;
$_vert: null;
@each $side in $_toggle {
$_horz: if($side == left or $side == right, $side, $_horz);
$_vert: if($side == top or $side == bottom, $side, $_vert);
}
display: block;
position: fixed;
#{$_horz}: 10px;
#{$_vert}: 10px;
z-index: 999;
color: #333;
background: rgba(white, .25);
}
// [Private] Grid Overlay Base
// ---------------------------
// Base styles for generating a grid overlay
@mixin grid-overlay-base() {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
content: " ";
z-index: 998;
}
// Get Symmetrical Background
// --------------------------
// - $grid: <map>
@function get-background-sym(
$grid
) {
$grid : parse-grid($grid);
$_gutters : susy-get(gutters, $grid);
$_column-width : susy-get(column-width, $grid);
$_math : susy-get(math, $grid);
$_color : debug-get(color);
$_trans : transparent;
$_light : lighten($_color, 15%);
$_end : 1 + $_gutters;
$_after : percentage(1/$_end);
$_stops : ();
$_size : span(1 $grid wide);
@if is-inside($grid) {
$_stops: $_color, $_light;
} @else if is-split($grid) {
$_split: $_gutters/2;
$_before: percentage($_split/$_end);
$_after: percentage((1 + $_split)/$_end);
$_stops: $_trans $_before, $_color $_before, $_light $_after, $_trans $_after;
} @else {
$_stops: $_color, $_light $_after, $_trans $_after;
}
@if $_math == static {
$_size: valid-column-math($_math, $_column-width) * $_end;
}
$_output: (
image: (columns: $_stops),
size: $_size,
);
@return $_output;
}
// Get Asymmetrical Inside
// -----------------------
// - $grid: <settings>
@function get-asym-inside(
$grid
) {
$grid : parse-grid($grid);
$_columns : susy-get(columns, $grid);
$_color : debug-get(color);
$_light : lighten($_color, 15%);
$_stops : ();
@for $location from 1 through susy-count($_columns) {
$this-stop: ();
@if $location == 1 {
$this-stop: append($this-stop, $_color, comma);
} @else {
$start: parse-span(1 at $location $grid);
$start: get-isolation($start);
$this-stop: append($this-stop, $_color $start, comma);
}
@if $location == susy-count($_columns) {
$this-stop: append($this-stop, $_light, comma);
} @else {
$_end: parse-span(1 at ($location + 1) $grid);
$_end: get-isolation($_end);
$this-stop: append($this-stop, $_light $_end, comma);
}
$_stops: join($_stops, $this-stop, comma);
}
@return $_stops;
}
// Get Asymmetrical Split
// ----------------------
// - $grid: <settings>
@function get-asym-split(
$grid
) {
$grid : parse-grid($grid);
$_columns : susy-get(columns, $grid);
$_color : debug-get(color);
$_light : lighten($_color, 15%);
$_stops : ();
@for $location from 1 through susy-count($_columns) {
$this-stop: ();
$start: parse-span(1 at $location $grid);
$start: get-isolation($start);
$this-stop: append($this-stop, transparent $start, comma);
$this-stop: append($this-stop, $_color $start, comma);
$_end: $start + span(1 at $location $grid);
$this-stop: append($this-stop, $_light $_end, comma);
$this-stop: append($this-stop, transparent $_end, comma);
$_stops: join($_stops, $this-stop, comma);
}
@return $_stops;
}
// Get Asymmetrical Outside
// ------------------------
// - $grid: <settings>
@function get-asym-outside(
$grid
) {
$grid : parse-grid($grid);
$_columns : susy-get(columns, $grid);
$_color : debug-get(color);
$_light : lighten($_color, 15%);
$_trans : transparent;
$_stops : ();
@for $location from 1 through susy-count($_columns) {
$this-stop: ();
@if $location == 1 {
$this-stop: append($this-stop, $_color, comma);
} @else {
$start: parse-span(1 at $location $grid);
$start: get-isolation($start);
$this-stop: append($this-stop, $_color $start, comma);
}
@if $location == susy-count($_columns) {
$this-stop: append($this-stop, $_light, comma);
} @else {
$gutter: get-span-width(first $location $grid);
$_end: parse-span(1 at ($location + 1) $grid);
$_end: get-isolation($_end);
$gutter: $_light $gutter, $_trans $gutter, $_trans $_end;
$this-stop: join($this-stop, $gutter, comma);
}
$_stops: join($_stops, $this-stop, comma);
}
@return $_stops;
}
// Get Asymmetrical Background
// ---------------------------
// - $grid: <settings>
@function get-background-asym(
$grid
) {
$_stops: ();
@if is-inside($grid) {
$_stops: get-asym-inside($grid);
} @else if is-split($grid) {
$_stops: get-asym-split($grid);
} @else {
$_stops: get-asym-outside($grid);
}
@return (image: (columns: $_stops));
}
// Get Background
// --------------
// - $grid: <settings>
@function get-background(
$grid
) {
$grid : parse-grid($grid);
$_show : susy-get(debug image, $grid);
$_return : ();
@if $_show and $_show != 'hide' {
$_columns: susy-get(columns, $grid);
@if $_show != 'show-baseline' {
$_sym: is-symmetrical($_columns);
$_return: if($_sym, get-background-sym($grid), get-background-asym($grid));
$_return: map-merge($_return, (clip: content-box));
}
@if $_show != 'show-columns'
and global-variable-exists(base-line-height)
and type-of($base-line-height) == 'number'
and not unitless($base-line-height) {
$_color: variable-exists('grid-background-baseline-color');
$_color: if($_color, $grid-background-baseline-color, #000);
$_image: map-get($_return, image);
$_size: map-get($_return, size);
$_baseline: (baseline: ($_color 1px, transparent 1px));
$_baseline-size: 100% $base-line-height;
$_return: map-merge($_return, (
image: if($_image, map-merge($_image, $_baseline), $_baseline),
size: if($_size, ($_size, $_baseline-size), $_baseline-size),
));
@if $_show == 'show' {
$_clip: map-get($_return, clip);
$_return: map-merge($_return, (clip: join($_clip, border-box, comma)));
}
} @else if $_show == 'show-baseline' {
@warn 'Please provide a $base-line-height with the desired height and units';
}
}
@if map-get($_return, image) {
$_return: map-merge($_return, (flow: susy-get(flow, $grid)));
}
@return $_return;
}
// Get Debug
// ---------
// Return the value of a debug setting
// - $key: <setting>
@function debug-get(
$key,
$grid: $susy
) {
$key: join(debug, $key, space);
@return susy-get($key, $grid);
}

View File

@ -1,200 +0,0 @@
// Bleed Syntax
// ============
// Bleed
// -----
// Add negative margins, and equal positive padding to create bleed.
// - $bleed : <span>
@mixin bleed(
$bleed: 0 gutter()
) {
$inspect : $bleed;
$output : get-bleed($bleed);
@if susy-get(global-box-sizing) != content-box {
$output: map-merge((box-sizing: content-box), $output);
}
@include susy-inspect(bleed, $inspect);
@include output($output);
}
// Bleed-x
// -------
// Shortcut for horizontal bleed.
// - $bleed : <span>
@mixin bleed-x(
$bleed: gutter()
) {
$bleed : parse-span($bleed);
$trbl : susy-get(span, $bleed);
@if length($trbl) == 1 {
$bleed: map-merge($bleed, (span: 0 nth($trbl, 1)));
} @else if length($trbl) == 2 {
$bleed: map-merge($bleed, (span: 0 nth($trbl, 2) 0 nth($trbl, 1)));
} @else {
@warn 'bleed-x only takes 2 lengths, but #{length($trbl)} were passed.';
}
@include bleed($bleed);
}
// Bleed-y
// -------
// Shortcut for vertical bleed.
// - $bleed : <span>
@mixin bleed-y(
$bleed: if(function-exists(rhythm), rhythm(1), 1em)
) {
$bleed : parse-span($bleed);
$trbl : susy-get(span, $bleed);
@if length($trbl) == 1 {
$bleed: map-merge($bleed, (span: nth($trbl, 1) 0));
} @else if length($trbl) == 2 {
$bleed: map-merge($bleed, (span: nth($trbl, 1) 0 nth($trbl, 2) 0));
} @else {
@warn 'bleed-y only takes 2 lengths, but #{length($trbl)} were passed.';
}
@include bleed($bleed);
}
// Get Bleed
// ---------
// Return bleed output values
// - $bleed: <span>
@function get-bleed(
$bleed
) {
$bleed : map-merge((spread: wide), parse-span($bleed));
$trbl : susy-get(span, $bleed);
$short : null;
$output : ();
@for $i from 1 through length($trbl) {
$this: nth($trbl, $i);
$new: ();
$margin: null;
$padding: null;
$padding-x: null;
@if $this > 0 {
$this: map-merge($bleed, (span: $this));
$margin: span($this);
$padding: $margin;
$padding-x: $padding;
}
@if $margin and $margin > 0 {
$margin: - $margin;
@if is-inside($this) {
$gutter: gutter($this);
$join: if($gutter and comparable($padding, $gutter), true, false);
$padding-x: if($join and $padding > 0, $padding + $gutter, $padding);
}
}
@if $i == 1 {
$new: (
margin-top: $margin,
padding-top: $padding,
margin-right: $margin,
padding-right: $padding-x,
margin-bottom: $margin,
padding-bottom: $padding,
margin-left: $margin,
padding-left: $padding-x,
);
} @else if $i == 2 {
$new: (
margin-right: $margin,
padding-right: $padding-x,
margin-left: $margin,
padding-left: $padding-x,
);
} @else if $i == 3 {
$new: (
margin-bottom: $margin,
padding-bottom: $padding,
);
} @else if $i == 4 {
$new: (
margin-left: $margin,
padding-left: $padding-x,
);
}
$output: map-merge($output, $new);
}
@each $prop, $value in $output {
$output: if($value == 0, map-merge($output, ($prop: null)), $output);
}
@return bleed-shorthand($output);
}
// Bleed Shorthand
// ---------------
// Convert bleed output into shorthand when possible.
// - $bleed: <output map>
@function bleed-shorthand(
$bleed
) {
$margin: ();
$padding: ();
$return: ();
@each $key, $value in $bleed {
@if str-index($key, margin) {
$margin: map-merge($margin, ($key: $value));
} @else if str-index($key, padding) > 0 {
$padding: map-merge($padding, ($key: $value));
}
}
$props: (
margin: $margin,
padding: $padding,
);
@each $name, $map in $props {
$four: if(length(map-keys($map)) == 4, true, false);
$null: if(index(map-values($map), null), true, false);
@if $four and not($null) {
$top: map-get($map, '#{$name}-top');
$right: map-get($map, '#{$name}-right');
$bottom: map-get($map, '#{$name}-bottom');
$left: map-get($map, '#{$name}-left');
$tb: if($top == $bottom, $top, null);
$rl: if($right == $left, $right, null);
$all: if($tb == $rl, $tb, null);
$new: if($all, $all, null);
@if not($new) {
@if $tb and $rl {
$new: $tb $rl;
} @else if $rl {
$new: $top $rl $bottom;
} @else {
$new: $top $right $bottom $left;
}
}
$return: map-merge($return, ($name: $new));
} @else {
$return: map-merge($return, $map);
}
}
@return $return;
}

View File

@ -1,47 +0,0 @@
// Susy Box Sizing
// =================
// Global Box Sizing
// -----------------
// Set a box model globally on all elements.
// - [$box]: border-box | content-box
// - [$inherit]: true | false
@mixin global-box-sizing(
$box: susy-get(global-box-sizing),
$inherit: false
) {
$inspect: $box;
@if $inherit {
@at-root {
html { @include output((box-sizing: $box)); }
*, *:before, *:after { box-sizing: inherit; }
}
} @else {
*, *:before, *:after { @include output((box-sizing: $box)); }
}
@include susy-inspect(global-box-sizing, $inspect);
@include update-box-model($box);
}
// Border Box Sizing
// -----------------
// A legacy shortcut...
// - [$inherit]: true | false
@mixin border-box-sizing(
$inherit: false
) {
@include global-box-sizing(border-box, $inherit);
}
// Update Box Model
// ----------------
// PRIVATE: Updates global box model setting
@mixin update-box-model(
$box
) {
@if $box != susy-get(global-box-sizing) {
@include susy-set(global-box-sizing, $box);
}
}

View File

@ -1,185 +0,0 @@
// Breakpoint Integration
// ======================
$susy-media: () !default;
$susy-media-fallback: false !default;
$_susy-media-context: ();
// Susy Breakpoint
// ---------------
// Change grids at different media query breakpoints.
// - $query : <min-width> [<max-width>] | <property> <value> | <map>
// - $layout : <settings>
// - $no-query : <boolean> | <selector>
@mixin susy-breakpoint(
$query,
$layout: false,
$no-query: $susy-media-fallback
) {
@include susy-media-router($query, $no-query) {
@if $layout {
@include with-layout($layout) {
@content;
}
} @else {
@content;
}
}
}
// Susy Media
// ----------
// - $query: <min-width> [<max-width>] | <property> <value>
// - $no-query: <boolean> | <selector>
@mixin susy-media(
$query,
$no-query: $susy-media-fallback
) {
$old-context: $_susy-media-context;
$name: if(map-has-key($susy-media, $query), $query, null);
$query: susy-get-media($query);
$query: susy-parse-media($query);
@include susy-media-context($query, $name);
@if $no-query and type-of($no-query) != string {
@content;
} @else {
@media #{susy-render-media($query)} {
@content;
}
@if type-of($no-query) == string {
#{$no-query} & {
@content;
}
}
}
@include susy-media-context($old-context, $clean: true);
}
// Media Router
// ------------
// Rout media arguments to the correct mixin.
@mixin susy-media-router(
$query,
$no-query: $susy-media-fallback
) {
@if susy-support(breakpoint, (mixin: breakpoint), $warn: false) {
@include breakpoint($query, $no-query) {
@content;
}
} @else {
@include susy-media($query, $no-query) {
@content;
}
}
}
// Update Context
// -------------
// Set the new media context
@mixin susy-media-context(
$query,
$name: null,
$clean: false
) {
$query: map-merge((name: $name), $query);
@if $clean {
$_susy-media-context: $query !global;
} @else {
$_susy-media-context: map-merge($_susy-media-context, $query) !global;
}
}
// Media Context
// -------------
// Return the full media context, or a single media property (e.g. min-width)
@function susy-media-context(
$property: false
) {
@if $property {
@return map-get($_susy-media-context, $property);
} @else {
@return $_susy-media-context;
}
}
// Get Media
// ---------
// Return a named media-query from $susy-media.
// - $name: <key>
@function susy-get-media(
$name
) {
@if map-has-key($susy-media, $name) {
$map-value: map-get($susy-media, $name);
@if ($name == $map-value) {
$name: $map-value;
} @else {
$name: susy-get-media($map-value);
}
}
@return $name;
}
// Render Media
// ------------
// Build a media-query string from various media settings
@function susy-render-media(
$query
) {
$output: null;
@each $property, $value in $query {
$string: null;
@if $property == media {
$string: $value;
} @else {
$string: '(#{$property}: #{$value})';
}
$output: if($output, '#{$output} and #{$string}', $string);
}
@return $output;
}
// Parse Media
// -----------
// Return parsed media-query settings based on shorthand
@function susy-parse-media(
$query
) {
$mq: null;
@if type-of($query) == map {
$mq: $query;
} @else if type-of($query) == number {
$mq: (min-width: $query);
} @else if type-of($query) == list and length($query) == 2 {
@if type-of(nth($query, 1)) == number {
$mq: (
min-width: min($query...),
max-width: max($query...),
);
} @else {
$mq: (nth($query, 1): nth($query, 2));
}
} @else {
$mq: (media: '#{$query}');
}
@return $mq;
}

View File

@ -1,81 +0,0 @@
// Container Syntax
// ================
// Container [mixin]
// -----------------
// Set a container element
// - [$layout] : <settings>
@mixin container(
$layout: $susy
) {
$inspect : $layout;
$layout : parse-grid($layout);
$_width : get-container-width($layout);
$_justify : parse-container-position(susy-get(container-position, $layout));
$_property : if(susy-get(math, $layout) == static, width, max-width);
$_box : susy-get(box-sizing, $layout);
@if $_box {
@include output((box-sizing: $_box));
}
@include susy-inspect(container, $inspect);
@include float-container($_width, $_justify, $_property);
@include show-grid($layout);
}
// Container [function]
// --------------------
// Return container width
// - [$layout] : <settings>
@function container(
$layout: $susy
) {
$layout: parse-grid($layout);
@return get-container-width($layout);
}
// Get Container Width
// -------------------
// Calculate the container width
// - [$layout]: <settings>
@function get-container-width(
$layout: $susy
) {
$layout : parse-grid($layout);
$_width : susy-get(container, $layout);
$_column-width : susy-get(column-width, $layout);
$_math : susy-get(math, $layout);
@if not($_width) or $_width == auto {
@if valid-column-math($_math, $_column-width) {
$_columns : susy-get(columns, $layout);
$_gutters : susy-get(gutters, $layout);
$_spread : if(is-split($layout), wide, narrow);
$_width : susy-sum($_columns, $_gutters, $_spread) * $_column-width;
} @else {
$_width: 100%;
}
}
@return $_width;
}
// Parse Container Position
// ------------------------
// Parse the $container-position into margin values.
// - [$justify] : left | center | right | <length> [<length>]
@function parse-container-position(
$justify: map-get($susy-defaults, container-position)
) {
$_return: if($justify == left, 0, auto) if($justify == right, 0, auto);
@if not(index(left right center, $justify)) {
$_return: nth($justify, 1);
$_return: $_return if(length($justify) > 1, nth($justify, 2), $_return);
}
@return $_return;
}

View File

@ -1,36 +0,0 @@
// Context Syntax
// ==============
// Nested [function]
// -----------------
// Return a subset grid for nested context.
// - $context : <span>
@function nested(
$context
) {
$context : parse-span($context);
$span : susy-get(span, $context);
$location : get-location($context);
$columns : susy-get(columns, $context);
@return susy-slice($span, $location, $columns);
}
// Nested [mixin]
// --------------
// Use a subset grid for a nested context
// - $context : <span>
// - @content : <content>
@mixin nested(
$context
) {
$inspect : $context;
$context : parse-span($context);
$old : susy-get(columns);
$susy : map-merge($susy, (columns: nested($context))) !global;
@include susy-inspect(nested, $inspect);
@content;
$susy : map-merge($susy, (columns: $old)) !global;
}

View File

@ -1,94 +0,0 @@
// Gallery Syntax
// ==============
// Gallery
// -------
// Create an isolated gallery
// - $span : <span>
// - [$selector] : child | of-type
@mixin gallery(
$span,
$selector: child
) {
$inspect : $span;
$span : parse-span($span);
$span : map-merge($span, (location: 1));
$n : susy-get(span, $span);
$columns : susy-get(columns, $span);
$context : susy-count($columns);
$flow : susy-get(flow, $span);
$inside : is-inside($span);
$from : from($flow);
$line : floor($context / $n);
$symmetrical : is-symmetrical($columns);
$output: (
width : null,
float : from,
margin-before : null,
margin-after : null,
padding-before : null,
padding-after : null,
flow : $flow,
);
@if $inside {
$gutters: get-gutters($span);
$output: map-merge($output, (
padding-before: map-get($gutters, before),
padding-after: map-get($gutters, after),
));
}
@if $symmetrical {
$output: map-merge($output, (width: get-span-width($span)));
}
$box : susy-get(box-sizing, $span);
$global-box : if(susy-get(global-box-sizing) == 'border-box', true, false);
@include susy-inspect(gallery, $inspect);
// Collective Output
@if $box == border-box or ($inside and not($box) and not($global-box)) {
@include output((box-sizing: border-box));
} @else if $box == content-box {
@include output((box-sizing: content-box));
}
@include float-span-output($output...);
// Individual Loop
@for $item from 1 through $line {
$nth: '#{$line}n + #{$item}';
&:nth-#{$selector}(#{$nth}) {
// Individual Prep
$output: (
width : if($symmetrical, null, get-span-width($span)),
float : null,
margin-before : get-isolation($span),
margin-after : -100%,
padding-before : null,
padding-after : null,
flow : $flow,
);
// Individual Output
@include float-span-output($output...);
@if get-edge($span) == first {
@include break;
@include first($span);
} @else {
@include nobreak;
}
// Individual Location Increment
$location: get-location($span) + $n;
$location: if($location > $context, 1, $location);
$span: map-merge($span, (location: $location));
}
}
}

View File

@ -1,64 +0,0 @@
// Grid Syntax
// ===========
// Layout
// ------
// Set a new layout using a shorthand
// - $layout: <settings>
// - $clean: boolean
@mixin layout(
$layout,
$clean: false
) {
$inspect : $layout;
$susy : _get-layout($layout, $clean) !global;
@include susy-inspect(layout, $inspect);
}
// Use Grid
// --------
// Use an arbitrary layout for a section of code
// - $layout: <settings>
// - $clean: boolean
@mixin with-layout(
$layout,
$clean: false
) {
$inspect : $layout;
$old : $susy;
$susy : _get-layout($layout, $clean) !global;
@include susy-inspect(with-layout, $inspect);
@content;
$susy: $old !global;
}
// Layout
// ------
// Return a parsed layout map based on shorthand syntax
// - $layout: <settings>
@function layout(
$layout: $susy
) {
@return parse-grid($layout);
}
// Get Layout
// ----------
// Return a new layout based on current and given settings
// - $layout: <settings>
// - $clean: boolean
@function _get-layout(
$layout,
$clean: false
) {
$layout: layout($layout);
@return if($clean, $layout, _susy-deep-merge($susy, $layout));
}

View File

@ -1,154 +0,0 @@
// Gutter Syntax
// =============
// Gutters
// -------
// Set gutters on an element.
// - [$span] : <settings>
@mixin gutters(
$span: $susy
) {
$inspect : $span;
$span : parse-gutters($span);
$_gutters : get-gutters($span);
$_output: (
before: map-get($_gutters, before),
after: map-get($_gutters, after),
flow: susy-get(flow, $span),
);
@include susy-inspect(gutters, $inspect);
@if is-inside($span) {
@include padding-output($_output...);
} @else {
@include margin-output($_output...);
}
}
@mixin gutter(
$span: $susy
) {
@include gutters($span);
}
// Gutter
// ------
// Return the width of a gutter.
// - [$span] : <settings>
@function gutter(
$span: $susy
) {
$span: parse-gutters($span);
$_gutters: get-gutters($span);
$_gutters: map-get($_gutters, before) or map-get($_gutters, after);
@return $_gutters;
}
@function gutters(
$span: $susy
) {
@return gutter($span);
}
// Get Gutter Width
// ----------------
// Return gutter width.
// - [$context]: <context>
@function get-gutter-width(
$context: $susy
) {
$context : parse-gutters($context);
$_gutters : susy-get(gutters, $context);
$_gutter : susy-get(gutter-override, $context);
@if $_gutters and ($_gutters > 0) and not($_gutter) {
$_column-width: susy-get(column-width, $context);
$_math: gutter-math($context);
@if $_math == static {
$_gutter: $_gutters * valid-column-math($_math, $_column-width);
} @else {
$_columns : susy-get(columns, $context);
$_spread : if(is-split($context), wide, susy-get(spread, $context));
$_gutter : percentage($_gutters / susy-sum($_columns, $_gutters, $_spread));
}
}
$_gutter: if($_gutter == 'no-gutters' or $_gutter == 'no-gutter', null, $_gutter);
@return $_gutter;
}
// Get Gutters
// -----------
// Return before and after gutter values.
// - [$context]: <context>
@function get-gutters(
$context: $susy
) {
$context : parse-gutters($context);
$_gutter-position : susy-get(gutter-position, $context);
$_gutter : get-gutter-width($context);
$_return : (before: null, after: null);
@if is-split($context) and $_gutter {
$_gutter: $_gutter / 2;
$_return: map-merge($_return, (before: $_gutter, after: $_gutter));
} @else {
$_return: map-merge($_return, ($_gutter-position: $_gutter));
}
@return $_return;
}
// Is Inside
// ---------
// Returns true if gutters are inside.
// $context: <context>
@function is-inside(
$context
) {
$_inside: inside inside-static;
$_gutter-position: susy-get(gutter-position, $context);
@return if(index($_inside, $_gutter-position), true, false);
}
// Is Split
// --------
// Returns true if gutters are split.
// $context: <context>
@function is-split(
$context
) {
$_split: split inside inside-static;
$_gutter-position: susy-get(gutter-position, $context);
@return if(index($_split, $_gutter-position), true, false);
}
// Gutter Math
// -----------
// Return the math to use for gutter calculations
// $context: <context>
@function gutter-math(
$context: $susy
) {
$_return : susy-get(math, $context);
$_return : if(susy-get(gutter-position, $context) == inside-static, static, $_return);
@return $_return;
}

View File

@ -1,77 +0,0 @@
// Isolation Syntax
// ================
// Isolate [Mixin]
// ---------------
// Set isolation as an override.
// - $location: <span>
@mixin isolate(
$isolate: 1
) {
$inspect: $isolate;
$output: (
push: isolate($isolate),
flow: susy-get(flow, $isolate),
);
@include susy-inspect(isolate, $inspect);
@include isolate-output($output...);
}
// Isolate [function]
// ------------------
// Return an isolation offset width.
// - $location: <span>
@function isolate(
$isolate: 1
) {
$isolate: parse-span($isolate);
$isolation: susy-get(span, $isolate);
@if $isolation and not(get-location($isolate)) {
$new: (
span: null,
location: $isolation,
);
$isolate: map-merge($isolate, $new);
}
@return get-isolation($isolate);
}
// Get Isolation
// -------------
// Return the isolation offset width
// - $input: <map>
@function get-isolation(
$input
) {
$location : get-location($input);
$columns : susy-get(columns, $input);
$width : null;
@if type-of($location) == number and not(unitless($location)) {
$width: $location;
} @else if $location {
$push: $location - 1;
@if $push > 0 {
$push: map-merge($input, (
span: $push,
location: 1,
spread: wide,
));
$width: get-span-width($push);
}
}
@if susy-get(gutter-position, $input) == split
and susy-get(gutters, $input) > 0 {
$width: if($width == null, gutters($input), $width + gutters($input));
}
@return $width or 0;
}

View File

@ -1,94 +0,0 @@
// Margin Syntax
// =============
// Pre
// ---
// Add spanning-margins before an element.
// - $span : <span>
@mixin pre(
$span
) {
$inspect: $span;
$span : map-merge((spread: wide), parse-span($span));
$flow : susy-get(flow, $span);
$split : if(susy-get(gutter-position, $span) == split, true, false);
$gutter : gutter($span);
$span : span($span);
$width : if($split and $gutter, $span + $gutter, $span);
@include susy-inspect(pre, $inspect);
@include margin-output($width, null, $flow);
}
// Post
// ----
// Add spanning-margins after an element.
// - $span : <span>
@mixin post(
$span
) {
$inspect : $span;
$span : map-merge((spread: wide), parse-span($span));
$flow : susy-get(flow, $span);
$split : if(susy-get(gutter-position, $span) == split, true, false);
$width : if($split, span($span) + gutter($span), span($span));
@include susy-inspect(post, $inspect);
@include margin-output(null, $width, $flow);
}
// Push
// ----
// Simple synonymn for pre.
// - $span : <span>
@mixin push(
$span
) {
@include pre($span);
}
// Pull
// ----
// Add negative spanning-margins before an element.
// - $span : <span>
@mixin pull(
$span
) {
$inspect : $span;
$span : map-merge((spread: wide), parse-span($span));
$flow : susy-get(flow, $span);
$split : if(susy-get(gutter-position, $span) == split, true, false);
$width : if($split, 0 - span($span) + gutter($span), 0 - span($span));
@include susy-inspect(pull, $inspect);
@include margin-output($width, null, $flow);
}
// Squish
// ------
// Add spanning-margins before and after an element.
// - $pre : <span>
// - [$post] : <span>
@mixin squish(
$pre,
$post: false
) {
$inspect : ($pre, $post);
$pre : map-merge((spread: wide), parse-span($pre));
@if $post {
$post: map-merge((spread: wide), parse-span($post));
} @else {
$span: susy-get(span, $pre);
@if length($span) > 1 {
$pre: map-merge($pre, (span: nth($span, 1)));
$post: map-merge($pre, (span: nth($span, 2)));
} @else {
$post: $pre;
}
}
@include susy-inspect(squish, $inspect);
@include pre($pre);
@include post($post);
}

View File

@ -1,74 +0,0 @@
// Padding Syntax
// ==============
// Prefix
// ------
// Add spanning-padding before an element.
// - $span : <span>
@mixin prefix(
$span
) {
$inspect : $span;
$span : map-merge((spread: wide), parse-span($span));
$flow : susy-get(flow, $span);
$width : span($span);
@if is-inside($span) {
$gutter: gutter($span);
$width: if($gutter and comparable($width, $gutter), $width + $gutter, $width);
}
@include susy-inspect(prefix, $inspect);
@include padding-output($width, null, $flow);
}
// Suffix
// ------
// Add spanning-padding after an element.
// - $span : <span>
@mixin suffix(
$span
) {
$inspect : $span;
$span : map-merge((spread: wide), parse-span($span));
$flow : susy-get(flow, $span);
$width : span($span);
@if is-inside($span) {
$gutter: gutter($span);
$width: if($gutter and comparable($width, $gutter), $width + $gutter, $width);
}
@include susy-inspect(suffix, $inspect);
@include padding-output(null, $width, $flow);
}
// Pad
// ---
// Add spanning-padding before and after an element.
// - $pre : <span>
// - [$post] : <span>
@mixin pad(
$pre,
$post: false
) {
$inspect : ($pre, $post);
$pre : map-merge((spread: wide), parse-span($pre));
@if $post {
$post: map-merge((spread: wide), parse-span($post));
} @else {
$span: susy-get(span, $pre);
@if length($span) > 1 {
$pre: map-merge($pre, (span: nth($span, 1)));
$post: map-merge($pre, (span: nth($span, 2)));
} @else {
$post: $pre;
}
}
@include susy-inspect(pad, $inspect);
@include prefix($pre);
@include suffix($post);
}

View File

@ -1,138 +0,0 @@
// Row Start & End
// ===============
// Break
// -----
// Apply to any element that should force a line break.
@mixin break {
@include output((clear: both));
}
// NoBreak
// -------
// Cancel the break() effect, e.g. when using media queries.
@mixin nobreak {
@include output((clear: none));
}
// Full
// ----
// - [$context]: <layout shorthand>
@mixin full(
$context: $susy
) {
$inspect : $context;
@include susy-inspect(full, $inspect);
@include span(full of parse-grid($context) break);
}
// First
// -----
// - [$context]: <settings>
@mixin first(
$context: $susy
) {
$inspect : $context;
$context : parse-grid($context);
$flow : susy-get(flow, $context);
@include susy-inspect(first, $inspect);
@if not(is-split($context)) {
@include float-first($flow);
}
}
@mixin alpha(
$context: $susy
) {
@include first($context);
}
// Last
// ----
// - [$context]: <settings>
@mixin last(
$context: $susy
) {
$inspect : $context;
$context : parse-grid($context);
@include susy-inspect(last, $inspect);
$output: (
flow: susy-get(flow, $context),
last-flow: susy-get(last-flow, $context),
margin: if(is-split($context), null, 0),
);
@include float-last($output...);
}
@mixin omega(
$context: $susy
) {
@include last($context);
}
// Get Edge
// --------
// Calculate edge value based on location, if possible
@function get-edge(
$span
) {
$span : parse-span($span);
$edge : susy-get(edge, $span);
@if not($edge) {
$count: susy-count(susy-get(columns, $span));
$location: susy-get(location, $span);
$n: susy-get(span, $span);
$number: if(type-of($location) == number, true, false);
$index: if($number and unitless($location), true, false);
@if $n == $count {
$edge: full;
} @else if $location and $n and $index {
@if $location == 1 {
$edge: if($n == $count, full, first);
} @else if $location + $n - 1 == $count {
$edge: last;
}
}
}
@if $edge == alpha or $edge == omega {
$edge: if($edge == alpha, first, last);
}
@return $edge;
}
// Get Location
// ------------
// Calculate location value based on edge, if possible
@function get-location(
$span
) {
$span : parse-span($span);
$location : susy-get(location, $span);
$edge : get-edge($span);
$n : susy-get(span, $span);
@if $edge and not($location) and type-of($n) == number and unitless($n) {
@if $edge == first {
$location: 1;
} @else if $edge == last {
$location: susy-count(susy-get(columns, $span)) - $n + 1;
}
}
@return $location
}

View File

@ -1,216 +0,0 @@
// Susy Settings
// =============
// Susy Language Defaults
// ----------------------
// - PRIVATE
@include susy-defaults((
container: auto,
math: fluid,
output: float,
container-position: center,
gutter-position: after,
global-box-sizing: content-box,
debug: (
image: hide,
color: rgba(#66f, .25),
output: background,
toggle: top right,
),
));
// Valid Keyword Values
// --------------------
// - PRIVATE: DONT'T TOUCH
$susy-keywords: (
container: auto,
math: static fluid,
output: isolate float,
container-position: left center right,
flow: ltr rtl,
gutter-position: before after split inside inside-static,
box-sizing: border-box content-box,
span: full,
edge: first alpha last omega full,
spread: narrow wide wider,
gutter-override: no-gutters no-gutter,
role: nest,
clear: break nobreak,
debug image: show hide show-columns show-baseline,
debug output: background overlay,
);
// Parse Susy Keywords and Maps
// ----------------------------
@function parse-settings(
$short: $susy
) {
$_return: ();
@if type-of($short) == map {
$_return: $short;
} @else {
@each $item in $short {
// strings
@if type-of($item) == string {
@each $key, $value in $susy-keywords {
@if index($value, $item) {
$_key-value: append($key, $item);
$_return: _susy-deep-set($_return, $_key-value...);
}
}
// maps
} @else if type-of($item) == map {
$_return: map-merge($_return, $item);
}
}
}
@return $_return;
}
// Parse Columns & Gutters
// -----------------------
@function parse-layout(
$short
) {
$_return: ();
$_columns: ();
$_gutters: null;
@if not(unitless(nth(nth($short, 1), 1))) {
$_gutters: nth($short, 1);
} @else {
$_columns: (columns: nth($short, 1));
$_gutters: if(length($short) > 1, nth($short, 2), $_gutters);
}
@if type-of($_gutters) == list and length($_gutters) > 0 {
$_gutters: (
gutters: nth($_gutters, 2) / nth($_gutters, 1),
column-width: nth($_gutters, 1),
);
} @else {
$_gutters: if($_gutters, (gutters: $_gutters), ());
}
$_return: map-merge($_return, $_columns);
$_return: map-merge($_return, $_gutters);
@return $_return;
}
// Parse Grid/Context
// ------------------
@function parse-grid(
$short: $susy
) {
$_return: parse-settings($short);
$_layout: ();
@if type-of($short) == map {
$_return: $short;
} @else {
@each $item in $short {
// number or list
@if type-of($item) == number or type-of($item) == list {
@if type-of($item) == list or unitless($item) {
$_layout: append($_layout, $item);
} @else {
$_return: map-merge($_return, (container: $item));
}
}
}
$_layout: if(length($_layout) > 0, parse-layout($_layout), $_layout);
}
@return map-merge($_return, $_layout);
}
// Parse Span
// ----------
@function parse-span(
$short,
$key: span
) {
$_return: ();
@if type-of($short) == map {
$_return: $short;
} @else {
$_at: index($short, at);
@if $_at {
$_loci: $_at + 1;
$_location: nth($short, $_loci);
$_return: map-merge($_return, (location: $_location));
$short: set-nth($short, $_at, null);
$short: set-nth($short, $_loci, null);
}
$_i: 1;
$_span: ();
@while $_i <= length($short) {
$_this: nth($short, $_i);
@if type-of($_this) == number {
$_span: append($_span, $_this);
$short: set-nth($short, $_i, null);
} @else if $_this == of {
$short: set-nth($short, $_i, null);
$_i: length($short) + 1;
}
$_i: $_i + 1;
}
@if length($_span) > 0 {
$_span: if(length($_span) == 1, nth($_span, 1), $_span);
$_return: map-merge($_return, ($key: $_span));
}
$_return: map-merge($_return, parse-grid($short));
}
@return $_return;
}
// Parse Gutters
// -------------
@function parse-gutters(
$short: $susy
) {
$_gutters: parse-span($short, gutter-override);
$_span: susy-get(gutter-override, $_gutters);
@if $_span and not(map-get($_gutters, columns)) {
$_context: ();
$_new: ();
@each $item in $_span {
@if type-of($item) == number and unitless($item) {
$_context: append($_context, $item);
} @else {
$_new: append($_new, $item);
}
}
$_context: parse-grid($_context);
$_new: if(length($_new) == 0, null, $_new);
$_new: if(length($_new) == 1, nth($_new, 1), $_new);
$_new: (gutter-override: if($_new != $_span, $_new, $_span));
$_gutters: map-merge($_gutters, $_new);
$_gutters: map-merge($_gutters, $_context);
}
@return $_gutters;
}

View File

@ -1,163 +0,0 @@
// Span Syntax
// ===========
// Span [mixin]
// ------------
// Set a spanning element using shorthand syntax.
// - $span : <span>
@mixin span(
$span
) {
$inspect: $span;
$span: parse-span($span);
$output: span-math($span);
$nesting: susy-get(span, $span);
$clear: susy-get(clear, $span);
$box: susy-get(box-sizing, $span);
$content-box: if(susy-get(global-box-sizing) != 'border-box', true, false);
$box: $box or if(is-inside($span) and $content-box, border-box, null);
@if $clear == break {
@include break;
} @else if $clear == nobreak {
@include nobreak;
}
@include susy-inspect(span, $inspect);
@include output((box-sizing: $box));
@include float-span-output($output...);
@if valid-columns($nesting, silent) {
@include nested($span) { @content; }
} @else {
@content;
}
}
// Span [function]
// ---------------
// Return the width of a span.
// - $span : <span>
@function span(
$span
) {
@return get-span-width($span);
}
// Span Math
// ---------
// Get all the span results.
// - $span: <map>
@function span-math(
$span
) {
$nest : if(susy-get(role, $span) == nest, true, false);
$split-nest : if(is-split($span) and $nest, true, false);
$edge : get-edge($span);
$location : get-location($span);
$float : from;
$padding-before : null;
$padding-after : null;
$margin-before : null;
$margin-after : null;
// calculate widths
$spread: index(map-values($span), spread);
$span: if($split-nest and not($spread), map-merge($span, (spread: wide)), $span);
$width: get-span-width($span);
$gutters: get-gutters($span);
// apply gutters
@if is-inside($span) {
@if not(susy-get(role, $span)) {
$padding-before: map-get($gutters, before);
$padding-after: map-get($gutters, after);
}
} @else {
@if not($split-nest) {
$margin-before: map-get($gutters, before);
$margin-after: map-get($gutters, after);
}
}
// special margin handling
@if susy-get(output, $span) == isolate and $location {
$margin-before: get-isolation($span);
$margin-after: -100%;
} @else if $edge {
$is-split: is-split($span);
$pos: susy-get(gutter-position, $span);
@if $edge == last {
$float: susy-get(last-flow, $span);
}
@if not($is-split) {
@if $edge == full or ($edge == first and $pos == before) {
$margin-before: 0;
}
@if $edge == full or ($edge == last and $pos == after) {
$margin-after: 0;
}
}
}
@return (
width : $width,
float : $float,
margin-before : $margin-before,
margin-after : $margin-after,
padding-before : $padding-before,
padding-after : $padding-after,
flow : susy-get(flow, $span),
);
}
// Get Span Width
// --------------
// Return span width.
// - $span: <map>
@function get-span-width(
$span
) {
$span : parse-span($span);
$n : susy-get(span, $span);
$location : get-location($span);
$columns : susy-get(columns, $span);
$gutters : susy-get(gutters, $span);
$spread : susy-get(spread, $span);
$context : null;
$span-sum : null;
$width : null;
@if $n == 'full' {
$pos: susy-get(gutter-position, $span);
$role: susy-get(role, $span);
$n: if($pos == split and $role != nest, susy-count($columns), 100%);
}
@if type-of($n) != number {
@warn "(#{type-of($n)}) #{$n} is not a valid span.";
} @else if unitless($n) {
$context: susy-sum($columns, $gutters, if(is-split($span), wide, narrow));
$spread: if(is-inside($span), $spread or wide, $spread);
$span-sum: susy($n, $location, $columns, $gutters, $spread);
$_math: susy-get(math, $span);
$_column-width: susy-get(column-width, $span);
@if $_math == static {
$width: $span-sum * valid-column-math($_math, $_column-width);
} @else {
$width: percentage($span-sum / $context);
}
} @else {
$width: $n;
}
@return $width;
}

View File

@ -1,16 +0,0 @@
// Validation
// ==========
// Validate Column Math
// --------------------
@function valid-column-math(
$math,
$column-width
) {
@if $math == static and not($column-width) {
@error 'Static math requires a valid column-width setting.';
}
@return $column-width;
}

View File

@ -1,18 +0,0 @@
// ---------------------------------------------------------------------------
// Imports
@import "compass/layout/grid-background";
@import "compass/css3/background-origin";
@import "compass/css3/background-clip";
// ---------------------------------------------------------------------------
// Susy Grid Background
//
// A wrapper for the compass "column-grid-background" mixin
// Uses all your settings to create a grid background for a container element.
// Note: Sub-pixel rounding can lead to several pixels of variation between browsers.
@mixin susy-grid-background(){
@include column-grid-background($total-columns, column(), gutter(), 0);
@include background-origin(content-box);
@include background-clip(content-box);
}

View File

@ -1,377 +0,0 @@
// ---------------------------------------------------------------------------
// Imports
// We need access to some basic font settings for handling media-queries.
@import "compass/typography/vertical_rhythm";
// For now, we also need this...
$browser-default-font-size-px : 16px;
$browser-default-font-size-percent : 100%;
$browser-default-font-size-pt : 12pt;
$rem-with-px-fallback : true !default;
// ---------------------------------------------------------------------------
// Sass list Functions
// Return a list with specific items removed
//
// filter($list, $target)
// - $list : The list to filter.
// - $target : An item to be removed from the list.
@function filter($list, $target) {
$clean: compact();
@if index($list, $target) {
@each $item in $list {
$clean: if($item == $target, $clean, append($clean, $item));
}
} @else { $clean: $list; }
@return $clean;
}
// ---------------------------------------------------------------------------
// Don't use static output when it will break things
// Switch element-level output to fluid, when container-width is wrong for static
//
// fix-static-misalignment([$style, $width])
// - $style: $container-style.
// - $width: $container-width.
@function fix-static-misalignment(
$style: $container-style,
$width: $container-width
) {
@if $container-width and $container-width != container-outer-width($width: false) {
$style: fluid;
}
@return $style;
}
// ---------------------------------------------------------------------------
// Grid Functions
// Returns the full width of a grid based on your grid settings.
//
// $columns : The number of columns to get width for.
@function columns-width(
$columns : $total-columns
) {
@if round($columns) != $columns {
@warn "Susy works best with integer column-spans." +
"For partial-columns, you may need to finesse the math by hand using functions directly.";
}
@return ($columns * $column-width) + (if($columns >= 1, ceil($columns - 1), 0) * $gutter-width);
}
// Return the grid width after adding or subtracting grid padding
//
// $width : the width of the grid without padding;
// $operation : ( add | subtract ) if padding should be added or subtracted;
@function handle-grid-padding(
$width,
$operation : subtract
) {
$pad: $grid-padding*2;
@if comparable($width, $grid-padding) {
$width: if($operation == subtract, $width - $pad, $width + $pad);
} @else {
@warn "$grid-padding must be set in units comparable to the container width.";
}
@return $width;
}
// Return the full outer width of a Container element.
//
// $columns : The number of columns in the Grid Layout.
@function container-outer-width(
$columns : $total-columns,
$width : $container-width
) {
$outerwidth: if($width, $width, columns-width($columns));
@if $width {
@if not($border-box-sizing) { $outerwidth: handle-grid-padding($outerwidth, subtract); }
} @else {
@if $border-box-sizing { $outerwidth: handle-grid-padding($outerwidth, add); }
}
@return $outerwidth;
}
// Return the percentage width of a single column in a given 'context'.
//
// $context : The grid context in columns, if nested.
// $style : The container style to use.
@function column(
$context : $total-columns,
$style : fix-static-misalignment()
) {
@return if($style == static, $column-width, relative-width($column-width, $context));
}
// Return the percentage width of multiple 'columns' in a given 'context'.
//
// $columns : The number of columns to get relative width for.
// $context : The grid context in columns, if nested.
// $style : The container style to use.
@function columns(
$columns,
$context : $total-columns,
$style : fix-static-misalignment()
) {
@return if($style == static, columns-width($columns), relative-width(columns-width($columns), $context));
}
// Return the percentage width of a single gutter in a given 'context'.
//
// $context : The grid context in columns, if nested.
// $style : The container style to use.
@function gutter(
$context : $total-columns,
$style : fix-static-misalignment()
) {
@return if($style == static, $gutter-width, relative-width($gutter-width, $context));
}
// Return the percentage width of a given value in a given 'context'.
//
// $width : Any given width value.
// $context : The grid context in columns, if nested.
@function relative-width(
$width,
$context : $total-columns
) {
@return percentage($width / columns-width($context));
}
// Return the total space occupied by multiple columns and associated gutters.
// Useful for adding padding or margins (prefix, suffix, push, pull, etc.)
//
// $columns : The number of columns to get relative space for.
// $context : The grid context in columns, if nested.
// $style : The container style to use.
@function space(
$columns,
$context : $total-columns,
$style : fix-static-misalignment()
) {
@return columns($columns, $context, $style) + if($columns >= 1, gutter($context, $style), 0);
}
// Accept a list including column-count and (optional) position.
// Return either the column count or the position alone.
//
// $columns : the list to split and interprate.
// $request : The value to return, either 'columns' or 'position'.
@function split-columns-value(
$columns,
$request : columns
) {
$pos : false;
$cols : false;
@each $var in $columns {
@if (type-of($var) == 'string') {
$pos: $var;
} @else {
@if (type-of($var) == 'number') and (unitless($var)) {
$cols: $var;
} @else {
@warn '"#{$var}" is not a valid part of "$columns: #{$columns}" in the columns() mixin.';
}
}
}
@if $request == 'columns' {
@return $cols;
} @else {
@if $request == 'position' {
@return $pos;
} @else {
@warn '"#{$request}" is not a valid value for $request';
}
}
}
// Accept nth-selector variables, and format them as a valid CSS3 selector.
//
// $n : [first | only | last | <equation>]
// $selector : [child | last-child | of-type | last-of-type ]
@function format-nth(
$n : last,
$selector : child
) {
@if ($n == 'last') or ($n =='first') or ($n =='only') {
$selector: '#{$n}-#{$selector}';
} @else {
$selector: 'nth-#{$selector}(#{$n})';
}
@return $selector;
}
// ---------------------------------------------------------------------------
// Media Functions
// Return an em value adjusted to match the browser default font size.
// Note: This only works if actual sizes are set relative to browser defaults.
//
// $ems : The initial value to be converted.
// $font-size : The current font-size in.
@function base-ems(
$ems,
$font-size: $base-font-size
){
$font-size : if(unit($ems) == 'rem', $base-font-size, $font-size);
$unit : unit($font-size);
$mult : $ems / ($ems * 0 + 1);
@if $unit == 'px' {
@return $font-size / $browser-default-font-size-px * $mult * 1em;
}
@else if $unit == '%' {
@return $font-size / $browser-default-font-size-percent * $mult * 1em;
}
@else if $unit == 'em' {
@return $font-size / 1em * $mult * 1em;
}
@else if $unit == 'pt' {
@return $font-size / $browser-default-font-size-pt * $mult * 1em;
}
@else {
@warn 'Variable $base-font-size does not have a valid font unit. Valid units for fonts in CSS are px, pt, em, and %.';
}
}
// This name will be deprecated...
@function absolute-ems(
$ems,
$font-size: $base-font-size
){
@return base-ems( $ems, $font-size);
}
// Return a length, after any em-values have been sent through absolute-ems().
//
// $length : The length value to be checked and adjusted if necessary.
// $font-size : The current font-size in px.
@function fix-ems(
$length,
$font-size: $base-font-size
){
@if $length {
@if (unit($length) == 'em') or (unit($length) == 'rem') {
$length: absolute-ems($length,$font-size);
}
}
@return $length;
}
// Sort a list of arguments into "$min $layout $max $ie" order, and return the list.
//
// $media-layout : a list of values [$min $layout $max $ie] including...
// : - one unitless number (columns in a layout)
// : - two optional lengths (min and max-width media-query breakpoints).
// : - one optional boolean or string to trigger fallback support for IE.
// $font-size : [optional] The base font-size of your layout, if you are using ems.
// : - defaults to $base-font-size
@function medialayout(
$media-layout,
$font-size: $base-font-size
) {
$media : false;
$min : false;
$layout : false;
$max : false;
$ie : false;
$has-layout : false;
@each $val in $media-layout {
@if (type-of($val) == "number") {
@if unitless($val) {
$layout : $val;
$has-layout : true;
} @else {
@if ($has-layout) and not($media) {
$max: $val;
} @else {
@if $media {
$media: join($media,$val);
} @else {
$media: $val;
}
}
}
} @else {
$ie: $val;
}
}
@if (length($media) > 0) {
@if (length($media) == 1) {
$min: nth($media,1);
} @else {
$min: nth($media,1);
$max: nth($media,2);
@if comparable($min, $max) {
@if ($min > $max) {
$max: nth($media,1);
$min: nth($media,2);
}
} @else {
@warn "Can't compare incompatible units." +
"Using #{$min} for min-width, and #{$max} for max-width";
}
@if (length($media) > 2) {
@warn "You can only send two lengths: a min-width and an (optional) max-width." +
"You sent #{length($media)}: #{$media}";
}
}
}
// media-queries must be set in ems relative to the browser default
// rather than the font-size set in CSS.
$min: fix-ems($min,$font-size);
$max: fix-ems($max,$font-size);
@return $min $layout $max $ie;
}
// Return the nearest layout (column-count) above a given breakpoint.
//
// $min : The min-width media-query breakpoint above which to establish a new layout.
@function get-layout(
$min
) {
$min : fix-ems($min);
$return : false;
@if comparable($min, $column-width) {
$return : ceil(($min + $gutter-width) / ($column-width + $gutter-width));
} @else {
@warn "Can't determine a layout, becuse #{$min} and #{$column-width} are not comparable.";
}
@return $return;
}
// Check to see if a given $media-layout list is simply the default.
//
// $media-layout : a list of values including -
// : One unitless number (columns in a layout)
// : Two optional lengths (min and max-width media-query breakpoints).
// : One optional boolean or string to trigger fallback support for IE.
@function is-default-layout(
$media-layout
) {
$media-layout : medialayout($media-layout);
$min : nth($media-layout,1);
$layout-cols : nth($media-layout,2);
$max : nth($media-layout,3);
@if $min or $max {
@return false;
} @else {
@return if($layout-cols == $total-columns,true,false);
}
}

View File

@ -1,312 +0,0 @@
// ---------------------------------------------------------------------------
// Imports
@import "compass/utilities/general/clearfix";
@import "compass/css3/box-sizing";
// ---------------------------------------------------------------------------
// Border-Box Sizing
// Apply the border-box sizing model to all elements
// and adjust the grid math appropriately.
@mixin border-box-sizing {
$border-box-sizing: true !global;
* { @include box-sizing(border-box); }
}
// ---------------------------------------------------------------------------
// Container
// Set the width of a container
//
// $columns : The number of columns in the Grid Layout.
@mixin set-container-width(
$columns : $total-columns,
$style : $container-style,
$px-vals : $pixel-values-only
){
$width: container-outer-width($columns);
@if $style == 'static' {
@if $px-vals == true {
width: round(convert-length($width, px));
} @else {
@include rem(width, $width);
}
} @else {
@if $style == 'fluid' {
@if unit($width) == '%' {
@if $px-vals == true {
width: round(convert-length($width, px));
} @else {
@include rem(width, $width);
}
}
} @else {
@if $px-vals == true {
max-width: round(convert-length($width, px));
} @else {
@include rem(max-width, $width);
}
@include for-legacy-browser(ie,"6") {
@if unit($width) == 'rem' {
_width: round(convert-length($width, px));
} @else {
_width: $width;
}
}
}
}
}
// Set the outer grid-containing element(s).
//
// $columns : The number of columns in the container.
@mixin apply-container(
$columns : $total-columns,
$px-vals : $pixel-values-only
){
@include pie-clearfix;
@include set-container-width($columns);
@if $px-vals == true {
padding-left: round(convert-length($grid-padding, px));
padding-right: round(convert-length($grid-padding, px));
} @else {
@include rem(padding-left, $grid-padding);
@include rem(padding-right, $grid-padding);
}
margin: { left: auto; right: auto; }
}
// Set one or more layouts on a grid-containing element at any number of media-query breakpoints.
//
// $media-layout-1 : [default:$total-columns] A list of values including -
// : One unitless number (representing columns in a layout)
// : Two optional lengths (representing min and max-width media-query breakpoints).
// $media-layout-2 ...-10 : [optional] Same as $media-layout-1
@mixin container(
$media-layouts...
){
$media-layouts: if(length($media-layouts) > 0, $media-layouts, $total-columns);
@each $ml in $media-layouts {
@if is-default-layout($ml) {
@include apply-container;
} @else {
@include at-breakpoint($ml) {
@include apply-container;
}
}
}
}
// ---------------------------------------------------------------------------
// Columns
// Create a grid element spanning any number of 'columns' in a grid 'context'.
// $columns : The number of columns to span.
// $context : [optional] The context (columns spanned by parent).
// : Context is required on any nested elements.
// : Context MUST NOT be declared on a root element.
// $padding : [optional] Padding applied to the inside of individual grid columns.
// : Padding is only output if one or two values are specified (e.g. 1em or 10px 20px)
// : Padding values are applied only on the horizontal axis in from-to order
// $from : The start direction of your layout (e.g. 'left' for ltr languages)
// $style : The container style to use.
@mixin span-columns(
$columns,
$context : $total-columns,
$padding : false,
$from : $from-direction,
$style : fix-static-misalignment()
) {
$from : unquote($from);
$to : opposite-position($from);
$pos : split-columns-value($columns,position);
$cols : split-columns-value($columns,columns);
$pad-from : if($style == static, 0 * $gutter-width, relative-width(0 * $gutter-width, $context));
$pad-to : if($style == static, 0 * $gutter-width, relative-width(0 * $gutter-width, $context));
@if $padding != false {
$pad-from : nth($padding, 1);
@if length($padding) > 1 {
$pad-to: nth($padding, 2);
} @else {
$pad-to: $pad-from;
}
$pad-from : if($style == static, $pad-from, relative-width($pad-from, $context));
$pad-to : if($style == static, $pad-to, relative-width($pad-to, $context));
padding-#{$from}: $pad-from;
padding-#{$to}: $pad-to;
}
width: columns($cols, $context, $style) - if($border-box-sizing, 0, $pad-to + $pad-from);
@if ($pos == 'omega') {
@include omega($from);
} @else {
float: $from;
margin-#{$to}: gutter($context, $style);
@include for-legacy-browser(ie, "6") {
display: inline;
}
}
}
// Apply to elements spanning the last column, to account for the page edge.
// Only needed as an override. Normally 'omega' can just be called by `columns`.
//
// $from : The start-direction for your document.
@mixin omega(
$from : $from-direction
) {
$from : unquote($from);
$to : opposite-position($from);
$hack : opposite-position($omega-float);
float: $omega-float;
margin-#{$to}: 0;
@include for-legacy-browser(ie, "6", "7") {
*margin-#{$hack}: - $gutter-width;
@include for-legacy-browser(ie, "6") {
display: inline;
}
}
}
// Shortcut to apply omega to a specific subset of elements.
//
// $n : [first | only | last | <equation>]
// $selector : [child | last-child | of-type | last-of-type ]
// $from : The start-direction for your document.
@mixin nth-omega(
$n : last,
$selector : child,
$from : $from-direction
) {
$from : unquote($from);
&:#{format-nth($n,$selector)} {
@if $n == "first" {
@include omega($from);
} @else {
@include with-browser-ranges(css-sel3) {
@include omega($from);
}
}
}
}
// ---------------------------------------------------------------------------
// Resets
// Reset a '+columns' grid element to default block behavior
//
// $from : The start direction of your layout (e.g. 'left' for ltr languages)
@mixin reset-columns(
$from: $from-direction
) {
$from : unquote($from);
$to : opposite-position($from);
$hack : opposite-position($omega-float);
float: none;
width: auto;
margin-#{$to}: auto;
@include for-legacy-browser(ie, "6", "7") {
*margin-#{$hack}: auto;
@include for-legacy-browser(ie, "6") {
display: block;
}
}
}
// Apply to elements previously set as omega.
// This will return floats and margins back to non-omega settigns.
//
// $context : [optional] The context (columns spanned by parent).
// $from : The start-direction for your document.
// $style : The container style to use.
@mixin remove-omega(
$context : $total-columns,
$from : $from-direction,
$style : fix-static-misalignment()
) {
$from : unquote($from);
$to : opposite-position($from);
$hack : opposite-position($omega-float);
float: $from;
margin-#{$to}: gutter($context, $style);
@include for-legacy-browser(ie, "6", "7") {
*margin-#{$hack}: auto;
}
}
// Shortcut to apply remove-omega to a specific subset of elements.
//
// $n : [first | only | last | <equation>]
// $selector : [child | last-child | of-type | last-of-type ]
// $context : [optional] The context (columns spanned by parent).
// $from : The start-direction for your document.
// $style : The container style to use.
@mixin remove-nth-omega(
$n : last,
$selector : child,
$context : $total-columns,
$from : $from-direction,
$style : fix-static-misalignment()
) {
$from : unquote($from);
&:#{format-nth($n,$selector)} {
@if $n == "first" {
@include remove-omega($context, $from, $style);
} @else {
@include with-browser-ranges(css-sel3) {
@include remove-omega($context, $from, $style);
}
}
}
}
// ---------------------------------------------------------------------------
// Change Settings
@mixin with-grid-settings(
$columns: $total-columns,
$width: $column-width,
$gutter: $gutter-width,
$padding: $grid-padding
) {
// keep the defaults around
$default-columns: $total-columns;
$default-width: $column-width;
$default-gutter: $gutter-width;
$default-padding: $grid-padding;
// use the new settings
$total-columns: $columns !global;
$column-width: $width !global;
$gutter-width: $gutter !global;
$grid-padding: $padding !global;
// apply to contents
@content;
// re-instate the defaults
$total-columns: $default-columns !global;
$column-width: $default-width !global;
$gutter-width: $default-gutter !global;
$grid-padding: $default-padding !global;
}

View File

@ -1,51 +0,0 @@
// ---------------------------------------------------------------------------
// Isolation
// Isolate the position of a grid element (use in addition to span-columns)
//
// $location : The grid column to isolate in, relative to the container;
// $context : [optional] The context (columns spanned by parent).
// $from : The start direction of your layout (e.g. 'left' for ltr languages)
@mixin isolate(
$location,
$context: $total-columns,
$from: $from-direction,
$style: fix-static-misalignment()
) {
$to: opposite-position($from);
margin-#{$to}: -100%;
margin-#{$from}: space($location - 1, $context, $style);
}
// Isolate a group of elements in a grid, using nth-child selectors
//
// $columns : The column-width of each item on the grid;
// $context : [optional] The context (columns spanned by parent).
// $selector : [child | of-type | last-of-type ] (default is 'child')
// $from : The start direction of your layout (e.g. 'left' for ltr languages)
@mixin isolate-grid(
$columns,
$context: $total-columns,
$selector: 'child',
$from: $from-direction,
$style: fix-static-misalignment()
) {
$to: opposite-position($from);
$location: 1;
$line: floor($context / $columns);
@include span-columns($columns, $context, $from: $from, $style: $style);
margin-#{$to}: -100%;
@for $item from 1 through $line {
$nth: '#{$line}n + #{$item}';
&:#{format-nth($nth,$selector)} {
margin-#{$from}: space($location - 1, $context, $style);
@if $location == 1 { clear: $from; }
@else { clear: none; }
$location: $location + $columns;
@if $location > $context { $location: 1; }
}
}
}

View File

@ -1,93 +0,0 @@
// ---------------------------------------------------------------------------
// Margin Mixins
// Apply 'columns' margin before an element to push it along the grid.
//
// $columns : The number of columns to span.
// $context : [optional] The context (columns spanned by parent).
// : Context is required on any nested elements.
// : Context MUST NOT be declared on a root element.
// $from : The start direction of your layout (e.g. 'left' for ltr languages)
// $style : The container style to use.
@mixin pre(
$columns,
$context : $total-columns,
$from : $from-direction,
$style : fix-static-misalignment()
) {
$from : unquote($from);
margin-#{$from}: space($columns, $context, $style);
}
// 'push' is a synonymn for 'pre'
@mixin push(
$columns,
$context : $total-columns,
$from : $from-direction,
$style : fix-static-misalignment()
) {
$from : unquote($from);
@include pre($columns, $context, $from, $style);
}
// Apply negative 'columns' margin before an element to pull it along the grid.
//
// $columns : The number of columns to span.
// $context : [optional] The context (columns spanned by parent).
// : Context is required on any nested elements.
// : Context MUST NOT be declared on a root element.
// $from : The start direction of your layout (e.g. 'left' for ltr languages)
// $style : The container style to use.
@mixin pull(
$columns,
$context : $total-columns,
$from : $from-direction,
$style : fix-static-misalignment()
) {
$from : unquote($from);
margin-#{$from}: 0 - space($columns, $context, $style);
}
// Apply 'columns' margin after an element to contain it in a grid.
//
// $columns : The number of columns to span.
// $context : [optional] The context (columns spanned by parent).
// : Context is required on any nested elements.
// : Context MUST NOT be declared on a root element.
// $from : The start direction of your layout (e.g. 'left' for ltr languages)
// $style : The container style to use.
@mixin post(
$columns,
$context : $total-columns,
$from : $from-direction,
$style : fix-static-misalignment()
) {
$from : unquote($from);
$to : opposite-position($from);
margin-#{$to}: space($columns, $context, $style);
}
// Apply 'columns' before and/or after an element to contain it on a grid.
//
// $pre : The number of columns to add as margin before.
// $post : The number of columns to add as margin after.
// $context : [optional] The context (columns spanned by parent).
// : Context is required on any nested elements.
// : Context MUST NOT be declared on a root element.
// $from : The start direction of your layout (e.g. 'left' for ltr languages)
// $style : The container style to use.
@mixin squish(
$pre : false,
$post : false,
$context : $total-columns,
$from : $from-direction,
$style : fix-static-misalignment()
) {
$from : unquote($from);
@if $pre {
@include pre($pre, $context, $from, $style)
}
@if $post {
@include post($post, $context, $from, $style)
}
}

View File

@ -1,105 +0,0 @@
// ---------------------------------------------------------------------------
// Media Mixins
// Create a new layout context for (@content) descendants.
//
// $layout-cols : a (unitless) number of columns to use for this layout.
@mixin layout(
$layout-cols
) {
// store default $total-columns setting for later, then change it.
$default-layout : $total-columns;
$total-columns : $layout-cols !global;
// apply children in this new layout context.
@content;
// return to default $total-columns setting.
$total-columns : $default-layout !global;
}
// Nest a block of code inside a new media-query and layout context.
//
// $media-layout : a list of values [$min $layout $max $ie] including...
// : - one unitless number (columns in a layout)
// : - two optional lengths (min and max-width media-query breakpoints).
// : - one optional boolean or string to trigger fallback support for IE.
// $font-size : [optional] The base font-size of your layout, if you are using ems.
// : - defaults to $base-font-size
@mixin at-breakpoint(
$media-layout,
$font-size: $base-font-size
) {
$media-layout : medialayout($media-layout,$font-size);
$min : nth($media-layout,1);
$layout : nth($media-layout,2);
$max : nth($media-layout,3);
$ie : nth($media-layout,4);
@if not($breakpoint-media-output) and not($breakpoint-ie-output) and not($breakpoint-raw-output) {
@warn "Either $breakpoint-media-output, $breakpoint-ie-output, or $breakpoint-raw-output must be true for at-breakpoint to work.";
}
// We need to have either a min-width breakpoint or a layout in order to proceed.
@if $min or $layout or $max {
// If we don't have a layout, we create one based on the min-width.
@if not($layout) {
$layout: get-layout($min);
}
// If we still don't have a layout, we have a problem.
@if $layout {
// Set our new layout context.
@include layout($layout) {
@if $breakpoint-media-output {
@include with-browser-ranges(css-mediaqueries) {
@if $min and $max {
// Both $min and $max
@media (min-width: $min) and (max-width: $max) {
@content;
}
} @else {
@if not($min) and not($max) {
// Neither $min nor $max:
// We can create a breakpoint based on the number of columns in the layout.
$min: fix-ems(container-outer-width($width: false));
}
@if $min {
// Min only:
@media (min-width: $min) {
@content;
}
} @else {
// Max only:
@media (max-width: $max) {
@content;
}
}
}
}
}
// Set an IE fallback
@if $ie and $breakpoint-ie-output {
@if (type-of($ie) == 'bool') {
$ie: 'lt-ie9';
}
.#{$ie} & {
@content;
}
}
@if $breakpoint-raw-output {
@content;
}
}
} @else {
@warn "We were unable to determine a layout for your breakpoint.";
}
} @else {
@warn "You need to provide either a valid layout (number of columns)"
+ "or a valid media-query min-width breakpoint (length).";
}
}

View File

@ -1,92 +0,0 @@
// ---------------------------------------------------------------------------
// Padding Mixins
// add empty colums as padding before an element.
// $columns : The number of columns to prefix.
// $context : [optional] The context (columns spanned by parent).
// : Context is required on any nested elements.
// : Context MUST NOT be declared on a root element.
// $from : The start direction of your layout (e.g. 'left' for ltr languages)
// $style : The container style to use.
@mixin prefix(
$columns,
$context : $total-columns,
$from : $from-direction,
$style : fix-static-misalignment()
) {
$from : unquote($from);
padding-#{$from}: space($columns, $context, $style);
}
// add empty colums as padding after an element.
// $columns : The number of columns to suffix.
// $context : [optional] The context (columns spanned by parent).
// : Context is required on any nested elements.
// : Context MUST NOT be declared on a root element.
// $from : The start direction of your layout (e.g. 'left' for ltr languages)
// $style : The container style to use.
@mixin suffix(
$columns,
$context : $total-columns,
$from : $from-direction,
$style : fix-static-misalignment()
) {
$from : unquote($from);
$to : opposite-position($from);
padding-#{$to}: space($columns, $context, $style);
}
// add empty colums as padding before and after an element.
// $columns : The number of columns to pad.
// $context : [optional] The context (columns spanned by parent).
// : Context is required on any nested elements.
// : Context MUST NOT be declared on a root element.
// $from : The start direction of your layout (e.g. 'left' for ltr languages)
// $style : The container style to use.
@mixin pad(
$prefix : false,
$suffix : false,
$context : $total-columns,
$from : $from-direction,
$style : fix-static-misalignment()
) {
$from : unquote($from);
@if $prefix {
@include prefix($prefix, $context, $from, $style);
}
@if $suffix {
@include suffix($suffix, $context, $from, $style);
}
}
// Bleed into colums with margin/padding on any side of an element.
// $width : The side of the bleed.
// : Any unit-length will be used directly.
// : Any unitless number will be used as a column-count.
// : Use "2 of 6" format to represent 2 cals in a 6-col nested context.
// $sides : One or more sides to bleed [ top | right | bottom | left | all ].
// $style : The container style to use.
@mixin bleed(
$width: $grid-padding,
$sides: left right,
$style: fix-static-misalignment()
) {
@if $border-box-sizing { @include box-sizing(content-box) }
@if type-of($width) == 'list' {
$width: filter($width, of);
$width: space(nth($width,1), nth($width,2), $style);
} @else if unitless($width) {
$width: space($width, $style: $style);
}
@if $sides == 'all' {
margin: - $width;
padding: $width;
} @else {
@each $side in $sides {
margin-#{$side}: - $width;
padding-#{$side}: $width;
}
}
}

View File

@ -1,60 +0,0 @@
// ---------------------------------------------------------------------------
// Susy Settings
// The total number of columns in the grid
$total-columns : 12 !default;
// The width of columns and gutters.
// These must all be set with the comparable units.
$column-width : 4em !default;
$gutter-width : 1em !default;
// Padding on the left and right of a Grid Container.
$grid-padding : $gutter-width !default;
// ---------------------------------------------------------------------------
// Advanced Settings
// From Direction:
// Controls for right-to-left or bi-directional sites.
$from-direction : left !default;
// Omega Float Direction:
// The direction that +omega elements are floated by deafult.
$omega-float : opposite-position($from-direction) !default;
// Container Width:
// Override the total width of your grid, using any length (50em, 75%, etc.)
$container-width : false !default;
// Container Style:
// 'magic' - Static (fixed or elastic) when there's enough space,
// fluid when there isn't. This is the SUSY MAGIC SAUCE(TM).
// 'static' - Forces the grid container to remain static at all times.
// 'fluid' - Forces the grid to remain fluid at all times.
// (this will overrule any static $container-width settings)
$container-style : magic !default;
// Border-Box Sizing
// Adjust the grid math appropriately for box-sizing: border-box;
// Warning: This does not actually apply the new box model!
// In most cases you can ignore this setting,
// and simply apply the border-box-sizing mixin.
$border-box-sizing : false !default;
// Pixel Values only:
// Make sure only pixel values are set for the container width.
$pixel-values-only : false !default;
// ---------------------------------------------------------------------------
// IE Settings
// When you are using a seperate IE stylesheet,
// you can use these settings to control the output of at-breakpoint.
// By default, at-breakpoint will output media-queries as well as
// any defined ie-fallback classes.
$breakpoint-media-output : true !default;
$breakpoint-ie-output : true !default;
// Danger Zone! Only set as 'true' in IE-specific style sheets.
$breakpoint-raw-output : false !default;

View File

@ -1,9 +0,0 @@
// Float API
// =========
@import "shared";
@import "float/container";
@import "float/span";
@import "float/end";
@import "float/isolate";

View File

@ -1,15 +0,0 @@
// Shared API
// ==========
@import "support";
@import "shared/inspect";
@import "shared/output";
@import "shared/direction";
@import "shared/background";
@import "shared/container";
@import "shared/margins";
@import "shared/padding";

View File

@ -1,9 +0,0 @@
// Susy Browser Support
// ====================
@import "support/support";
@import "support/prefix";
@import "support/background";
@import "support/box-sizing";
@import "support/rem";
@import "support/clearfix";

View File

@ -1,16 +0,0 @@
// Float Container API
// ===================
// Float Container
// ---------------
// - [$width] : <length>
// - [$justify] : left | center | right
// - [$math] : fluid | static
@mixin float-container(
$width,
$justify: auto auto,
$property: max-width
) {
@include susy-clearfix;
@include container-output($width, $justify, $property);
}

View File

@ -1,40 +0,0 @@
// Float Ends API
// ==============
// Susy End Defaults
// -----------------
// - PRIVATE
@include susy-defaults((
last-flow: to,
));
// Float Last
// ----------
// - [$flow] : ltr | rtl
@mixin float-last(
$flow: map-get($susy-defaults, flow),
$last-flow: map-get($susy-defaults, last-flow),
$margin: 0
) {
$to: to($flow);
$output: (
float: if($last-flow == to, $to, null),
margin-#{$to}: $margin,
);
@include output($output);
}
// Float First
// -----------
// - [$flow] : ltr | rtl
@mixin float-first(
$flow: map-get($susy-defaults, flow)
) {
$output: (
margin-#{from($flow)}: 0,
);
@include output($output);
}

View File

@ -1,22 +0,0 @@
// Float Isolation API
// ===================
// Isolate Output
// --------------
// - $push : <length>
// - [$flow] : ltr | rtl
@mixin isolate-output(
$push,
$flow: map-get($susy-defaults, flow)
) {
$to: to($flow);
$from: from($flow);
$output: (
float: $from,
margin-#{$from}: $push,
margin-#{$to}: -100%,
);
@include output($output);
}

View File

@ -1,35 +0,0 @@
// Float Span API
// ==============
// Float Span Output
// -----------------
// - $width : <length>
// - [$float] : from | to
// - [$margin-before] : <length>
// - [$margin-after] : <length>
// - [$padding-before] : <length>
// - [$padding-after] : <length>
// - [$flow] : ltr | rtl
@mixin float-span-output(
$width,
$float : from,
$margin-before : null,
$margin-after : null,
$padding-before : null,
$padding-after : null,
$flow : map-get($susy-defaults, flow)
) {
$to : to($flow);
$from : from($flow);
$output: (
width: $width,
float: if($float == to, $to, null) or if($float == from, $from, null),
margin-#{$from}: $margin-before,
margin-#{$to}: $margin-after,
padding-#{$from}: $padding-before,
padding-#{$to}: $padding-after,
);
@include output($output);
}

View File

@ -1,26 +0,0 @@
// Grid Background API
// ===================
// - Sub-pixel rounding can lead to several pixels variation between browsers.
// Grid Background Output
// ----------------------
// - $image: background-image
// - $size: background-size
// - $clip: background-clip
// - [$flow]: ltr | rtl
@mixin background-grid-output (
$image,
$size: null,
$clip: null,
$flow: map-get($susy-defaults, flow)
) {
$output: (
background-image: $image,
background-size: $size,
background-origin: $clip,
background-clip: $clip,
background-position: from($flow) top,
);
@include output($output);
}

View File

@ -1,21 +0,0 @@
// Shared Container API
// ====================
// Container Output
// ----------------
// - [$width] : <length>
// - [$justify] : left | center | right
// - [$math] : fluid | static
@mixin container-output(
$width,
$justify: auto auto,
$property: max-width
) {
$output: (
#{$property}: $width or 100%,
margin-left: nth($justify, 1),
margin-right: nth($justify, 2),
);
@include output($output);
}

View File

@ -1,42 +0,0 @@
// Direction Helpers
// =================
// Susy Flow Defaults
// ------------------
// - PRIVATE
@include susy-defaults((
flow: ltr,
));
// Get Direction
// -------------
// Return the 'from' or 'to' direction of a ltr or rtl flow.
// - [$flow] : ltr | rtl
// - [$key] : from | to
@function get-direction(
$flow: map-get($susy-defaults, flow),
$key: from
) {
$return: if($flow == rtl, (from: right, to: left), (from: left, to: right));
@return map-get($return, $key);
}
// To
// --
// Return the 'to' direction of a flow
// - [$flow] : ltr | rtl
@function to(
$flow: map-get($susy-defaults, flow)
) {
@return get-direction($flow, to);
}
// From
// ----
// Return the 'from' direction of a flow
// - [$flow] : ltr | rtl
@function from(
$flow: map-get($susy-defaults, flow)
) {
@return get-direction($flow, from);
}

View File

@ -1,25 +0,0 @@
// Debugging
// =========
// Susy Inspect
// ------------
// Output arguments passed to a inspect.
// - $mixin : <susy mixin>
// - $inspec : <mixin arguments>
@mixin susy-inspect(
$mixin,
$inspect
) {
$show: false;
@each $item in $inspect {
@if index($item, inspect) {
$show: true;
}
}
@if $show or susy-get(debug inspect) {
-susy-#{$mixin}: inspect($inspect);
}
}

View File

@ -1,23 +0,0 @@
// Margins API
// ===========
// Margin Output
// -------------
// - $before : <length>
// - $after : <length>
// - [$flow] : ltr | rtl
@mixin margin-output(
$before,
$after,
$flow: map-get($susy-defaults, flow)
) {
$to: to($flow);
$from: from($flow);
$output: (
margin-#{$from}: $before,
margin-#{$to}: $after,
);
@include output($output);
}

View File

@ -1,14 +0,0 @@
// Output
// ======
// Output
// ------
// Output CSS with proper browser support.
// - $styles : <map of css property-value pairs>
@mixin output(
$styles
) {
@each $prop, $val in $styles {
@include susy-support($prop, $val);
}
}

View File

@ -1,23 +0,0 @@
// Padding API
// ===========
// Padding Output
// --------------
// - $before : <length>
// - $after : <length>
// - [$flow] : ltr | rtl
@mixin padding-output(
$before,
$after,
$flow: map-get($susy-defaults, flow)
) {
$to: to($flow);
$from: from($flow);
$output: (
padding-#{$from}: $before,
padding-#{$to}: $after,
);
@include output($output);
}

View File

@ -1,58 +0,0 @@
// Background Properties
// =====================
// Susy Background Image
// ---------------------
// Check for an existing support mixin, or provide a simple fallback.
// - $image: <background-image>
@mixin susy-background-image(
$image
) {
@if susy-support(background-image, (mixin: background-image), $warn: false) {
@include background-image($image...);
} @else {
background-image: $image;
}
}
// Susy Background Size
// ---------------------
// Check for an existing support mixin, or provide a simple fallback.
// - $image: <background-size>
@mixin susy-background-size(
$size
) {
@if susy-support(background-options, (mixin: background-size)) {
@include background-size($size);
} @else {
background-size: $size;
}
}
// Susy Background Origin
// ----------------------
// Check for an existing support mixin, or provide a simple fallback.
// - $image: <background-origin>
@mixin susy-background-origin(
$origin
) {
@if susy-support(background-options, (mixin: background-origin)) {
@include background-origin($origin);
} @else {
background-origin: $origin;
}
}
// Susy Background Clip
// --------------------
// Check for an existing support mixin, or provide a simple fallback.
// - $image: <background-clip>
@mixin susy-background-clip(
$clip
) {
@if susy-support(background-options, (mixin: background-clip)) {
@include background-clip($clip);
} @else {
background-clip: $clip;
}
}

View File

@ -1,19 +0,0 @@
// Box Sizing
// ==========
// Box Sizing
// ----------
// Check for an existing support mixin, or provide a simple fallback.
// - $model: <box-sizing>
@mixin susy-box-sizing(
$model: content-box
) {
@if $model {
@if susy-support(box-sizing, (mixin: box-sizing), $warn: false) {
@include box-sizing($model);
} @else {
$prefix: (moz, webkit, official);
@include susy-prefix(box-sizing, $model, $prefix);
}
}
}

View File

@ -1,18 +0,0 @@
// Susy Fallback Clearfix
// ======================
// Clearfix
// --------
// Check for an existing support mixin, or provide a simple fallback.
@mixin susy-clearfix {
@if susy-support(clearfix, (mixin: clearfix)) {
@include clearfix;
} @else {
&:after {
content: " ";
display: block;
clear: both;
}
}
}

View File

@ -1,19 +0,0 @@
// Susy Prefix
// ===========
// Prefix
// ------
// Output simple prefixed properties.
// - $prop : <css property>
// - $val : <css value>
// - [$prefix] : <browser prefix list>
@mixin susy-prefix(
$prop,
$val,
$prefix: official
) {
@each $fix in $prefix {
$fix: if($fix == official or not($fix), $prop, '-#{$fix}-#{$prop}');
@include susy-rem($fix, $val);
}
}

View File

@ -1,22 +0,0 @@
// rem Support
// ===========
// rem
// ---
// Check for an existing support mixin, or output directly.
// - $prop : <css property>
// - $val : <css value>
@mixin susy-rem(
$prop,
$val
) {
$_reqs: (
variable: rhythm-unit rem-with-px-fallback,
mixin: rem,
);
@if susy-support(rem, $_reqs, $warn: false) and $rhythm-unit == rem {
@include rem($prop, $val);
} @else {
#{$prop}: $val;
}
}

View File

@ -1,85 +0,0 @@
// Browser Support
// ===============
// Susy Support Defaults
// ---------------------
@include susy-defaults((
use-custom: (
clearfix: false,
background-image: true,
background-options: false,
breakpoint: true,
box-sizing: true,
rem: true,
),
));
// Susy Support [mixin]
// --------------------
// Send property-value pairs to the proper support modules.
// - $prop : <css property>
// - $val : <css value>
@mixin susy-support(
$prop,
$val
) {
// Background Support
@if $prop == background-image {
@include susy-background-image($val);
} @else if $prop == background-size {
@include susy-background-size($val);
} @else if $prop == background-origin {
@include susy-background-origin($val);
} @else if $prop == background-clip {
@include susy-background-clip($val);
}
// Box-Sizing Support
@else if $prop == box-sizing {
@include susy-box-sizing($val);
}
// Rem Support
@else {
@include susy-rem($prop, $val);
}
}
// Susy Support [function]
// -----------------------
// Check for support of a feature.
// - $feature : <string>
// - e.g "rem" or "box-sizing"
// - $requirements : <map>
// - e.g (variable: rem-with-px-fallback, mixin: rem)
// - $warn : <bool>
@function susy-support(
$feature,
$requirements: (),
$warn: true
) {
$_support: susy-get(use-custom $feature);
@if $_support {
$_fail: false;
@each $_type, $_req in $requirements {
@each $_i in $_req {
$_pass: call(unquote("#{$_type}-exists"), $_i);
@if not($_pass) {
$_fail: true;
@if $warn {
@warn "You requested custom support of #{$feature}, but the #{$_i} #{$_type} is not available.";
}
}
}
}
$_support: if($_fail, false, $_support);
}
@return $_support;
}

View File

@ -0,0 +1,5 @@
// SVG Grid Background
// ===================
@import 'svg-grid/prefix';
@import 'svg-grid/svg-unprefix';

View File

@ -0,0 +1,7 @@
// Prefixed SVG Plugin
// ===================
@import 'svg-settings';
@import 'svg-utilities';
@import 'svg-grid-math';
@import 'svg-api';

View File

@ -0,0 +1,114 @@
/// Plugin: SVG Grid Image
/// ======================
/// @group plugin_svg-grid
/// @see susy-svg-grid
/// ## Overview
/// If you want to generate svg-backgrounds
/// for help visualizing and debugging your grids,
/// import the SVG Grid Plugin.
///
/// The plugin adds `svg-grid-colors` setting
/// to your global defaults,
/// which you can override in `$susy`.
/// It also provides you with a new function,
/// `susy-svg-grid()`,
/// which will return inline svg for use in
/// backgrounds or generated content.
///
/// This function come with an unprefixed alias by default,
/// using the `svg-grid` import.
/// If you only only want prefixed versions of the API,
/// import the `svg-grid/prefix` partial instead.
///
/// @group plugin_svg-grid
///
/// @example scss - importing the plugin
/// // The full path to import Susy will depend on your setup
///
/// // unprefixed
/// @import 'plugins/svg-grid';
///
/// // prefixed
/// @import 'plugins/svg-grid/prefix';
///
/// @example scss - generating background grids
/// .grid {
/// background: susy-svg-grid() no-repeat scroll;
/// }
// SVG Grid
// --------
/// Return inline svg-data in to display the grid.
///
/// @group plugin_svg-grid
///
/// @param {Map | List} $grid [$susy] -
/// Map or shorthand defining the current grid
/// @param {Color | List | null} $colors [null] -
/// Column color, or list of colors for column-gradient,
/// used to override the global `svg-grid-colors` setting
/// @param {Length | null} $offset [null] -
/// Manually override the default grid-image offset,
/// to account for grid edges
///
/// @return {String} -
/// CSS inline-data SVG string, in `url(<svg>)` format,
/// for use in image or content properties
/// @example scss
/// .grid {
/// background: susy-svg-grid() no-repeat scroll;
/// }
@function susy-svg-grid(
$grid: $susy,
$colors: null,
$offset: null
) {
// Grid parsing & normalizing
$grid: susy-compile($grid, $context-only: true);
// Color and gradient handling
$gradient: '';
@if (not $colors) {
$colors: susy-get('svg-grid-colors');
}
@if length($colors) > 1 {
$gradient: _susy-svg-gradient($colors);
$colors: 'url(%23susy-svg-gradient)';
} @else {
$colors: _susy-svg-color($colors);
}
// Get a default image-width
$span: (
'span': map-get($grid, 'columns'),
'spread': map-get($grid, 'container-spread'),
);
$span: map-merge($grid, $span);
$image-width: su-call('su-span', $span);
$image-width: if((type-of($image-width) == 'number'), $image-width, 100%);
// SVG construction
$columns: map-get($grid, 'columns');
$offset: $offset or _susy-svg-offset($grid);
$attrs: 'fill="#{$colors}" width="#{$image-width}"';
$svg: 'data:image/svg+xml,';
$svg: $svg + '%3Csvg xmlns="http://www.w3.org/2000/svg" #{$attrs} %3E';
$svg: $svg + $gradient;
@for $column from 1 through length($columns) {
$width: susy-span(1 narrow at $column, $grid);
$x: _susy-svg-column-position($column, $grid);
$svg: $svg + _susy-svg-rect($x, $width, $offset);
}
@return url('#{$svg}%3C/svg%3E');
}

View File

@ -0,0 +1,67 @@
// SVG Grid Math
// =============
// SVG Column Position
// -------------------
/// Determine the proper horizontal position
/// for a column rectangle
///
/// @access private
///
/// @param {Integer} $column -
/// 1-indexed column location on the grid
/// @param {Map} $grid -
/// Normalized settings map representing the current grid
///
/// @return {Length} -
/// Horizontal position of svg column rectangle,
/// as distance from the grid edge
@function _susy-svg-column-position(
$column,
$grid
) {
$x: $column - 1;
@if ($x > 0) {
$x: susy-span(first $x wide, $grid);
}
@return $x;
}
// SVG Offset
// ----------
/// Determine if a grid image needs to be offset,
/// to account for edge gutters.
///
/// @access private
///
/// @param {Map} $grid -
/// Normalized settings map representing the current grid
///
/// @return {Length | null} -
/// Expected distance from container edge to first column,
/// based on spread values and gutter-widths
@function _susy-svg-offset(
$grid
) {
$columns: su-valid-columns(map-get($grid, 'columns'));
$gutters: su-valid-gutters(map-get($grid, 'gutters'));
$container: su-valid-spread(map-get($grid, 'container-spread')) + 1;
@if ($container == 0) {
@return null;
}
$gutter: su-call('su-gutter', $grid);
@if (type-of($gutter) == 'string') {
@return 'calc(#{$container} * #{$gutter} / 2)';
}
@return $container * $gutter / 2;
}

View File

@ -0,0 +1,14 @@
// SVG Settings
// ============
// Susy SVG Defaults
// =================
/// This plugin adds the `svg-grid-colors` property
/// and default value to `$_susy-defaults`
/// you can override that value in `$susy`
/// or any other grid settings map.
/// @group plugin_svg-grid
$_susy-defaults: map-merge((
'svg-grid-colors': hsla(120, 50%, 50%, 0.5) hsla(120, 50%, 75%, 0.5),
), $_susy-defaults);

View File

@ -0,0 +1,18 @@
// Unprefix Susy SVG Grid
// ======================
// SVG Grid
// --------
/// Un-prefixed alias for `susy-svg-grid`
///
/// @group plugin_svg-grid
/// @alias susy-svg-grid
@function svg-grid(
$grid: $susy,
$colors: susy-get('svg-grid-colors'),
$offset: null
) {
@return susy-svg-grid($grid, $colors, $offset);
}

View File

@ -0,0 +1,133 @@
// SVG Utilities
// =============
// SVG Validate Units
// ------------------
/// Make sure a length is supported in svg
///
/// @access private
///
/// @param {Length} $length -
/// The length to validate
/// @param {String} $name [null] -
/// Optional name of length origin,
/// for error reporting
///
/// @return {Length} -
/// An svg-validated length, or comparable valid length
@function _susy-svg-validate-units(
$length,
$name: null
) {
$_svg-units: ('em', 'ex', 'px', 'pt', 'pc', 'cm', 'mm', 'in', '%');
$string: type-of($length) == 'string';
@if ($length == 0) or ($string) or index($_svg-units, unit($length)) {
@return $length;
}
@return _susy-error(
'`#{unit($length)}` #{$name} units are not supported in SVG',
'_susy-svg-validate-units');
}
// SVG Rect
// --------
/// Build a single svg rectangle
///
/// @access private
///
/// @param {Length} $x -
/// Horizontal position for the rectangle
/// @param {Length} $width -
/// Width of the rectangle
/// @param {Length} $offset [null] -
/// Offset the rectangle, to account for edge gutters
///
/// @return {String} -
/// Escaped string representing one svg rectangle
@function _susy-svg-rect(
$x,
$width,
$offset: null
) {
$x: _susy-svg-validate-units($x);
$width: _susy-svg-validate-units($width);
$offset: if($offset == 0, null, $offset);
@if (type-of($offset) == 'number') and (type-of($x) == 'number') {
@if comparable($x, $offset) {
$x: $x + $offset;
} @else {
$x: 'calc(#{$x} + #{$offset})';
}
} @else if $offset and ($x != 0) {
$x: 'calc(#{$x} + #{$offset})';
} @else if $offset {
$x: $offset;
}
@return '%3Crect x="#{$x}" width="#{$width}" height="100%"/%3E';
}
// SVG Color
// ---------
/// Stringify colors, and escape hex symbol
///
/// @access private
///
/// @param {Color} $color -
/// Color to stringify and escape
///
/// @return {String} -
/// Escaped string value of color
@function _susy-svg-color(
$color
) {
$color: inspect($color); // convert to string
@if (str-index($color, '#') == 1) {
$color: '%23' + str-slice($color, 2);
}
@return $color;
}
// SVG Gradient
// ------------
/// Create a multi-color svg gradient
///
/// @access private
///
/// @param {List} $colors -
/// List of colors to be equally spaced from `0%` to `100%`
/// in each column rectangle
///
/// @return {String} -
/// Escaped string representing one svg gradient
/// (`id="susy-svg-gradient"`)
@function _susy-svg-gradient(
$colors
) {
$gradient: '%3Cdefs%3E%3ClinearGradient spreadMethod="pad"';
$gradient: '#{$gradient} id="susy-svg-gradient"';
$gradient: '#{$gradient} x1="0%" y1="0%" x2="100%" y2="0%"%3E';
@for $i from 1 through length($colors) {
$color: _susy-svg-color(nth($colors, $i));
$offset: percentage(($i - 1) / (length($colors) - 1));
$stop: '%3Cstop offset="#{$offset}" style="stop-color:#{$color};" /%3E';
$gradient: $gradient + $stop;
}
@return $gradient + '%3C/linearGradient%3E%3C/defs%3E';
}

View File

@ -1,103 +0,0 @@
// Column math
// ===========
// Is Symmetrical
// --------------
// Returns true if a grid is symmetrical.
// - [$columns] : <number> | <list>
@function is-symmetrical(
$columns: susy-get(columns)
) {
$columns: valid-columns($columns);
@return if(type-of($columns) == number, $columns, null);
}
// Susy Count
// ----------
// Find the number of columns in a given layout
// - [$columns] : <number> | <list>
@function susy-count(
$columns: susy-get(columns)
) {
$columns: valid-columns($columns);
@return is-symmetrical($columns) or length($columns);
}
// Susy Sum
// --------
// Find the total sum of column-units in a layout
// - [$columns] : <number> | <list>
// - [$gutters] : <ratio>
// - [$spread] : false/narrow | wide | wider
@function susy-sum(
$columns : susy-get(columns),
$gutters : susy-get(gutters),
$spread : false
) {
$columns: valid-columns($columns);
$gutters: valid-gutters($gutters);
$spread: if($spread == wide, 0, if($spread == wider, 1, -1));
$gutter-sum: (susy-count($columns) + $spread) * $gutters;
$column-sum: is-symmetrical($columns);
@if not($column-sum) {
@each $column in $columns {
$column-sum: ($column-sum or 0) + $column;
}
}
@return $column-sum + $gutter-sum;
}
// Susy Slice
// ----------
// Return a subset of columns at a given location.
// - $span : <number>
// - $location : <number>
// - [$columns] : <number> | <list>
@function susy-slice(
$span,
$location,
$columns: susy-get(columns)
) {
$columns: valid-columns($columns);
$sub-columns: $span;
@if not(is-symmetrical($columns)) {
$location: $location or 1;
$sub-columns: ();
@for $i from $location to ($location + $span) {
$sub-columns: append($sub-columns, nth($columns, $i));
}
}
@return $sub-columns;
}
// Susy
// ----
// Find the sum of a column-span.
// - $span : <number>
// - $location : <number>
// - [$columns] : <number> | <list>
// - [$gutters] : <ratio>
// - [$spread] : false/narrow | wide | wider
@function susy(
$span,
$location : false,
$columns : susy-get(columns),
$gutters : susy-get(gutters),
$spread : false
) {
$columns: valid-columns($columns);
$gutters: valid-gutters($gutters);
$span: susy-slice($span, $location, $columns);
@return susy-sum($span, $gutters, $spread);
}

View File

@ -1,73 +0,0 @@
// Settings
// ========
// Version
// -------
$su-version: 1.1;
// Default Settings
// ----------------
// PRIVATE: The basic settings
$susy-defaults: (
columns: 4,
gutters: .25,
);
// User Settings
// -------------
// - Define the $susy variable with a map of your own settings.
// - Set EITHER $column-width OR $container
// - Use $column-width for static layouts
$susy: () !default;
// Susy Defaults
// -------------
// PRIVATE: Add defaults to Susy
@mixin susy-defaults(
$defaults
) {
$susy-defaults: map-merge($susy-defaults, $defaults) !global;
}
// Susy Set
// --------
// Change one setting
// - $key : setting name
// - $value : setting value
@mixin susy-set(
$key-value...
) {
$susy: _susy-deep-set($susy, $key-value...) !global;
}
// Susy Get
// --------
// Return one setting from a grid
// - $key : <keyword>
// - $layout : <settings>
@function susy-get(
$key,
$layout: map-merge($susy-defaults, $susy)
) {
$layout: parse-grid($layout);
$_options: $layout $susy $susy-defaults;
$_break: false;
$_return: null;
@each $opt in $_options {
@if type-of($opt) == map and not($_break) {
$_keyset: _susy-deep-has-key($opt, $key...);
@if $_keyset {
$_return: _susy-deep-get($opt, $key...);
$_break: true;
}
}
}
@return $_return;
}

View File

@ -1,111 +0,0 @@
// Map Functions
// =============
// Truncate List
// -------------
// - Return a list, truncated to a given length
@function _susy-truncate-list(
$list,
$length
) {
$_return: ();
@for $i from 1 through length($list) {
$_return: if($i <= $length, append($_return, nth($list, $i)), $_return);
}
@return $_return;
}
// Deep Get
// --------
// - Return a value deep in nested maps
@function _susy-deep-get(
$map,
$keys...
) {
$_return: $map;
@each $key in $keys {
@if type-of($_return) == map {
$_return: map-get($_return, $key);
}
}
@return $_return;
}
// Deep Set
// --------
// - Set a value deep in nested maps
@function _susy-deep-set(
$map,
$keys-value...
) {
$_value: nth($keys-value, -1);
$_keys: _susy-truncate-list($keys-value, length($keys-value) - 1);
$_length: length($_keys);
$_return: ();
@for $i from 1 through $_length {
$_n: 0 - $i;
$_level: _susy-truncate-list($_keys, $_length + $_n);
$_level: _susy-deep-get($map, $_level...);
$_merge: nth($_keys, $_n);
$_merge: ($_merge: $_value);
$_return: if($_level, map-merge($_level, $_merge), $_merge);
$_value: $_return;
}
@return $_return;
}
// Deep Merge
// ----------
// Return 2 objects of any depth, merged
@function _susy-deep-merge(
$map1,
$map2
) {
@if type-of($map1) != map or type-of($map2) != map {
$map1: $map2;
} @else {
@each $key, $value in $map2 {
$_new: ($key: _susy_deep-merge(map-get($map1, $key), $value));
$map1: map-merge($map1, $_new);
}
}
@return $map1;
}
// Deep Has-Key
// ------------
// - Return true if a deep key exists
@function _susy-deep-has-key(
$map,
$keys...
) {
$_return: null;
$_stop: false;
@each $key in $keys {
@if not($_stop) {
$_return: map-has-key($map, $key);
}
@if $_return {
$map: map-get($map, $key);
} @else {
$_stop: true;
}
}
@return $_return;
}

View File

@ -1,57 +0,0 @@
// Math Validation
// ===============
// Valid Columns
// -------------
// Check that a column setting is valid.
@function valid-columns(
$columns,
$silent: false
) {
$type: type-of($columns);
$return: null;
@if $type == number and unitless($columns) {
$return: $columns;
} @else if $type == list {
$fail: null;
@each $col in $columns {
@if type-of($col) == number {
$fail: $fail or if(unitless($col), null, true);
} @else {
$fail: true;
}
}
$return: if($fail, $return, $columns);
}
@if $return != $columns and not($silent) {
$return: null;
$warn: '$columns must be a unitless number or list of unitless numbers.';
@warn $warn + ' Current value [#{$type}]: #{$columns}';
}
@return $return;
}
// Valid Gutters
// -------------
// Check that a gutter setting is valid.
@function valid-gutters(
$gutters,
$silent: false
) {
$type: type-of($gutters);
$return: null;
@if $type == number and unitless($gutters) {
$return: $gutters;
} @else if not($silent) {
$warn: '$gutters must be a unitless number.';
@warn $warn + ' Current value [#{$type}]: #{$gutters}';
}
@return $return;
}

View File

@ -0,0 +1,318 @@
/// Susy3 API Functions
/// ===================
/// These three functions form the core of Susy's
/// layout-building grid API.
///
/// - Use `span()` and `gutter()` to return any grid-width,
/// and apply the results wherever you need them:
/// CSS `width`, `margin`, `padding`, `flex-basis`, `transform`, etc.
/// - For asymmetrical-fluid grids,
/// `slice()` can help manage your nesting context.
///
/// All three functions come with an unprefixed alias by default,
/// using the `susy` import.
/// Import the `susy-prefix` partial instead,
/// if you only only want prefixed versions of the API.
///
/// This is a thin syntax-sugar shell around
/// the "Su" core-math functions: `su-span`, `su-gutter`, and `su-slice`.
/// If you prefer the more constrained syntax of the math engine,
/// you are welcome to use those functions instead.
///
/// @group b-api
/// @see susy-span
/// @see susy-gutter
/// @see susy-slice
/// @see su-span
/// @see su-gutter
/// @see su-slice
/// ## Shorthand
///
/// All functions draw on the same shorthand syntax in two parts,
/// seperated by the word `of`.
///
/// ### Span Syntax: `<width>` [`<location>` `<spread>`]
/// The first part describes the
/// **span** width, location, and spread in any order.
/// Only the width is required:
///
/// - `span(2)` will return the width of 2 columns.
/// - `span(3 wide)` will return 3-columns, with an additional gutter.
/// - location is only needed with asymmetrical grids,
/// where `span(3 at 2)` will return the width of
/// specific columns on the grid.
/// Since these are functions, they will not handle placement for you.
///
/// ### Context Syntax: `[of <columns> <container-spread> <gutters>]`
/// The second half of Susy's shorthand
/// describes the grid-**context**
/// available columns, container-spread, and optional gutter override
/// in any order.
/// All of these settings have globally-defined defaults:
///
/// - `span(2 of 6)` will set the context to
/// a slice of 6 columns from the global grid.
/// More details below.
/// - `span(2 of 12 wide)` changes the container-spread
/// as well as the column-context.
/// - `span(2 of 12 set-gutters 0.5em)`
/// will override the global gutters setting
/// for this one calculation.
///
/// A single unitless number for `columns`
/// will be treated as a slice of the parent grid.
/// On a grid with `columns: susy-repeat(12, 120px)`,
/// the shorthand `of 4` will use the parent `120px` column-width.
/// You can also be more explicit,
/// and say `of susy-repeat(4, 100px)`.
/// If you are using asymmetrical grids,
/// like `columns: (1 1 2 3 5 8)`,
/// Susy can't slice it for you without knowing which columns you want.
/// The `slice` function accepts exactly the same syntax as `span`,
/// but returns a list of columns rather than a width.
/// Use it in your context like `of slice(first 3)`.
///
/// @group b-api
// Susy Span
// ---------
/// This is the primary function in Susy
/// used to return the width of a span across one or more columns,
/// and any relevant gutters along the way.
/// With the default settings,
/// `span(3)` will return the width of 3 columns,
/// and the 2 intermediate gutters.
/// This can be used to set the `width` property of grid elements,
/// or `margin` and `padding`
/// to push, pull, and pad your elements.
///
/// - This is a thin syntax-sugar shell around
/// the core-math `su-span()` function.
/// - The un-prefixed alias `span()` is available by default.
///
/// @group b-api
/// @see su-span
/// @see $susy
///
/// @param {list} $span -
/// Shorthand expression to define the width of the span,
/// optionally containing:
/// - a count, length, or column-list span.
/// - `at $n`, `first`, or `last` location on asymmetrical grids,
/// where `at 1 == first`,
/// and `last` will calculate the proper location
/// based on columns and span.
/// - `narrow`, `wide`, or `wider` for optionally spreading
/// across adjacent gutters.
/// - `of $n <spread>` for available grid columns
/// and spread of the container.
/// Span counts like `of 6` are valid
/// in the context of symmetrical grids,
/// where Susy can safely infer a slice of the parent columns.
/// - and `set-gutters $n` to override global gutter settings.
///
/// @param {map} $config [()] -
/// Optional map of Susy grid configuration settings.
/// See `$susy` documentation for details.
///
/// @return {length} -
/// Calculated length value, using the units given,
/// or converting to `%` for fraction-based grids,
/// or a full `calc` function when units/fractions
/// are not comparable outside the browser.
///
/// @example scss - span half the grid
/// .foo {
/// // the result is a bit under 50% to account for gutters
/// width: susy-span(6 of 12);
/// }
///
/// @example scss - span a specific segment of asymmetrical grid
/// .foo {
/// width: susy-span(3 at 3 of (1 2 3 5 8));
/// }
@function susy-span(
$span,
$config: ()
) {
$output: susy-compile($span, $config);
@if map-get($output, 'span') {
@return su-call('su-span', $output);
}
$actual: '[#{type-of($span)}] `#{inspect($span)}`';
@return _susy-error(
'Unable to determine span value from #{$actual}.',
'susy-span');
}
// Susy Gutter
// -----------
/// The gutter function returns
/// the width of a single gutter on your grid,
/// to be applied where you see fit
/// on `margins`, `padding`, `transform`, or element `width`.
///
/// - This is a thin syntax-sugar shell around
/// the core-math `su-gutter()` function.
/// - The un-prefixed alias `gutter()` is available by default.
///
/// @group b-api
/// @see su-gutter
/// @see $susy
///
/// @param {list | number} $context [null] -
/// Optional context for nested gutters,
/// including shorthand for
/// `columns`, `gutters`, and `container-spread`
/// (additional shorthand will be ignored)
///
/// @param {map} $config [()] -
/// Optional map of Susy grid configuration settings.
/// See `$susy` documentation for details.
///
/// @return {length} -
/// Width of a gutter as `%` of current context,
/// or in the units defined by `column-width` when available
///
/// @example scss - add gutters before or after an element
/// .floats {
/// float: left;
/// width: span(3 of 6);
/// margin-left: gutter(of 6);
/// }
///
/// @example scss - add gutters to padding
/// .flexbox {
/// flex: 1 1 span(3 wide of 6 wide);
/// padding: gutter(of 6) / 2;
/// }
///
@function susy-gutter(
$context: susy-get('columns'),
$config: ()
) {
$context: susy-compile($context, $config, 'context-only');
@return su-call('su-gutter', $context);
}
// Susy Slice
// ----------
/// Working with asymmetrical grids (un-equal column widths)
/// can be challenging  
/// expecially when they involve fluid/fractional elements.
/// Describing a context `of (15em 6em 6em 6em 15em)` is a lot
/// to put inside the span or gutter function shorthand.
/// This slice function returns a sub-slice of asymmetrical columns to use
/// for a nested context.
/// `slice(3 at 2)` will give you a subset of the global grid,
/// spanning 3 columns, starting with the second.
///
/// - This is a thin syntax-sugar shell around
/// the core-math `su-slice()` function.
/// - The un-prefixed alias `slice()` is available by default.
///
/// @group b-api
/// @see su-slice
/// @see $susy
///
/// @param {list} $span -
/// Shorthand expression to define the subset span, optionally containing:
/// - `at $n`, `first`, or `last` location on asymmetrical grids;
/// - `of $n <spread>` for available grid columns
/// and spread of the container
/// - Span-counts like `of 6` are only valid
/// in the context of symmetrical grids
/// - Valid spreads include `narrow`, `wide`, or `wider`
///
/// @param {map} $config [()] -
/// Optional map of Susy grid configuration settings.
/// See `$susy` documentation for details.
///
/// @return {list} -
/// Subset list of columns for use for a nested context
///
/// @example scss - Return a nested segment of asymmetrical grid
/// $context: susy-slice(3 at 3 of (1 2 3 5 8));
/// /* $context: #{$context}; */
@function susy-slice(
$span,
$config: ()
) {
$span: susy-compile($span, $config);
@return su-call('su-slice', $span);
}
/// ## Building Grids
/// The web has come a long way
/// since the days of double-margin-hacks
/// and inconsistent subpixel rounding.
/// In addition to floats and tables,
/// we can now use much more powerful tools,
/// like flexbox and CSS grid,
/// to build more interesting and responsive layouts.
///
/// With Susy3, we hope you'll start moving in that direction.
/// You can still build classic 12-column Grid Systems,
/// and we'll help you get there,
/// but Susy3 is primarily designed for a grid-math-on-demand
/// approach to layout:
/// applying our functions only where you really need grid math.
/// Read the [intro article by OddBird][welcome] for more details.
///
/// [welcome]: http://oddbird.net/2017/06/28/susy3/
///
/// @group b-api
/// @link http://oddbird.net/2017/06/28/susy3/ Article: Welcome to Susy3
///
/// @example scss - floats
/// .float {
/// width: span(3);
/// margin-right: gutter();
/// }
///
/// @example scss - flexbox
/// .flexbox {
/// flex: 1 1 span(3);
/// // half a gutter on either side
/// padding: 0 gutter() / 2;
/// }
///
/// @example scss - pushing and pulling
/// .push-3 {
/// margin-left: span(3 wide);
/// }
///
/// .pull-3 {
/// margin-left: 0 - span(3 wide);
/// }
///
/// @example scss - building an attribute system
/// // markup example: <div data-span="last 3"></div>
/// [data-span] {
/// float: left;
///
/// &:not([data-span*='last']) {
/// margin-right: gutter();
/// }
/// }
///
/// @for $span from 1 through length(susy-get('columns')) {
/// [data-span*='#{$span}'] {
/// width: span($span);
/// }
/// }

View File

@ -0,0 +1,261 @@
/// Syntax Normalization
/// ====================
/// Susy is divided into two layers:
/// "Su" provides the core math functions with a stripped-down syntax,
/// while "Susy" adds global settings, shorthand syntax,
/// and other helpers.
/// Each setting (e.g. span, location, columns, spread, etc.)
/// has a single canonical syntax in Su.
///
/// This normalization module helps translate between those layers,
/// transforming parsed Susy input into
/// values that Su will understand.
///
/// @group x-normal
///
/// @see susy-normalize
/// @see susy-normalize-span
/// @see susy-normalize-columns
/// @see susy-normalize-spread
/// @see susy-normalize-location
// Susy Normalize
// --------------
/// Normalize the values in a configuration map.
/// In addition to the global `$susy` properties,
/// this map can include local span-related imformation,
/// like `span` and `location`.
///
/// Normalization does not check that values are valid,
/// which will happen in the Su math layer.
/// These functions merely look for known Susy syntax
/// returning a map with those shorthand values
/// converted into low-level data for Su.
/// For example `span: all` and `location: first`
/// will be converted into specific numbers.
///
/// @group x-normal
/// @see $susy
/// @see susy-parse
///
/// @param {map} $config -
/// Map of Susy configuration settings to normalize.
/// See `$susy` and `susy-parse()` documentation for details.
/// @param {map | null} $context [null] -
/// Map of Susy configuration settings to use as global reference,
/// or `null` to use global settings.
///
/// @return {map} -
/// Map of Susy configuration settings,
/// with all values normalized for Su math functions.
@function susy-normalize(
$config,
$context: null
) {
// Spread
@each $setting in ('spread', 'container-spread') {
$value: map-get($config, $setting);
@if $value {
$value: susy-normalize-spread($value);
$config: map-merge($config, ($setting: $value));
}
}
// Columns
$columns: map-get($config, 'columns');
@if $columns {
$columns: susy-normalize-columns($columns, $context);
$config: map-merge($config, ('columns': $columns));
}
@if not $columns {
$map: type-of($context) == 'map';
$columns: if($map, map-get($context, 'columns'), null);
$columns: $columns or susy-get('columns');
}
// Span
$span: map-get($config, 'span');
@if $span {
$span: susy-normalize-span($span, $columns);
$config: map-merge($config, ('span': $span));
}
// Location
$location: map-get($config, 'location');
@if $location {
$location: susy-normalize-location($span, $location, $columns);
$config: map-merge($config, ('location': $location));
}
@return $config;
}
// Normalize Span
// --------------
/// Normalize `span` shorthand for Su.
/// Su span syntax allows an explicit length (e.g. `3em`),
/// unitless column-span number (e.g. `3` columns),
/// or an explicit list of columns (e.g. `(3 5 8)`).
///
/// Susy span syntax also allows the `all` keyword,
/// which will be converted to a slice of the context
/// in normalization.
///
/// @group x-normal
///
/// @param {number | list | 'all'} $span -
/// Span value to normalize.
/// @param {list} $columns -
/// Normalized list of columns in the grid
///
/// @return {number | list} -
/// Number or list value for `$span`
@function susy-normalize-span(
$span,
$columns: susy-get('columns')
) {
@if ($span == 'all') {
@return length($columns);
}
@return $span;
}
// Normalize Columns
// -----------------
/// Normalize `column` shorthand for Su.
/// Su column syntax only allows column lists (e.g. `120px 1 1 1 120px`).
///
/// Susy span syntax also allows a unitless `slice` number (e.g `of 5`),
/// which will be converted to a slice of the context
/// in normalization.
///
/// @group x-normal
///
/// @param {list | integer} $columns -
/// List of available columns,
/// or unitless integer representing a slice of
/// the available context.
/// @param {map | null} $context [null] -
/// Map of Susy configuration settings to use as global reference,
/// or `null` to access global settings.
///
/// @return {list} -
/// Columns list value, normalized for Su input.
///
/// @throws
/// when attempting to access a slice of asymmetrical context
@function susy-normalize-columns(
$columns,
$context: null
) {
$context: $context or susy-settings();
@if type-of($columns) == 'list' {
@return _susy-flatten($columns);
}
@if (type-of($columns) == 'number') and (unitless($columns)) {
$span: $columns;
$context: map-get($context, 'columns');
$symmetrical: susy-repeat(length($context), nth($context, 1));
@if ($context == $symmetrical) {
@return susy-repeat($span, nth($context, 1));
} @else {
$actual: 'of `#{$span}`';
$columns: 'grid-columns `#{$context}`';
@return _susy-error(
'context-slice #{$actual} can not be determined based on #{$columns}.',
'susy-normalize-columns');
}
}
@return $columns;
}
// Normalize Spread
// ----------------
/// Normalize `spread` shorthand for Su.
/// Su spread syntax only allows the numbers `-1`, `0`, or `1`
/// representing the number of gutters covered
/// in relation to columns spanned.
///
/// Susy spread syntax also allows keywords for each value
/// `narrow` for `-1`, `wide` for `0`, or `wider` for `1`
/// which will be converted to their respective integers
/// in normalization.
///
/// @group x-normal
///
/// @param {0 | 1 | -1 | 'narrow' | 'wide' | 'wider'} $spread -
/// Spread across adjacent gutters, relative to a column-count
/// either `narrow` (-1), `wide` (0), or `wider` (1)
///
/// @return {number} -
/// Numeric value for `$spread`
@function susy-normalize-spread(
$spread
) {
$normal-spread: (
'narrow': -1,
'wide': 0,
'wider': 1,
);
@return map-get($normal-spread, $spread) or $spread;
}
// Normalize Location
// ------------------
/// Normalize `location` shorthand for Su.
/// Su location syntax requires the (1-indexed) number for a column.
///
/// Susy also allows the `first` and `last` keywords,
/// where `first` is always `1`,
/// and `last` is calculated based on span and column values.
/// Both keywords are normalized into an integer index
/// in normalization.
///
/// @group x-normal
///
/// @param {number} $span -
/// Number of grid-columns to be spanned
/// @param {integer | 'first' | 'last'} $location -
/// Starting (1-indexed) column position of a span,
/// or a named location keyword.
/// @param {list} $columns -
/// Already-normalized list of columns in the grid.
///
/// @return {integer} -
/// Numeric value for `$location`
@function susy-normalize-location(
$span,
$location,
$columns
) {
$count: length($columns);
$normal-locations: (
'first': 1,
'alpha': 1,
'last': $count - $span + 1,
'omega': $count - $span + 1,
);
@return map-get($normal-locations, $location) or $location;
}

View File

@ -0,0 +1,163 @@
/// Shorthand Syntax Parser
/// =======================
/// The syntax parser converts [shorthand syntax][short]
/// into a map of settings that can be compared/merged with
/// other config maps and global setting.
///
/// [short]: b-api.html
///
/// @group x-parser
// Parse
// -----
/// The `parse` function provides all the syntax-sugar in Susy,
/// converting user shorthand
/// into a usable map of keys and values
/// that can be normalized and passed to Su.
///
/// @group x-parser
/// @see $susy
///
/// @param {list} $shorthand -
/// Shorthand expression to define the width of the span,
/// optionally containing:
/// - a count, length, or column-list span;
/// - `at $n`, `first`, or `last` location on asymmetrical grids;
/// - `narrow`, `wide`, or `wider` for optionally spreading
/// across adjacent gutters;
/// - `of $n <spread>` for available grid columns
/// and spread of the container
/// (span counts like `of 6` are only valid
/// in the context of symmetrical grids);
/// - and `set-gutters $n` to override global gutter settings
/// @param {bool} $context-only [false] -
/// Allow the parser to ignore span and span-spread values,
/// only parsing context and container-spread.
/// This makes it possible to accept spanless values,
/// like the `gutters()` syntax.
/// When parsing context-only,
/// the `of` indicator is optional.
///
/// @return {map} -
/// Map of span and grid settings
/// parsed from shorthand input
/// including all the properties available globally
/// `columns`, `gutters`, `spread`, `container-spread`
/// along with the span-specific properties
/// `span`, and `location`.
///
/// @throw
/// when a shorthand value is not recognized
@function susy-parse(
$shorthand,
$context-only: false
) {
$parse-error: 'Unknown shorthand property:';
$options: (
'first': 'location',
'last': 'location',
'alpha': 'location',
'omega': 'location',
'narrow': 'spread',
'wide': 'spread',
'wider': 'spread',
);
$return: ();
$span: null;
$columns: null;
$of: null;
$next: false;
// Allow context-only shorthand, without span
@if ($context-only) and (not index($shorthand, 'of')) {
@if su-valid-columns($shorthand, 'fail-silent') {
$shorthand: 'of' $shorthand;
} @else {
$shorthand: join('of', $shorthand);
}
}
// loop through the shorthand list
@for $i from 1 through length($shorthand) {
$item: nth($shorthand, $i);
$type: type-of($item);
$error: false;
$details: '[#{$type}] `#{$item}`';
// if we know what's supposed to be coming next…
@if $next {
// Add to the return map
$return: map-merge($return, ($next: $item));
// Reset next to `false`
$next: false;
} @else { // If we don't know what's supposed to be coming
// Keywords
@if ($type == 'string') {
// Check the map for keywords
@if map-has-key($options, $item) {
$setting: map-get($options, $item);
// Spread could be on the span or the container
@if ($setting == 'spread') and ($of) {
$return: map-merge($return, ('container-spread': $item));
} @else {
$return: map-merge($return, ($setting: $item));
}
} @else if ($item == 'all') {
// `All` is a span shortcut
$span: 'all';
} @else if ($item == 'at') {
// Some keywords setup what's next…
$next: 'location';
} @else if ($item == 'set-gutters') {
$next: 'gutters';
} @else if ($item == 'of') {
$of: true;
} @else {
$error: true;
}
} @else if ($type == 'number') or ($type == 'list') { // Numbers & lists
@if not ($span or $of) {
// We don't have a span, and we're not expecting context
$span: $item;
} @else if ($of) and (not $columns) {
// We are expecting context
$columns: $item;
} @else {
$error: true;
}
} @else {
$error: true;
}
}
@if $error {
@return _susy-error('#{$parse-error} #{$details}', 'susy-parse');
}
}
// If we have span, merge it in
@if $span {
$return: map-merge($return, ('span': $span));
}
// If we have columns, merge them in
@if $columns {
$return: map-merge($return, ('columns': $columns));
}
// Return the map of settings
@return $return;
}

View File

@ -0,0 +1,329 @@
/// Susy3 Configuration
/// ===================
/// Susy3 has 4 core settings, in a single settings map.
/// You'll notice a few differences from Susy2:
///
/// **Columns** no longer accept a single number, like `12`,
/// but use a syntax more similar to the new
/// CSS [grid-template-columns][columns]
/// a list of relative sizes for each column on the grid.
/// Unitless numbers in Susy act very similar to `fr` units in CSS,
/// and the `susy-repeat()` function (similar to the css `repeat()`)
/// helps quickly establish equal-width columns.
///
/// [columns]: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns
///
/// - `susy-repeat(12)` will create 12 fluid, equal-width columns
/// - `susy-repeat(6, 120px)` will create 6 equal `120px`-wide columns
/// - `120px susy-repeat(4) 120px` will create 6 columns,
/// the first and last are `120px`,
/// while the middle 4 are equal fractions of the remainder.
/// Susy will output `calc()` values in order to achieve this.
///
/// **Gutters** haven't changed
/// a single fraction or explicit width
/// but the `calc()` output feature
/// means you can now use any combination of units and fractions
/// to create static-gutters on a fluid grid, etc.
///
/// **Spread** existed in the Susy2 API as a span option,
/// and was otherwise handled behind the scenes.
/// Now we're giving you full control over all spread issues.
/// You can find a more [detailed explanation of spread on the blog][spread].
///
/// [spread]: http://oddbird.net/2017/06/13/susy-spread/
///
/// You can access your global settings at any time
/// with the `susy-settings()` function,
/// or grab a single setting from the global scope
/// with `susy-get('columns')`, `susy-get('gutters')` etc.
///
/// @group a-config
/// @link http://oddbird.net/2017/06/13/susy-spread/
/// Article: Understanding Spread in Susy3
///
/// @see $susy
/// @see susy-settings
/// @see susy-get
// Susy
// ----
/// The grid is defined in a single map variable,
/// with four initial properties:
/// `columns`, `gutters`, `spread` and `container-spread`.
/// Anything you put in the root `$susy` variable map
/// will be treated as a global project default.
/// You can create similar configuration maps
/// under different variable names,
/// to override the defaults as-needed.
///
/// @group a-config
/// @type Map
///
/// @see $_susy-defaults
/// @see {function} susy-repeat
/// @link
/// https://codepen.io/mirisuzanne/pen/EgmJJp?editors=1100
/// Spread examples on CodePen
///
/// @prop {list} columns -
/// Columns are described by a list of numbers,
/// representing the relative width of each column.
/// The syntax is a simplified version of CSS native
/// `grid-template-columns`,
/// expecting a list of grid-column widths.
/// Unitless numbers create fractional fluid columns
/// (similar to the CSS-native `fr` unit),
/// while length values (united numbers)
/// are used to define static columns.
/// You can mix-and match units and fractions,
/// to create a mixed grid.
/// Susy will generate `calc()` values when necessary,
/// to make all your units work together.
///
/// Use the `susy-repeat($count, $value)` function
/// to more easily repetative columns,
/// similar to the CSS-native `repeat()`.
///
/// - `susy-repeat(8)`:
/// an 8-column, symmetrical, fluid grid.
/// <br />Identical to `(1 1 1 1 1 1 1 1)`.
/// - `susy-repeat(6, 8em)`:
/// a 6-column, symmetrical, em-based grid.
/// <br />Identical to `(8em 8em 8em 8em 8em 8em)`.
/// - `(300px susy-repeat(4) 300px)`:
/// a 6-column, asymmetrical, mixed fluid/static grid
/// using `calc()` output.
/// <br />Identical to `(300px 1 1 1 1 300px)`.
///
/// **NOTE** that `12` is no longer a valid 12-column grid definition,
/// and you must list all the columns individually
/// (or by using the `susy-repeat()` function).
///
/// @prop {number} gutters -
/// Gutters are defined as a single width,
/// or fluid ratio, similar to the native-CSS
/// `grid-column-gap` syntax.
/// Similar to columns,
/// gutters can use any valid CSS length unit,
/// or unitless numbers to define a relative fraction.
///
/// - `0.5`:
/// a fluid gutter, half the size of a single-fraction column.
/// - `1em`:
/// a static gutter, `1em` wide.
///
/// Mix static gutters with fluid columns, or vice versa,
/// and Susy will generate the required `calc()` to make it work.
///
/// @prop {string} spread [narrow] -
/// Spread of an element across adjacent gutters:
/// either `narrow` (none), `wide` (one), or `wider` (two)
///
/// - Both spread settings default to `narrow`,
/// the most common use-case.
/// A `narrow` spread only has gutters *between* columns
/// (one less gutter than columns).
/// This is how all css-native grids work,
/// and most margin-based grid systems.
/// - A `wide` spread includes the same number of gutters as columns,
/// spanning across a single side-gutter.
/// This is how most padding-based grid systems often work,
/// and is also useful for pushing and pulling elements into place.
/// - The rare `wider` spread includes gutters
/// on both sides of the column-span
/// (one more gutters than columns).
///
/// @prop {string} container-spread [narrow] -
/// Spread of a container around adjacent gutters:
/// either `narrow` (none), `wide` (one), or `wider` (two).
/// See `spread` property for details.
///
/// @since 3.0.0-beta.1 -
/// `columns` setting no longer accepts numbers
/// (e.g. `12`) for symmetrical fluid grids,
/// or the initial `12 x 120px` syntax for
/// symmetrical fixed-unit grids.
/// Use `susy-repeat(12)` or `susy-repeat(12, 120px)` instead.
///
/// @example scss - default values
/// // 4 symmetrical, fluid columns
/// // gutters are 1/4 the size of a column
/// // elements span 1 less gutter than columns
/// // containers span 1 less gutter as well
/// $susy: (
/// 'columns': susy-repeat(4),
/// 'gutters': 0.25,
/// 'spread': 'narrow',
/// 'container-spread': 'narrow',
/// );
///
/// @example scss - inside-static gutters
/// // 6 symmetrical, fluid columns
/// // gutters are static, triggering calc()
/// // elements span equal columns & gutters
/// // containers span equal columns & gutters
/// $susy: (
/// 'columns': susy-repeat(6),
/// 'gutters': 0.5em,
/// 'spread': 'wide',
/// 'container-spread': 'wide',
/// );
$susy: () !default;
// Susy Repeat
// -----------
/// Similar to the `repeat(<count>, <value>)` function
/// that is available in native CSS Grid templates,
/// the `susy-repeat()` function helps generate repetative layouts
/// by repeating any value a given number of times.
/// Where Susy previously allowed `8` as a column definition
/// for 8 equal columns, you should now use `susy-repeat(8)`.
///
/// @group a-config
///
/// @param {integer} $count -
/// The number of repetitions, e.g. `12` for a 12-column grid.
/// @param {*} $value [1] -
/// The value to be repeated.
/// Technically any value can be repeated here,
/// but the function exists to repeat column-width descriptions:
/// e.g. the default `1` for single-fraction fluid columns,
/// `5em` for a static column,
/// or even `5em 120px` if you are alternating column widths.
///
/// @return {list} -
/// List of repeated values
///
/// @example scss
/// // 12 column grid, with 5em columns
/// $susy: (
/// columns: susy-repeat(12, 5em),
/// );
///
/// @example scss
/// // asymmetrical 5-column grid
/// $susy: (
/// columns: 20px susy-repeat(3, 100px) 20px,
/// );
///
/// /* result: #{susy-get('columns')} */
@function susy-repeat(
$count,
$value: 1
) {
$return: ();
@for $i from 1 through $count {
$return: join($return, $value);
}
@return $return;
}
// Susy Defaults
// -------------
/// Configuration map of Susy factory defaults.
/// Do not override this map directly
/// use `$susy` for user and project setting overrides.
///
/// @access private
/// @type Map
///
/// @see $susy
///
/// @prop {number | list} columns [susy-repeat(4)]
/// @prop {number} gutters [0.25]
/// @prop {string} spread ['narrow']
/// @prop {string} container-spread ['narrow']
$_susy-defaults: (
'columns': susy-repeat(4),
'gutters': 0.25,
'spread': 'narrow',
'container-spread': 'narrow',
);
// Susy Settings
// -------------
/// Return a combined map of Susy settings,
/// based on the factory defaults (`$_susy-defaults`),
/// user-defined project configuration (`$susy`),
/// and any local overrides required
/// such as a configuration map passed into a function.
///
/// @group a-config
///
/// @param {maps} $overrides -
/// Optional map override of global configuration settings.
/// See `$susy` above for properties.
///
/// @return {map} -
/// Combined map of Susy configuration settings,
/// in order of specificity:
/// any `$overrides...`,
/// then `$susy` project settings,
/// and finally the `$_susy-defaults`
///
/// @example scss - global settings
/// @each $key, $value in susy-settings() {
/// /* #{$key}: #{$value} */
/// }
///
/// @example scss - local settings
/// $local: ('columns': 1 2 3 5 8);
///
/// @each $key, $value in susy-settings($local) {
/// /* #{$key}: #{$value} */
/// }
@function susy-settings(
$overrides...
) {
$settings: map-merge($_susy-defaults, $susy);
@each $config in $overrides {
$settings: map-merge($settings, $config);
}
@return $settings;
}
// Susy Get
// --------
/// Return the current global value of any Susy setting
///
/// @group a-config
///
/// @param {string} $key -
/// Setting to retrieve from the configuration.
///
/// @return {*} -
/// Value mapped to `$key` in the configuration maps,
/// in order of specificity:
/// `$susy`, then `$_susy-defaults`
///
/// @example scss -
/// /* columns: #{susy-get('columns')} */
/// /* gutters: #{susy-get('gutters')} */
@function susy-get(
$key
) {
$settings: susy-settings();
@if not map-has-key($settings, $key) {
@return _susy-error(
'There is no Susy setting called `#{$key}`',
'susy-get');
}
@return map-get($settings, $key);
}

View File

@ -0,0 +1,441 @@
/// Grid Math Engine
/// ================
/// The `su` functions give you direct access to the math layer,
/// without any syntax-sugar like shorthand parsing, and normalization.
/// If you prefer named arguments, and stripped-down syntax,
/// you can use these functions directly in your code
/// replacing `span`, `gutter`, and `slice`.
///
/// These functions are also useful
/// for building mixins or other extensions to Susy.
/// Apply the Susy syntax to new mixins and functions,
/// using our "Plugin Helpers",
/// or write your own syntax and pass the normalized results along
/// to `su` for compilation.
///
/// @group su-math
///
/// @see su-span
/// @see su-gutter
/// @see su-slice
/// @ignore _su-sum
/// @ignore _su-calc-span
/// @ignore _su-calc-sum
/// @ignore _su-needs-calc-output
// Su Span
// -------
/// Calculates and returns a CSS-ready span width,
/// based on normalized span and context data
/// a low-level version of `susy-span`,
/// with all of the logic and none of the syntax sugar.
///
/// - Grids defined with unitless numbers will return `%` values.
/// - Grids defined with comparable units
/// will return a value in the units provided.
/// - Grids defined with a mix of units,
/// or a combination of untiless numbers and unit-lengths,
/// will return a `calc()` string.
///
/// @group su-math
/// @see susy-span
///
/// @param {number | list} $span -
/// Number or list of grid columns to span
/// @param {list} $columns -
/// List of columns available
/// @param {number} $gutters -
/// Width of a gutter in column-comparable units
/// @param {0 | 1 | -1} $spread -
/// Number of gutters spanned,
/// relative to `span` count
/// @param {0 | 1 | -1} $container-spread [$spread] -
/// Number of gutters spanned,
/// relative to `columns` count
/// @param {integer} $location [1] -
/// Optional position of sub-span among full set of columns
///
/// @return {length} -
/// Relative or static length of a span on the grid
@function su-span(
$span,
$columns,
$gutters,
$spread,
$container-spread: $spread,
$location: 1
) {
$span: su-valid-span($span);
$columns: su-valid-columns($columns);
$gutters: su-valid-gutters($gutters);
$spread: su-valid-spread($spread);
@if (type-of($span) == 'number') {
@if (not unitless($span)) {
@return $span;
}
$location: su-valid-location($span, $location, $columns);
$span: su-slice($span, $columns, $location, $validate: false);
}
@if _su-needs-calc-output($span, $columns, $gutters, $spread, not 'validate') {
@return _su-calc-span($span, $columns, $gutters, $spread, $container-spread, not 'validate');
}
$span-width: _su-sum($span, $gutters, $spread, $validate: false);
@if unitless($span-width) {
$container-spread: su-valid-spread($container-spread);
$container: _su-sum($columns, $gutters, $container-spread, $validate: false);
@return percentage($span-width / $container);
}
@return $span-width;
}
// Su Gutter
// ---------
/// Calculates and returns a CSS-ready gutter width,
/// based on normalized grid data
/// a low-level version of `susy-gutter`,
/// with all of the logic and none of the syntax sugar.
///
/// - Grids defined with unitless numbers will return `%` values.
/// - Grids defined with comparable units
/// will return a value in the units provided.
/// - Grids defined with a mix of units,
/// or a combination of untiless numbers and unit-lengths,
/// will return a `calc()` string.
///
/// @group su-math
/// @see susy-gutter
///
/// @param {list} $columns -
/// List of columns in the grid
/// @param {number} $gutters -
/// Width of a gutter in column-comparable units
/// @param {0 | 1 | -1} $container-spread -
/// Number of gutters spanned,
/// relative to `columns` count
///
/// @return {length} -
/// Relative or static length of one gutter in a grid
@function su-gutter(
$columns,
$gutters,
$container-spread
) {
@if (type-of($gutters) == 'number') {
@if ($gutters == 0) or (not unitless($gutters)) {
@return $gutters;
}
}
@if _su-needs-calc-output($gutters, $columns, $gutters, -1, not 'validate') {
@return _su-calc-span($gutters, $columns, $gutters, -1, $container-spread, not 'validate');
}
$container: _su-sum($columns, $gutters, $container-spread);
@return percentage($gutters / $container);
}
// Su Slice
// --------
/// Returns a list of columns
/// based on a given span/location slice of the grid
/// a low-level version of `susy-slice`,
/// with all of the logic and none of the syntax sugar.
///
/// @group su-math
/// @see susy-slice
///
/// @param {number} $span -
/// Number of grid columns to span
/// @param {list} $columns -
/// List of columns in the grid
/// @param {number} $location [1] -
/// Starting index of a span in the list of columns
/// @param {bool} $validate [true] -
/// Check that arguments are valid before proceeding
///
/// @return {list} -
/// Subset list of grid columns, based on span and location
@function su-slice(
$span,
$columns,
$location: 1,
$validate: true
) {
@if $validate {
$columns: su-valid-columns($columns);
$location: su-valid-location($span, $location, $columns);
}
$floor: floor($span);
$sub-columns: ();
@for $i from $location to ($location + $floor) {
$sub-columns: append($sub-columns, nth($columns, $i));
}
@if $floor != $span {
$remainder: $span - $floor;
$column: $location + $floor;
$sub-columns: append($sub-columns, nth($columns, $column) * $remainder);
}
@return $sub-columns;
}
// Su Sum
// ------
/// Get the total sum of column-units in a layout.
///
/// @group su-math
/// @access private
///
/// @param {list} $columns -
/// List of columns in the grid
/// @param {number} $gutters -
/// Width of a gutter in column-comparable units
/// @param {0 | 1 | -1} $spread -
/// Number of gutters spanned,
/// relative to `columns` count
/// @param {bool} $validate [true] -
/// Check that arguments are valid before proceeding
///
/// @return {number} -
/// Total sum of column-units in a grid
@function _su-sum(
$columns,
$gutters,
$spread,
$validate: true
) {
@if $validate {
$columns: su-valid-span($columns);
$gutters: su-valid-gutters($gutters);
$spread: su-valid-spread($spread);
}
// Calculate column-sum
$column-sum: 0;
@each $column in $columns {
$column-sum: $column-sum + $column;
}
$gutter-sum: (ceil(length($columns)) + $spread) * $gutters;
$total: if(($gutter-sum > 0), $column-sum + $gutter-sum, $column-sum);
@return $total;
}
// Su Calc
// -------
/// Return a usable span width as a `calc()` function,
/// in order to create mixed-unit grids.
///
/// @group su-math
/// @access private
///
/// @param {number | list} $span -
/// Pre-sliced list of grid columns to span
/// @param {list} $columns -
/// List of columns available
/// @param {number} $gutters -
/// Width of a gutter in column-comparable units
/// @param {0 | 1 | -1} $spread -
/// Number of gutters spanned,
/// relative to `span` count
/// @param {0 | 1 | -1} $container-spread [$spread] -
/// Number of gutters spanned,
/// relative to `columns` count
/// @param {bool} $validate [true] -
/// Check that arguments are valid before proceeding
///
/// @return {length} -
/// Relative or static length of a span on the grid
@function _su-calc-span(
$span,
$columns,
$gutters,
$spread,
$container-spread: $spread,
$validate: true
) {
@if $validate {
$span: su-valid-span($span);
$columns: su-valid-columns($columns);
$gutters: su-valid-gutters($gutters);
$spread: su-valid-spread($spread);
$container-spread: su-valid-spread($container-spread);
}
// Span and context
$span: _su-calc-sum($span, $gutters, $spread, not 'validate');
$context: _su-calc-sum($columns, $gutters, $container-spread, not 'validate');
// Fixed and fluid
$fixed-span: map-get($span, 'fixed');
$fluid-span: map-get($span, 'fluid');
$fixed-context: map-get($context, 'fixed');
$fluid-context: map-get($context, 'fluid');
$calc: '#{$fixed-span}';
$fluid-calc: '(100% - #{$fixed-context})';
// Fluid-values
@if (not $fluid-span) {
$fluid-calc: null;
} @else if ($fluid-span != $fluid-context) {
$fluid-span: '* #{$fluid-span}';
$fluid-context: if($fluid-context, '/ #{$fluid-context}', '');
$fluid-calc: '(#{$fluid-calc $fluid-context $fluid-span})';
}
@if $fluid-calc {
$calc: if(($calc != ''), '#{$calc} + ', '');
$calc: '#{$calc + $fluid-calc}';
}
@return calc(#{unquote($calc)});
}
// Su Calc-Sum
// -----------
/// Get the total sum of fixed and fluid column-units
/// for creating a mixed-unit layout with `calc()` values.
///
/// @group su-math
/// @access private
///
/// @param {list} $columns -
/// List of columns available
/// @param {number} $gutters -
/// Width of a gutter in column-comparable units
/// @param {0 | 1 | -1} $spread -
/// Number of gutters spanned,
/// relative to `span` count
/// @param {bool} $validate [true] -
/// Check that arguments are valid before proceeding
///
/// @return {map} -
/// Map with `fixed` and `fluid` keys
/// containing the proper math as strings
@function _su-calc-sum(
$columns,
$gutters,
$spread,
$validate: true
) {
@if $validate {
$columns: su-valid-span($columns);
$gutters: su-valid-gutters($gutters);
$spread: su-valid-spread($spread);
}
$fluid: 0;
$fixed: ();
$calc: null;
// Gutters
$gutters: $gutters * (length($columns) + $spread);
// Columns
@each $col in append($columns, $gutters) {
@if unitless($col) {
$fluid: $fluid + $col;
} @else {
$fixed: _su-map-add-units($fixed, $col);
}
}
// Compile Fixed Units
@each $unit, $total in $fixed {
@if ($total != (0 * $total)) {
$calc: if($calc, '#{$calc} + #{$total}', '#{$total}');
}
}
// Calc null or string
@if $calc {
$calc: if(str-index($calc, '+'), '(#{$calc})', '#{$calc}');
}
// Fluid 0 => null
$fluid: if(($fluid == 0), null, $fluid);
// Return map
$return: (
'fixed': $calc,
'fluid': $fluid,
);
@return $return;
}
// Needs Calc
// ----------
/// Check if `calc()` will be needed in defining a span,
/// if the necessary units in a grid are not comparable.
///
/// @group su-math
/// @access private
///
/// @param {list} $span -
/// Slice of columns to span
/// @param {list} $columns -
/// List of available columns in the grid
/// @param {number} $gutters -
/// Width of a gutter
/// @param {0 | 1 | -1} $spread -
/// Number of gutters spanned,
/// relative to `span` count
/// @param {bool} $validate [true] -
/// Check that arguments are valid before proceeding
///
/// @return {bool} -
/// `True` when units do not match, and `calc()` will be required
@function _su-needs-calc-output(
$span,
$columns,
$gutters,
$spread,
$validate: true
) {
@if $validate {
$span: su-valid-span($span);
$columns: su-valid-columns($columns);
$gutters: su-valid-gutters($gutters);
}
$has-gutter: if((length($span) > 1) or ($spread >= 0), true, false);
$check: if($has-gutter, append($span, $gutters), $span);
$safe-span: _su-is-comparable($check...);
@if ($safe-span == 'static') {
@return false;
} @else if (not $safe-span) {
@return true;
}
$safe-fluid: _su-is-comparable($gutters, $columns...);
@return not $safe-fluid;
}

View File

@ -0,0 +1,213 @@
/// Validation
/// ==========
/// Each argument to Su has a single canonical syntax.
/// These validation functions check to ensure
/// that each argument is valid,
/// in order to provide useful errors
/// before attempting to calculate the results/
///
/// @group x-validation
///
/// @see su-valid-columns
/// @see su-valid-gutters
/// @see su-valid-spread
/// @see su-valid-location
// Valid Span
// ----------
/// Check that the `span` argument
/// is a number, length, or column-list
///
/// @group x-validation
///
/// @param {number | list} $span -
/// Number of columns, or length of span
///
/// @return {number | list} -
/// Validated `$span` number, length, or columns list
///
/// @throw
/// when span value is not a number, or valid column list
@function su-valid-span(
$span
) {
$type: type-of($span);
@if ($type == 'number') {
@return $span;
} @else if ($type == 'list') and su-valid-columns($span, 'silent-failure') {
@return $span;
}
$actual: '[#{type-of($span)}] `#{inspect($span)}`';
@return _susy-error(
'#{$actual} is not a valid number, length, or column-list for $span.',
'su-valid-span');
}
// Valid Columns
// -------------
/// Check that the `columns` argument is a valid
/// list of column-lengths
///
/// @group x-validation
///
/// @param {list} $columns -
/// List of column-lengths
/// @param {bool} $silent-failure [true] -
/// Set false to return null on failure
///
/// @return {list} -
/// Validated `$columns` list
///
/// @throw
/// when column value is not a valid list of numbers
@function su-valid-columns(
$columns,
$silent-failure: false
) {
@if (type-of($columns) == 'list') {
$fail: false;
@each $col in $columns {
@if (type-of($col) != 'number') {
$fail: true;
}
}
@if not $fail {
@return $columns;
}
}
// Silent Failure
@if $silent-failure {
@return null;
}
// Error Message
$actual: '[#{type-of($columns)}] `#{inspect($columns)}`';
@return _susy-error(
'#{$actual} is not a valid list of numbers for $columns.',
'su-valid-columns');
}
// Valid Gutters
// -------------
/// Check that the `gutters` argument is a valid number
///
/// @group x-validation
///
/// @param {number} $gutters -
/// Width of a gutter
///
/// @return {number} -
/// Validated `$gutters` number
///
/// @throw
/// when gutter value is not a number
@function su-valid-gutters(
$gutters
) {
$type: type-of($gutters);
@if ($type == 'number') {
@return $gutters;
}
$actual: '[#{$type}] `#{inspect($gutters)}`';
@return _susy-error(
'#{$actual} is not a number or length for $gutters.',
'su-valid-gutters');
}
// Valid Spread
// ------------
/// Check that the `spread` argument is a valid
/// intiger between `-1` and `1`
///
/// @group x-validation
///
/// @param {0 | 1 | -1} $spread -
/// Number of gutters to include in a span,
/// relative to the number columns
///
/// @return {0 | 1 | -1} -
/// Validated `$spread` number
///
/// @throw
/// when spread value is not a valid spread
@function su-valid-spread(
$spread
) {
@if index(0 1 -1, $spread) {
@return $spread;
}
$actual: '[#{type-of($spread)}] `#{inspect($spread)}`';
@return _susy-error(
'#{$actual} is not a normalized [0 | 1 | -1] value for `$spread`.',
'su-valid-spread');
}
// Valid Location
// --------------
/// Check that the `location` argument is a valid number,
/// within the scope of available columns
///
/// @group x-validation
///
/// @param {number} $span -
/// Number of grid-columns to be spanned
/// @param {integer | string} $location -
/// Starting (1-indexed) column-position of that span
/// @param {list} $columns -
/// List of available columns in the grid
///
/// @return {integer} -
/// Validated `$location` intiger
///
/// @throw
/// when location value is not a valid index,
/// given the context and span.
@function su-valid-location(
$span,
$location,
$columns
) {
$count: length($columns);
@if $location {
@if (type-of($location) != 'number') or (not unitless($location)) {
$actual: '[#{type-of($location)}] `#{$location}`';
@return _susy-error(
'#{$actual} is not a unitless number for $location.',
'su-valid-location');
} @else if (round($location) != $location) {
@return _susy-error(
'Location (`#{$location}`) must be a 1-indexed intiger position.',
'su-valid-location');
} @else if ($location > $count) or ($location < 1) {
@return _susy-error(
'Position `#{$location}` does not exist in grid `#{$columns}`.',
'su-valid-location');
} @else if ($location + $span - 1 > $count) {
$details: 'grid `#{$columns}` for span `#{$span}` at `#{$location}`';
@return _susy-error(
'There are not enough columns in #{$details}.',
'su-valid-location');
}
}
@return $location;
}

View File

@ -0,0 +1,191 @@
/// Syntax Utilities for Extending Susy
/// ===================================
/// There are many steps involved
/// when translating between the Susy syntax layer,
/// and the Su core math.
/// That entire process can be condensed with these two functions.
/// For anyone that wants to access the full power of Susy,
/// and build their own plugins, functions, or mixins
/// this is the primary API for compiling user input,
/// and accessing the core math.
///
/// This is the same technique we use internally,
/// to keep our API layer simple and light-weight.
/// Every function accepts two arguments,
/// a "shorthand" description of the span or context,
/// and an optional settings-map to override global defaults.
///
/// - Use `susy-compile()` to parse, merge, and normalize
/// all the user settings into a single map.
/// - Then use `su-call()` to call one of the core math functions,
/// with whatever data is needed for that function.
///
/// @group plugin-utils
/// @see susy-compile
/// @see su-call
///
/// @example scss - Susy API `gutter` function
/// @function susy-gutter(
/// $context: susy-get('columns'),
/// $config: ()
/// ) {
/// // compile and normalize all user arguments and global settings
/// $context: susy-compile($context, $config, 'context-only');
/// // call `su-gutter` with the appropriate data
/// @return su-call('su-gutter', $context);
/// }
///
/// @example scss - Sample `span` mixin for floated grids
/// @mixin span(
/// $span,
/// $config: ()
/// ) {
/// $context: susy-compile($span, $config);
/// width: su-call('su-span', $context);
///
/// @if index($span, 'last') {
/// float: right;
/// } @else {
/// float: left;
/// margin-right: su-call('su-gutter', $context);
/// }
/// }
// Compile
// -------
/// Susy's syntax layer has various moving parts,
/// with syntax-parsing for the grid/span shorthand,
/// and normalization for each of the resulting values.
/// The compile function rolls this all together
/// in a single call
/// for quick access from our internal API functions,
/// or any additional functions and mixins you add to your project.
/// Pass user input and configuration maps to the compiler,
/// and it will hand back a map of values ready for Su.
/// Combine this with the `su-call` function
/// to quickly parse, normalize, and process grid calculations.
///
/// @group plugin-utils
/// @see su-call
///
/// @param {list | map} $shorthand -
/// Shorthand expression to define the width of the span,
/// optionally containing:
/// - a count, length, or column-list span;
/// - `at $n`, `first`, or `last` location on asymmetrical grids;
/// - `narrow`, `wide`, or `wider` for optionally spreading
/// across adjacent gutters;
/// - `of $n <spread>` for available grid columns
/// and spread of the container
/// (span counts like `of 6` are only valid
/// in the context of symmetrical grids);
/// - and `set-gutters $n` to override global gutter settings
/// @param {map} $config [null] -
/// Optional map of Susy grid configuration settings
/// @param {bool} $context-only [false] -
/// Allow the parser to ignore span and span-spread values,
/// only parsing context and container-spread
///
/// @return {map} -
/// Parsed and normalized map of settings,
/// based on global and local configuration,
/// alongwith shorthad adjustments.
///
/// @example scss -
/// $user-input: 3 wide of susy-repeat(6, 120px) set-gutters 10px;
/// $grid-data: susy-compile($user-input, $susy);
///
/// @each $key, $value in $grid-data {
/// /* #{$key}: #{$value}, */
/// }
@function susy-compile(
$short,
$config: null,
$context-only: false
) {
// Get and normalize config
$config: if($config, susy-settings($config), susy-settings());
$normal-config: susy-normalize($config);
// Parse and normalize shorthand
@if (type-of($short) != 'map') and (length($short) > 0) {
$short: susy-parse($short, $context-only);
}
$normal-short: susy-normalize($short, $normal-config);
// Merge and return
@return map-merge($normal-config, $normal-short);
}
// Call
// ----
/// The Susy parsing and normalization process
/// results in a map of configuration settings,
/// much like the global `$susy` settings map.
/// In order to pass that information along to Su math functions,
/// the proper values have to be picked out,
/// and converted to arguments.
///
/// The `su-call` function streamlines that process,
/// weeding out the unnecessary data,
/// and passing the rest along to Su in the proper format.
/// Combine this with `susy-compile` to quickly parse,
/// normalize, and process grid calculations.
///
/// @group plugin-utils
///
/// @require su-span
/// @require su-gutter
/// @require su-slice
/// @see susy-compile
///
/// @param {'su-span' | 'su-gutter' | 'su-slice'} $name -
/// Name of the Su math function to call.
/// @param {map} $config -
/// Parsed and normalized map of Susy configuration settings
/// to use for math-function arguments.
///
/// @return {*} -
/// Results of the function being called.
///
/// @example scss -
/// $user-input: 3 wide of susy-repeat(6, 120px) set-gutters 10px;
/// $grid-data: susy-compile($user-input, $susy);
///
/// .su-span {
/// width: su-call('su-span', $grid-data);
/// }
@function su-call(
$name,
$config
) {
$grid-function-args: (
'su-span': ('span', 'columns', 'gutters', 'spread', 'container-spread', 'location'),
'su-gutter': ('columns', 'gutters', 'container-spread'),
'su-slice': ('span', 'columns', 'location'),
);
$args: map-get($grid-function-args, $name);
@if not $args {
$options: 'Try one of these: #{map-keys($grid-function-args)}';
@return _susy-error(
'#{$name} is not a public Su function. #{$options}',
'su-call');
}
$call: if(function-exists('get-function'), get-function($name), $name);
$output: ();
@each $arg in $args {
$value: map-get($config, $arg);
$output: if($value, map-merge($output, ($arg: $value)), $output);
}
@return call($call, $output...);
}

View File

@ -0,0 +1,56 @@
// Unprefix Susy
// =============
// Span
// ----
/// Un-prefixed alias for `susy-span`
/// (available by default)
///
/// @group api
/// @alias susy-span
///
/// @param {list} $span
/// @param {map} $config [()]
@function span(
$span,
$config: ()
) {
@return susy-span($span, $config);
}
// Gutter
// ------
/// Un-prefixed alias for `susy-gutter`
/// (available by default)
///
/// @group api
/// @alias susy-gutter
///
/// @param {integer | list} $context [null] -
/// @param {map} $config [()]
@function gutter(
$context: susy-get('columns'),
$config: ()
) {
@return susy-gutter($context, $config);
}
// Slice
// -----
/// Un-prefixed alias for `susy-slice`
/// (available by default)
///
/// @group api
/// @alias susy-slice
///
/// @param {list} $span
/// @param {map} $config [()]
@function slice(
$span,
$config: ()
) {
@return susy-slice($span, $config);
}

View File

@ -0,0 +1,167 @@
// Sass Utilities
// ==============
// - Susy Error Output Override [variable]
// - Susy Error [function]
// Susy Error Output Override
// --------------------------
/// Turn off error output for testing
/// @group x-utility
/// @access private
$_susy-error-output-override: false !default;
// Susy Error
// ----------
/// Optionally return error messages without failing,
/// as a way to test error cases
///
/// @group x-utility
/// @access private
///
/// @param {string} $message -
/// A useful error message, explaining the problem
/// @param {string} $source -
/// The original source of the error for debugging
/// @param {bool} $override [$_susy-error-output-override] -
/// Optionally return the error rather than failing
/// @return {string} -
/// Combined error with source and message
/// @throws When `$override == true`
@function _susy-error(
$message,
$source,
$override: $_susy-error-output-override
) {
@if $override {
@return 'ERROR [#{$source}] #{$message}';
}
@error '[#{$source}] #{$message}';
}
// Su Is Comparable
// ----------------
/// Check that the units in a grid are comparable
///
/// @group x-validation
/// @access private
///
/// @param {numbers} $lengths -
/// Arglist of all the number values to compare
/// (columns, gutters, span, etc)
///
/// @return {'fluid' | 'static' | false} -
/// The type of span (fluid or static) when units match,
/// or `false` for mismatched units
@function _su-is-comparable(
$lengths...
) {
$first: nth($lengths, 1);
@if (length($lengths) == 1) {
@return if(unitless($first), 'fluid', 'static');
}
@for $i from 2 through length($lengths) {
$comp: nth($lengths, $i);
$fail: not comparable($first, $comp);
$fail: $fail or (unitless($first) and not unitless($comp));
$fail: $fail or (unitless($comp) and not unitless($first));
@if $fail {
@return false;
}
}
@return if(unitless($first), 'fluid', 'static');
}
// Su Map Add Units
// ----------------
/// The calc features use a map of units and values
/// to compile the proper algorythm.
/// This function adds a new value to any comparable existing unit/value,
/// or adds a new unit/value pair to the map
///
/// @group x-utility
/// @access private
///
/// @param {map} $map -
/// A map of unit/value pairs, e.g. ('px': 120px)
/// @param {length} $value -
/// A new length to be added to the map
/// @return {map} -
/// The updated map, with new value added
///
/// @example scss -
/// $map: (0px: 120px);
/// $map: _su-map-add-units($map, 1in); // add a comparable unit
/// $map: _su-map-add-units($map, 3vw); // add a new unit
///
/// @each $units, $value in $map {
/// /* #{$units}: #{$value} */
/// }
@function _su-map-add-units(
$map,
$value
) {
$unit: $value * 0;
$has: map-get($map, $unit) or 0;
@if ($has == 0) {
@each $try, $could in $map {
$match: comparable($try, $value);
$unit: if($match, $try, $unit);
$has: if($match, $could, $has);
}
}
@return map-merge($map, ($unit: $has + $value));
}
// Susy Flatten
// ------------
/// Flatten a multidimensional list
///
/// @group x-utility
/// @access private
///
/// @param {list} $list -
/// The list to be flattened
/// @return {list} -
/// The flattened list
///
/// @example scss -
/// $list: 120px (30em 30em) 120px;
/// /* #{_susy-flatten($list)} */
@function _susy-flatten(
$list
) {
$flat: ();
// Don't iterate over maps
@if (type-of($list) == 'map') {
@return $list;
}
// Iterate over lists (or single items)
@each $item in $list {
@if (type-of($item) == 'list') {
$item: _susy-flatten($item);
$flat: join($flat, $item);
} @else {
$flat: append($flat, $item);
}
}
// Return flattened list
@return $flat;
}