Sass Reference - - By Hugo Giraudel

Lists

Lists are the Sass equivalent of arrays, which we can find almost any programming language. They are a data structure containing one or several values, possibly including lists, leading to nested lists.

List Delimiters

What makes a value a list is the delimiter. As soon as two values are separated by a valid delimiter, i.e. a space or comma, the overall value becomes a list.

$list: 'foo' 'bar';
$type: type-of($list); // list
$separator: list-separator($list); // space

$list: 'foo', 'bar';
$type: type-of($list); // list
$separator: list-separator($list); // comma

Note that since version 3.4, Sass allows trailing commas after the last value of a list. This behaviour, quite common in some other programming languages, turns out especially useful when reordering multi-line lists:

$list:
  'foo',
  'bar',
  'baz',
;

Because of this, any value immediately followed by a trailing comma becomes a (single item, space-separated) list.

$foo: 'foo';
$type: type-of($foo); // string

$foo: 'foo',;
$type: type-of($foo); // list

When using two different separators in the same list, the result becomes a list nested within another list with the comma as the top-level list delimiter, and space as the inner list separator.

// This is a 2 items long list
// First is a string: 'foo'
// Second is a 2 items long list: 'bar' 'baz'
$foo: 'foo', 'bar' 'baz';

List Wrappers

As the delimiter is what makes a value a list, wrapping parentheses (( and )) are optional although they are usually used to improve readability.

// Both are strictly identical
$foo: ('foo', 'bar');
$bar: 'foo', 'bar';

There are only two scenarios where wrapping parentheses are mandatory. The first one is when dealing with empty lists.

$list: (); // Empty list

Note that an empty lists use spaces as delimiters by default. This is easily checked by using the list-separator function on an empty list:

$list: ();
$separator: list-separator($list); // space

If you explicitly want to create a comma-separated empty list, the shortest way is to use the join function.

$list: join((), (), 'comma');
$separator: list-separator($list); // comma

The second case where wrapping parentheses are mandatory is when dealing with nested lists. When having only two level nested within each others, it is doable with mixing both commas and spaces, but when going deeper we have to use parentheses to explicitly delimit inner lists.

// All equivalents
$list: 'foo', 'bar' 'baz';
$list: 'foo', ('bar' 'baz');
$list: 'foo', ('bar', 'baz');
$list: ('foo', 'bar' 'baz');
$list: ('foo', ('bar' 'baz'));
$list: ('foo', ('bar', 'baz'));

List Indexes

One very important thing to know about lists in Sass is that indexes start at 1, and not 0 like in many languages. Remember this when using nth and set-nth functions.

$list: ('foo', 'bar', 'baz');
$item: nth($list, 1); // 'foo'

Iterating on lists

There are several ways to iterate over a list, and all of them include the use of a loop. Please refer to the loops entry in order to learn more about loops.

List manipulation functions

When dealing with lists in a programmatic way, Sass provides a small amount of handy functions to append, update, join, count and what else, lists.

// Initializing an empty list
$list: (); // ()

// Getting the number of items in list
$count: length($list); // 0

// Adding a value to the list
$list: append($list, 'foo'); // ('foo')

// Getting the number of items in list
$count: length($list); // 1

// Updating value in the list
$list: set-nth($list, 1, 'bar'); // ('bar')

// Adding a value to the list with explicit separator
$list: append($list, 'foo', 'comma'); // ('bar', 'foo');

// Getting the second value from list
$item: nth($list, 2); // 'foo'

// Zipping two lists while keeping indexes
$list: zip($list, 'baz' 'bar'); // ('bar' 'baz', 'foo' 'bar');

// Getting the number of items in list
$count: length($list); // 2

// Prepending value to the list with explicit separator
$list: join('foo', $list, 'comma'); // ('foo', 'bar' 'baz', 'foo' 'bar');

// Getting the number of items in list
$count: length($list); // 3

Oddly enough, there is no way to remove a value from a list, while there is a native function to remove a value from a map. Fortunately, there is quite easy to polyfill:

/// Remove value at `$index` in `$list`
/// @author Hugo Giraudel
/// @param {List} $list - List to remove value from
/// @param {Number} $index - Index to remove value from
/// @return {List} - Updated list
@function remove-nth($list, $index) {
  $new-list: ();

  @for $i from 1 through length($list) {
    @if $i != $index {
      $new-list: append($new-list, nth($list, $i), list-separator($list));
    }
  }

  @return $new-list;
}

Then, it can be used in the same fashion as set-nth:

$list: ('foo', 'bar', 'baz');
$list: remove-nth($list, 2); // ('foo', 'baz')

If we want to remove a specific value from list, we can also build a quite similar function for that:

/// Remove `$value` from `$list`
/// @author Hugo Giraudel
/// @param {List} $list - List to remove value from
/// @param {*} $value - Value to remove
/// @return {List} - Updated list
@function remove($list, $value) {
  $new-list: ();

  @each $item in $list {
    @if $value != $item {
      $new-list: append($new-list, $item, list-separator($list));
    }
  }

  @return $new-list;
}

Rewriting our previous example:

$list: ('foo', 'bar', 'baz');
$list: remove($list, 'bar'); // ('foo', 'baz')