/// 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; }