442 lines
11 KiB
SCSS
442 lines
11 KiB
SCSS
/// 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;
|
||
}
|