Блог

Sass map для типографики в отзывчивой верстке

Управлять типографикой и ее ритмом на сайте, довольно сложная задача для верстальщика, и в разы сложнее это делать при отзывчивой верстке

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

Вот так это примерно выглядит:

p { font-size: 15px; }

@media screen and (min-width: 480px) {
  p { font-size: 16px; }
}
@media screen and (min-width: 640px) {
  p { font-size: 17px; }
}
@media screen and (min-width: 1024px) {
  p { font-size: 19px; }
}

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

$p-font-size-mobile : 15px;
$p-font-size-small  : 16px;
$p-font-size-medium : 17px;
$p-font-size-large  : 19px;

$h1-font-size-mobile: 28px;
$h1-font-size-small : 31px;
$h1-font-size-medium: 33px;
$h1-font-size-large : 36px;

и как раз здесь незаменимы SASS maps и циклы

Они полезны при управлении значениями z-index, color и как увидим ниже значениями font-size.

Организация размеров шрифта при помощи SASS map

Создадим карту со парами ключ значение - точки изменения как ключи, размер шрифта как передаваемое значение

$p-font-sizes: (
  null  : 15px,
  480px : 16px,
  640px : 17px,
  1024px: 19px
);

Так как предпочтительно использовать подход "Mobil first", мы прописываем от меньшего к большему, т.е. null это дефолтное занчение размера шрифта до того как к нему будут применяться media query

Следующий mixin будет пробегать по нашей карте и формировать значения media query

@mixin font-size($fs-map) {
  @each $fs-breakpoint, $fs-font-size in $fs-map {
    @if $fs-breakpoint == null {
      font-size: $fs-font-size;
    }
    @else {
      @media screen and (min-width: $fs-breakpoint) {
        font-size: $fs-font-size;
      }
    }
  }
}

Применим наш mixin:

p {
  @include font-size($p-font-sizes);
}

В результате в css увидим следующее :

p { font-size: 15px; }

@media screen and (min-width: 480px) {
  p { font-size: 16px; }
}
@media screen and (min-width: 640px) {
  p { font-size: 17px; }
}
@media screen and (min-width: 1024px) {
  p { font-size: 19px; }
}

Теперь управлять размерами шрифта при отзывчивом дизайне становиться проще. Создаем карту, вызываем mixin и вуа -ля все работает

$h1-font-sizes: (
  null  : 28px
  480px : 31px,
  640px : 33px,
  1024px: 36px
);

h1 {
  @include font-size($h1-font-sizes);
}

Можно применить и к нескольким селекторам:

p, ul, ol {
  @include font-size($p-font-sizes);
}

Решаем проблему с фрагментацией точек изменения

Что если мы захотим, чтобы параграф у нас был 17px, а заголовок 33px при размере 700px вместо существующих 640? Используя вышеприведенное решение, нам придется переписывать это значение во всех картах, что вобщем то не создает радужного настроения, особенно если сайт со сложной типографикой.

Но если мы можем применять SASS map для font-size, то таким же образом мы можем поступить и с точками изменения.

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

$breakpoints: (
  small : 480px,
  medium: 700px, // Previously 640px
  large : 1024px
);

$p-font-sizes: (
  null  : 15px,
  small : 16px,
  medium: 17px,
  large : 19px
);

$h1-font-sizes: (
  null  : 28px,
  small : 31px,
  medium: 33px,
  large : 36px
);

Следущим шагом дополним mixin, чтобы при переборе карт с размерами шрифтов, он использовал имя точки изменения и присваивал значения из $breakpoints, перед формированием media query

@mixin font-size($fs-map, $fs-breakpoints: $breakpoints) {
  @each $fs-breakpoint, $fs-font-size in $fs-map {
    @if $fs-breakpoint == null {
      font-size: $fs-font-size;
    }
    @else {
      // If $fs-font-size is a key that exists in
      // $fs-breakpoints, use the value
      @if map-has-key($fs-breakpoints, $fs-breakpoint) {
        $fs-breakpoint: map-get($fs-breakpoints, $fs-breakpoint);
      }
      @media screen and (min-width: $fs-breakpoint) {
        font-size: $fs-font-size;
      }
    }
  }
}

Теперь вроде все неплохо, но если мы хотим поставить точку изменения, которой у нас нет в карте $breackpoints? Мы просто пропысываем значение этой точки и mixin все сделает сам.

$p-font-sizes: (
  null  : 15px,
  small : 16px,
  medium: 17px,
  900px : 18px,
  large : 19px,
  1440px: 20px,
);

p {
  @include font-size($p-font-sizes);
}

Магия происходит когда mixin обращается к функции SASS map-has-key. Она проверяет существует ли имя ключа в $breakpoits, если существует то использует значение этого ключа, в противном случае функция определяет ключ как значение и использует его для генерации media query

p { font-size: 15px; }

@media screen and (min-width: 480px) {
  p { font-size: 16px; }
}
@media screen and (min-width: 700px) {
  p { font-size: 17px; }
}
@media screen and (min-width: 900px) {
  p { font-size: 18px; }
}
@media screen and (min-width: 1024px) {
  p { font-size: 19px; }
}
@media screen and (min-width: 1440px) {
  p { font-size: 20px; }
}

Улучшаем вертикальный ритм типоргафики при помощи line-height

line-height очень важное свойство которое выстраивает нашу типографику по вертикали, мы можем включить его в наши карты

$breakpoints: (
  small : 480px,
  medium: 700px,
  large : 1024px
);

$p-font-sizes: (
  null  : (15px, 1.3),
  small : 16px,
  medium: (17px, 1.4),
  900px : 18px,
  large : (19px, 1.45),
  1440px: 20px,
);

Хотя для значений line-height мы можем использовать все единицы доступные CSS ( пиксели, проценты, em и т.д.), рекомендуется и предпочтительно использовать без них, для того чтобы избежать неожиданных результатов

Теперь нам нужно переделать mixin для того чтобы включить в него занчения line-height

@mixin font-size($fs-map, $fs-breakpoints: $breakpoints) {
  @each $fs-breakpoint, $fs-font-size in $fs-map {
    @if $fs-breakpoint == null {
      @include make-font-size($fs-font-size);
    }
    @else {
      // If $fs-font-size is a key that exists in
      // $fs-breakpoints, use the value
      @if map-has-key($fs-breakpoints, $fs-breakpoint) {
        $fs-breakpoint: map-get($fs-breakpoints, $fs-breakpoint);
      }
      @media screen and (min-width: $fs-breakpoint) {
        @include make-font-size($fs-font-size);
      }
    }
  }
}

// Utility function for mixin font-size
@mixin make-font-size($fs-font-size) {
  // If $fs-font-size is a list, include
  // both font-size and line-height
  @if type-of($fs-font-size) == "list" {
    font-size: nth($fs-font-size, 1);
    @if (length($fs-font-size) > 1) {
      line-height: nth($fs-font-size, 2);
    }
  }
  @else {
    font-size: $fs-font-size;
  }
}

Mixin теперь проверяет является ли значение ключа списком и если да то присваивеат их значения по порядку: 1 значение - font-size, 2 значение - line-height, в этом помогает функция nth

Теперь посмотрим в действии

p {
  @include font-size($p-font-sizes);
}

Результирующий CSS:

p { font-size: 15px; line-height: 1.3; }

@media screen and (min-width: 480px) {
  p { font-size: 16px; }
}
@media screen and (min-width: 700px) {
  p { font-size: 17px; line-height: 1.4; }
}
@media screen and (min-width: 900px) {
  p { font-size: 18px; }
}
@media screen and (min-width: 1024px) {
  p { font-size: 19px; line-height: 1.45; }
}
@media screen and (min-width: 1440px) {
  p { font-size: 20px; }
}

Приведенное решение можно расширить включив другие атрибуты такие как font-weight, margins и т.д.

Ключ превращаем в служебный mixin make-font-size и используем функцию nth, для вывода нужных значений из списка

В заключение

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

При применение этого mixina media query будут дублироваться в конечном CSS, но тесты на скорость загрузки показывают что при сжатом CSS в худшем случае эта разница незначительна, а обычно ее вообще не наблюдается

Источники : smashingmagazinejonsuh

Ваше сообщение отправленно.