Core points
map-get()
function can still provide the desired value even if one value is missing. The title of this article may surprise some people. If you are a Sass veteran, you may remember to use a list of lists to simulate the days when nested arrays of data (before Ruby-Sass-3.3). (Ruby) Sass 3.3 adds a new data type called Mapping. Lists of lists can save complex data in nested formats, but have no key-value pairing. The map adds key-value pairs and lets create an array of data.
With the advent of mapping, many of our Sass users started putting everything into the mapping (and for good reason!). All breakpoint widths, color values, grid layouts, type proportions, and other responsive typography details can be put into the map!
Now that Sass has a key-value pair mapping, is there any good reason to use a list of lists? One theoretical reason is backward compatibility: if your Sass is likely maintained by a developer with older versions installed, the list will help them. However, in practice, the Sass version is usually controlled by package.json
or other project configurations, and the Ruby gem can be updated with just one command (gem update sass
).
A more practical reason you might choose to use nested lists instead of mappings is that there is less input. Let's compare maps and nested lists to see how they compare in their respective syntax and loop traversal.
Grammar comparison
In our example, let's create a data structure that controls responsive typography. It will store four breakpoints (well, one is the smallest default view). For each breakpoint, we will store the minimum width, maximum width, base font size, and base line height.
The following is how we store data in a map. A large map will contain four keys (breakpoint labels) whose values are maps of variables we need to store and use. In this readable format, we have over 450 characters and 26 lines.
<code>$breakpoint-map: ( small: ( min-width: null, max-width: 479px, base-font: 16px, vertical-rhythm: 1.3 ), medium: ( min-width: 480px, max-width: 959px, base-font: 18px, vertical-rhythm: 1.414 ), large: ( min-width: 960px, max-width: 1099px, base-font: 18px, vertical-rhythm: 1.5 ), xlarge: ( min-width: 1100px, max-width: null, base-font: 21px, vertical-rhythm: 1.618 ) );</code>
Nested lists that store the same data are much shorter. However, we no longer append the key to the data, so we have to rely on looping through it or calling it with the nth()
function. That is, it is much shorter than the map: less than 180 characters, only 6 lines.
<code>$breakpoint-list: ( (small, null, 479px, 16px, 1.3), (medium, 480px, 959px, 18px, 1.414), (large, 960px, 1099px, 18px, 1.5), (xlarge, 1100px, null, 21px, 1.618) );</code>
Cycle comparison
When writing a data structure, writing a list only requires writing a third of the mapping time. But if we need to loop through these values, then how do we compare?
We can loop through the top items in this map using the following code:
<code>@each $label, $map in $breakpoint-map {}</code>
The two variables ($label
and $map
) at the beginning of this line are dynamically allocated when iterating the data in the map in the loop. Each top-level data block has two components: keys and values. We assign the key to $label
and the value (which is a nested map) to $map
. In this loop we can use the variables $label
and $map
, which will automatically represent the key and value of the current entry.
The loop will iterate four times, one nested map each iterating. However, to get useful data from nested maps, we need to use the map-get()
function. This function takes two parameters—the name of the map and the name of the required key—and returns the value associated with the key. It is the equivalent of the $array['key']
and $object->key
of PHP or the object.key
syntax of JavaScript in Sass.
To use @each
to iterate over all submaps and assign their values to useful variables using map-get()
, we end up with a 6-line, 220-character loop.
<code>@each $label, $map in $breakpoint-map { $min-width: map-get($map, min-width); $max-width: map-get($map, max-width); $base-font: map-get($map, base-font); $vertical-rhythm: map-get($map, vertical-rhythm); }</code>
Nested lists do make loops more efficient. For maps, we have to assign the map to dynamic loop variables and then assign all values to variables using map-get()
, but for lists we can quickly assign all values to variables.
Since each item in the top-level list has the same five values in the same order, we can immediately assign each value to a dynamic variable for use in a loop. With these variables, we do not need to assign subvalues to available variables using map-get()
. The nested list loop we need is only two lines, less than 100 characters.
<code>@each $label, $min-width, $max-width, $base-font, $vertical-rhythm in $breakpoint-list { }</code>
Nested List Warning
Nested lists are the main developer performance advantages: Overall, you may enter less than half as much as you did when using the mapping. However, there is a reason to add maps to Sass: they provide a function that lists do not have: key-value mapping.
If you are relying on nested lists, you must be absolutely sure you know how many items each list will contain and the order they are. Let's see what happens if we miss an item in the list:
<code>$breakpoint-map: ( small: ( min-width: null, max-width: 479px, base-font: 16px, vertical-rhythm: 1.3 ), medium: ( min-width: 480px, max-width: 959px, base-font: 18px, vertical-rhythm: 1.414 ), large: ( min-width: 960px, max-width: 1099px, base-font: 18px, vertical-rhythm: 1.5 ), xlarge: ( min-width: 1100px, max-width: null, base-font: 21px, vertical-rhythm: 1.618 ) );</code>
If we try to run the code, the last list will break. It will correctly assign "xlarge" to $label
and "1100px" to $min-width
, but then it assigns "21px" to $max-width
and "1.618" to $base-font
, making $vertical-rhythm
is empty. As a result, we get an invalid font size declaration and a missing line height property in the last breakpoint. Also, Sass doesn't report an error for this, so we don't know if things succeed. If we try to use the maximum width for media queries, we will end up with the font size value (only 21px) - I think this would be a very useless maximum width!
If we use map instead, even if a value is missing, the map-get()
function will give us what we need. This is our tradeoff: the simplicity and speed we get in the list, we lose specificity and error prevention in the mapping.
Another related problem with using nested lists is querying specific lists. Since the map has keys, you can quickly access any submap using map-get()
:
<code>$breakpoint-list: ( (small, null, 479px, 16px, 1.3), (medium, 480px, 959px, 18px, 1.414), (large, 960px, 1099px, 18px, 1.5), (xlarge, 1100px, null, 21px, 1.618) );</code>
To get data for medium lists from nested lists, we need a more complex function:
<code>@each $label, $map in $breakpoint-map {}</code>
This function loops through all lists in $breakpoint-list
, checks the first value of the label we want, and returns the list if a match is found. If the end of the @each
loop is reached without a match found, it will return null. It's basically a quick homemade interpretation of the list's map-get()
, which uses the first value as a pseudo-key.
Sass has many useful functions to handle mappings: nested lists do not exist in the same function. For example, you can use map-merge()
to add additional key-value pairs to the map. Use map-merge()
with shared keys to update the value of the shared key. You can add a new list using join()
or append()
, but the update function that simulates map-merge()
will require another custom Sass function.
Another useful mapping function is map-has-key()
. This function is useful for validating any custom function that depends on map-get()
. However, there are no comparable functions for the list.
You can use SassyLists to simulate the mapping function of a list. (This library provided these functions before Sass added mapping support.)
Conclusion
Since maps use key-value pairs, they are more powerful than lists. The additional Sass mapping function provides a practical way to find data and verify mapped values.
Nested Sass lists may be faster to write and maintain, but they may not be as suitable as mappings for error checking or detailed querying. Most of the time, I think mapping is a better option, although there is an increase in verboseness. For smaller blocks of code and single-use loops, I occasionally use nested lists, but the mapping is more suitable for project-wide settings and data storage.
Have you compared maps and nested lists in any of your work, or refactored the code to prioritize one over the other? Share your experience in the comments!
You can see the code used in this tutorial in this Sassmeister gist.
FAQ for Sass Mapping and Nested Lists (FAQ)
Sass mapping and nested lists are both powerful tools in Sass preprocessors, but they have obvious differences. Sass maps are similar to associative arrays in other programming languages, where each value is associated with a unique key. This makes it easy to retrieve, update and manipulate data. On the other hand, nested lists are a series of values similar to arrays in JavaScript. They are best suited when you need to store and iterate over a range of values, but they lack the ability to directly access specific values provided by the mapping.
To use Sass map, you first need to define a map with a pair of brackets, each key-value pair separated by a colon. For example, $map: (key1: value1, key2: value2)
. You can then use the map-get
function to access the values in the map as follows: map-get($map, key1)
.
Yes, you can nest Sass maps like nested lists. This is especially useful when you want to combine relevant data together. To access the values in a nested map, you need to use the map-get
function twice: map-get(map-get($map, key1), key2)
.
You can iterate over the Sass map using the @each
directive. The @each
directive takes two variables: key and value. Here is an example: @each $key, $value in $map { … }
.
Sass mapping has several advantages over nested lists. They allow direct access to specific values, making your code more efficient and easier to read. They also provide built-in functions for manipulating mappings, such as adding, deleting, and updating key-value pairs.
Yes, you can use the map-from-list
function to convert nested lists to Sass maps. This function takes a list of pairs and returns a map where each pair is a key-value pair in the map.
To use nested lists in Sass, you first need to define a list with a pair of brackets, each value separated by a space or comma. For example, $list: (value1, value2, value3)
. You can then use the nth
function to access the values in the list as follows: nth($list, 1)
.
Yes, you can use both Sass mapping and nested lists. For example, you can use mappings to store a series of lists and vice versa. This is useful for organizing complex data structures.
While Sass mapping and nested lists are powerful tools, they do have some limitations. For example, the Sass map cannot have duplicate keys, and the order of keys in the map cannot be guaranteed. Likewise, if nested lists become too large or too complex, they can be difficult to manage.
The choice of using Sass map or nested list depends on your specific needs. If you need to directly access specific values and be able to manipulate data, Sass mapping may be the best choice. If you just need to store and iterate over a series of values, a nested list is enough.
The above is the detailed content of Sass Maps vs. Nested Lists. For more information, please follow other related articles on the PHP Chinese website!