Статьи

Sass Maps против вложенных списков

Название этого поста может удивить некоторых из вас. Если вы ветеран Sass, вы можете вспомнить дни (до Ruby-Sass-3.3) использования списков списков для эмуляции вложенных массивов данных. (Ruby) В Sass 3.3 добавлен новый тип данных под названием maps . Списки списков могут содержать сложные данные во вложенном формате, но без согласования ключ-значение. Карты добавили пары ключ-значение и позволили нам создавать массивы данных.

С появлением карт многие из нас, пользователей Sass, начали вкладывать все в карты (и не зря!). Все ваши ширины точек останова , значения цвета , макеты сетки , шкалы типов и другие подробные детали типографики могут быть включены в карты!

Теперь, когда у Sass есть карты с парами ключ-значение, есть ли веская причина использовать список списков? Одной из теоретических причин была бы обратная совместимость: если ваш Sass может обслуживаться разработчиком с установленной более старой версией, списки помогут им. На практике, однако, версиями Sass часто управляет package.json или другая конфигурация проекта, и гем Ruby можно обновить с помощью одной команды ( gem update sass ).

Более практическая причина, по которой вы можете использовать вложенные списки вместо карты, — это меньше печатать. Давайте сравним карту и вложенный список, чтобы увидеть, как они сравниваются в своем собственном синтаксисе, и как мы их просматривали.

Сравнение синтаксиса

Для нашего примера давайте создадим структуру данных, которая управляет адаптивной типографикой. Он будет хранить четыре точки останова (ну, одна из них — это наименьшее представление по умолчанию). Для каждой точки останова мы будем хранить min-width , max-width , базовый font-size и базовую line-height .

Сложный синтаксис карты

Вот как мы будем хранить эти данные на карте. Одна большая карта будет содержать четыре ключа (метки точек останова), значения которых являются картами переменных, которые нам нужно хранить и использовать. В таком читаемом формате, как этот, у нас есть чуть более 450 символов и 26 строк.

 $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 ) ); 

Синтаксис вложенного списка

Вложенный список для хранения этих же данных намного короче. Однако у нас больше нет ключей, прикрепленных к нашим данным, поэтому мы должны полагаться на их циклическое выполнение или вызов их с помощью функций nth() . Тем не менее, он намного короче карты: менее 180 символов и всего 6 строк.

 $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) ); 

Сравнение циклов

Когда дело доходит до того, чтобы напечатать нашу структуру данных, набор списков занимает примерно треть времени печати карты. Однако, если нам нужно пройтись по этим значениям, как это сравнить?

Комплексная карта Loop

Мы можем использовать следующий код для цикла элементов верхнего уровня на этой карте:

 @each $label, $map in $breakpoint-map {} 

Две переменные в начале этой строки ( $label и $map ) назначаются динамически, поскольку цикл повторяет данные в карте. Каждый фрагмент данных верхнего уровня имеет два компонента: ключ и значение. Мы назначаем ключ для $label а значение (которое является вложенной картой) для $map . Внутри этого цикла мы можем использовать переменные $label и $map и они будут автоматически представлять ключ и значение текущей записи.

Этот цикл будет повторяться четыре раза, один раз для каждой вложенной карты. Однако, чтобы получить полезные данные из вложенной карты, нам нужно использовать функцию map-get() . Эта функция принимает два параметра — имя карты и имя нужного ключа — и возвращает значение, связанное с этим ключом. Это эквивалент Sass PHP- $array['key'] и $object->key или синтаксису JavaScript object.key .

Чтобы перебрать все @each с помощью @each и присвоить их значения полезным переменным с помощью map-get() , мы получаем 6-строчный цикл из 220 символов.

 @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); } 

Вложенный список Loop

Вложенные списки действительно делают циклы эффективными. В случае с картами нам пришлось присвоить карту динамической переменной цикла, а затем использовать map-get() для назначения всех ее значений переменным, но с помощью списков мы можем быстро назначить все значения переменным.

Поскольку каждый элемент в списке верхнего уровня имеет одинаковые пять значений в одном и том же порядке, мы можем немедленно назначить каждое из них динамической переменной для использования внутри нашего цикла. С этими переменными нам не нужно использовать map-get() чтобы назначать значения для используемых переменных. Цикл, который нам нужен для вложенных списков, состоит всего из двух строк и содержит менее 100 символов.

 @each $label, $min-width, $max-width, $base-font, $vertical-rhythm in $breakpoint-list { } 

Предупреждения о вложенных списках

Вложенные списки являются основным выигрышем в производительности разработчика: в целом, вы, вероятно, наберете менее половины, чем если бы вы использовали карту. Однако есть причина, по которой карты были добавлены в Sass: они предоставляют списки функций, а не: сопоставление ключ-значение.

Недостающие ценности

Если вы собираетесь полагаться на вложенные списки, вы должны быть абсолютно уверены, что знаете, сколько элементов будет в каждом списке и в каком порядке они будут. Давайте посмотрим, что произойдет в нашем примере выше, если мы пропустим элемент в одном из наших списков:

 $breakpoint-list: ( (small, null, 479px, 16px, 1.3), (medium, 480px, 959px, 18px, 1.414), (large, 960px, 1099px, 18px, 1.5), (xlarge, 1100px, 21px, 1.618) ); p { @each $label, $min-width, $max-width, $base-font, $vertical-rhythm in $breakpoint-list { @if $min-width { @include breakpoint( $min-width ) { font-size: $base-font; line-height: $vertical-rhythm; } } @else { font-size: $base-font; line-height: $vertical-rhythm; } } } 

Если мы попробуем запустить этот код, последний список сломается. Он правильно назначит «xlarge» для $label и «1100px» для $min-width , но затем назначит «21px» для $max-width и «1.618» для $base-font , оставив $vertical-rhythm пустым. В результате мы получаем недопустимое объявление font-size и отсутствующее свойство line-height в последней точке останова. Кроме того, Sass не сообщает об ошибке для этого, поэтому мы бы не знали, сработало ли это или нет. Если бы мы попытались использовать max-width для медиазапроса, мы бы получили значение font-size (всего 21px ) — это было бы довольно бесполезной максимальной шириной, я думаю!

Если бы мы использовали карты вместо этого, функция map-get() дала бы нам то, что нам нужно, даже если бы одно из значений отсутствовало. Это наш компромисс: то, что мы получаем в простоте и скорости со списками, мы теряем в специфичности и защите от ошибок с картами.

Запрос определенного списка

Связанная проблема с использованием вложенных списков — запрос определенного списка. Поскольку карты имеют ключи, вы можете быстро получить доступ к любой из дополнительных карт с помощью map-get() :

 $medium-map: map-get($maps, medium); 

Чтобы получить данные из списка medium во вложенных списках, нам нужна более сложная функция:

 @function get-list($label) { @each $list in $breakpoint-list { @if nth($list, 1) == $label { @return $list; } } @return null; } $medium-list: get-list(medium); 

Эта функция перебирает все списки в $breakpoint-list , проверяет первое значение для метки, которую мы хотим, и возвращает список, если находит совпадение. Если он доходит до конца цикла @each не найдя соответствия, он возвращает null . Это в основном быстрая домашняя интерпретация map-get() для списков, которые используют первое значение в качестве искусственного ключа.

Недостающие функции карты

У Sass довольно много полезных функций для работы с картами: те же функции не существуют для вложенных списков. Например, вы можете использовать map-merge() для добавления дополнительных пар ключ-значение на карту. Использование map-merge() с общими ключами обновит значение для общих ключей. Вы можете добавить новый список, используя join() или append() , но для подделки функции обновления map-merge() потребуется другая пользовательская функция Sass.

Другая полезная функция карты — map-has-key() . Эта функция полезна для проверки любой пользовательской функции, которая использует map-get() . Однако нет никакой сопоставимой функции для списков.

Вы можете использовать SassyLists для имитации функций карты со списками. (Эта библиотека предоставила эти функции, прежде чем Sass добавил поддержку карт.)

Вывод

Карты являются более мощными, чем списки, потому что они используют пары ключ-значение. Дополнительные функции карты Sass предоставляют полезные способы поиска данных и проверки значений карты.

Вложенные списки Sass можно быстрее создавать и поддерживать, но они, вероятно, не так хорошо подходят для проверки ошибок или подробных запросов, как карты. Я считаю, что большую часть времени карты являются лучшим вариантом, несмотря на повышенную детализацию. Для небольших кусков кода и одноразовых циклов я буду иногда использовать вложенный список, но карты лучше работают для настроек проекта и хранения данных.

Сравнивали ли вы карты и вложенные списки в любой из ваших работ или рефакторинг кода, чтобы отдать предпочтение одному из других? Поделитесь своим опытом в комментариях!

Вы можете увидеть код, использованный для этого урока, в этой книге .