Статьи

Лучшее решение для управления z-index с помощью Sass

В последнее время мы видели довольно много статей об управлении z-index

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

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

Зачем нужно управлять значениями z-index

Сначала давайте ответим на этот вопрос: зачем нам управлять z-index с помощью Sass? Мы не видим, как появляются многочисленные статьи об управлении padding Так зачем делать это для z-index

Ну, это связано с тем, что z-index Более того, принятие значения без единиц измерения между -infinity и бесконечностью дает вам много поводов облажаться.

Поэтому вместо использования таких значений, как 9999999

Что такое концепция?

Концепция здесь в основном одинакова во всех статьях по этой теме: Создайте функцию, которая принимает ключевое слово в качестве аргумента, которое сопоставляется со значением. Это значение является z-index, который будет распечатан.

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

В конечном итоге мы придем к этому:

 .element {
  z-index: z("modal");
}

Зачем использовать функцию, а не миксин?

Даг Эвери использует миксин в своей статье. Основное различие с функцией заключается в способе ее использования:

 // With a mixin
// Me no likey!
.element {
  @include z("modal");
}

Хотя я понимаю, что это действительно вопрос предпочтений, я действительно стараюсь не использовать миксины, когда выводится только одно свойство CSS. Функция является идеальным вариантом использования для чего-то подобного.

Открытие зверя

Поэтому нам нужна функция, принимающая один аргумент. Не стесняйтесь называть это как угодно; Я пошел со layer

 @function z($layer) {
  // ... where the magic happens.
}

Что делает функция в любом случае? Он будет искать заданный аргумент в карте слоев, чтобы увидеть, соответствует ли он значению z-index Если это так, он возвращает значение, иначе он возвращает сообщение об ошибке. Итак, нам нужна карта.

 $z-layers: (
  "goku":            9001,
  "shoryuken":       8000,
  "default":            1,
  "below":             -1,
  "bottomless-pit": -9000
);

Две вещи здесь:

  1. Мне нравится, когда мои переменные конфигурации находятся вне их в миксин / функциях, в отдельном файле (например, _config.scss Не стесняйтесь перемещать его внутри функции z()
  2. Вы можете добавить / удалить / обновить столько ключей / значений, сколько хотите, это только примеры.

Теперь вернемся к нашей функции.

 @function z($layer) {
  @return map-get($z-layers, $layer);
}

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

Если ключ существует на карте, он вернет значение индекса, сопоставленное с ним. Если ключ не был определен, он вернет null Когда свойство имеет null

Таким образом, в случае, если вы вызываете неизвестный ключ, Sass просто молча провалится, что не идеально. Давайте улучшим это, используя директиву @warn

 @function z($layer) {
  @if not map-has-key($z-layers, $layer) {
    @warn "No layer found for `#{$layer}` in $z-layers map. Property omitted.";
  }

  @return map-get($z-layers, $layer);
}

Там. Если вы запрашиваете неопределенный ключ (например, «SitePoint»), Sass выведет в консоли следующее:

«Не найден слой для SitePoint Собственность опущена. »

Довольно круто, правда?

Играя с новой игрушкой

Теперь, когда мы закончили строить нашу функцию, пришло время поиграть с ней! Как вы видели в начале этой статьи, использовать функцию довольно просто:

 .modal {
  // ...
  z-index: z("modal");
}

.modal-overlay {
  // ...
  z-index: z("modal") - 1;
}

Идея состоит в том, чтобы всегда использовать эту функцию при определении значений z-index Использование его только часть времени не имеет смысла и в значительной степени убивает систему.

Кроме того, я думаю, что лучше держать карту слоя максимально светлой. Чем больше слоев вы добавляете, тем больше сложность Z-шкалы. Попробуйте найти пару повторяющихся значений, сопоставить их с общими ключевыми словами, и вам будет хорошо.

Продвигая вещи дальше с помощью вложенных контекстов

Вы, вероятно, не без знания, что значения z-index Все они связаны с их собственным стековым контекстом. Это в основном означает, что если вы попытаетесь заставить элемент из Context-A появиться поверх элемента из Context-B, но Context-B будет нарисован поверх Context-A, то даже индекс более девяти тысяч не будет довольно.

Примечание. Для получения дополнительной информации о контекстах стека и z-indexэту потрясающую статью Филиппа Уолтона.

Теперь, если мы хотим, чтобы наша система знала контексты стекирования, мы могли бы иметь вложенные карты. Например, если наш modal

 $z-layers: (
  "goku":            9001, 
  "shoryuken":       8000,
  "modal": (
    "base":           500,
    "close":          100,
    "header":          50,
    "footer":          10
  ),
  "default":            1,
  "below":             -1,
  "bottomless-pit": -9000
);

Проблема в том, что мы не можем легко получить значение из вложенных карт, ни в коем случае не используя map-get К счастью, создать такую ​​функцию легко:

 @function map-deep-get($map, $keys...) {
  @each $key in $keys {
    $map: map-get($map, $key);
  }

  @return $map;
}

Достаточно. Просто, не правда ли? Теперь мы можем написать наш модальный модуль так:

 // New stacking context
.modal {  
  position: absolute;
  z-index: z("modal", "base");

  .close-button {
    z-index: z("modal", "close");
  }

  header {
    z-index: z("modal", "header");
  }

  footer {
    z-index: z("modal", "footer");
  }
}

Что даст следующий результат:

 .modal {
  position: absolute;
  z-index: 500;
}

/* This is `100` in the modal stacking context */
.modal .close-button {
  z-index: 100;
}

/* This is `50` in the modal stacking context */
.modal header {
  z-index: 50;
}

/* This is `10` in the modal stacking context */
.modal footer {
  z-index: 10;
}

В будущем!

Когда-нибудь в светлое будущее, о котором мы все мечтаем, у нас будут собственные переменные CSS. Тогда нам все это больше не нужно. Вместо этого вот что произойдет:

 :root {
  --z-goku:            9001;
  --z-shoryuken:       8000; 
  --z-modal:            500;
  --z-default:            1;
  --z-below:             -1;
  --z-bottomless-pit: -9000;
}

.modal {
  z-index: var(--z-modal);
}

Видеть? Практически то же самое, за исключением того, что это var()z()--keykey Немного больше времени для ввода и, возможно, немного более хаотично, поскольку это отдельные переменные, а не карта. Но он хорошо справляется с работой, сохраняя при этом нативность.

Последние мысли

Я не знаю как вы, но я думаю, что это прекрасный метод для обработки z-index Мало того, что все организовано с каждым z-индексом, хранящимся в карте слоев, но также довольно легко иметь небольшие вариации с операторами, как мы видели в нашем последнем примере.

Вот и все. Вот демоверсия Sassmeister, чтобы вы начали. Нет причин не применять это в ваших проектах, начиная с сегодняшнего дня.