Перейти к содержанию

Использование медиавыражений

В 2015 году непозволительно иметь сайт, ориентирующийся только на пользователей стационарных ПК и ноутбуков. Благодаря доступности мобильных устройств и интернета, а также повсеместного внедрения Wi-Fi сетей, сайты всё больше получают «мобильных» посетителей. Я уже давно стал замечать, что использую ноутбук лишь для производства контента, а его потребление происходит, в основном, с помощью планшета и, изредка, смартфона.

Для того, чтобы ориентировать сайт на все платформы нужно использовать медиавыражения, которые определяются с помощью директивы @media.

Медиавыражения

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

Медиавыражения (от англ. media query) — это объявление директивы @media с одним или несколькими условиями, в зависимости от которых определяется будут ли срабатывать объявления внутри этой директивы или нет.

В простейшем случае медиавыражение имеет такой вид:

@media (min-width: 992px) {
  .class {
    display: none;
  }
}

Если при объявлении директивы используется несколько условий, то они объединяются с помощью ключевого слова and:

@media (min-width: 768px) and (orientation: landscape) {
  .class {
    display: none;
  }
}

@media tv and (min-width: 992px) and (orientation: landscape) {
  .class {
    display: block;
  }
}

Такие конструкции позволяют применять те или иные свойства к элементам, в зависимости от выполнения некоторых условий. В основном, нас интересует: разрешение окна браузера, ориентация устройства и пиксельное соотношение (от англ. pixel ratio). Существуют и другие, но они применяются крайне редко.

Медиавыражения в Less

Препроцессор Less не привносит в синтаксис медиавыражений кардинальных изменений. Различие с CSS заключается в том, что здесь доступно два контекста использования и присутствует несколько особенностей. Рассматривать их отдельно и приводить примеры я не буду, а вот об особенностях поговорим подробнее, но позднее.

Стандартный контекст использования такой же, как и в классическом CSS:

@media (min-width: 992px) {
  .class {
    display: none;
    // какие-то другие стили
  }
}

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

.class {
  .two {
    @media (min-width: 992px) {
      display: none;
      // какие-то другие стили
    }
  }
}

После работы компилятора имеем следующий CSS-код:

@media (min-width: 992px) {
  .class .two {
    display: none;
  }
}

Второй вариант использовать предпочтительнее, ввиду того, что он не требует слежения за правильностью структуры и вложенности. При этом нет необходимости исправлять названия селекторов, если они поменяются в процессе разработки, ведь компилятор сам уследит, к чему относится директива @media, а также объявленные внутри неё свойства и селекторы.

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

Вложенные медиавыражения

В самом начале главы вы узнали о том, что селекторы можно вкладывать друг в друга. Так вот, в этом случае медиавыражения схожи с селекторами. Вложенные конструкции будут склеиваться в одно медиавыражение с несколькими условиями. То есть, условия будут объединяться, а на каждом уровне вложенности будет собираться своё отдельное объявление директивы @media.

Пример 2.5.1

Рассмотрим пример того, как происходит компиляция вложенных медиавыражений. Напишем какое-нибудь непростое вложенное медиавыражение с вложенными селекторами:

.one {
  @media (min-width: 768px) {
    background-color: #f5f5f5;

    .two {
      @media (max-width: 992px) {
        color: #000;
      }
    }
  }
}

Когда компилятор начнёт обрабатывать такую структуру, сначала будет создано медиавыражение с условием (min-width: 768px) и его свойствами, а уже потом со списком условий (min-width: 768px) and (max-width: 992px).

@media (min-width: 768px) {
  .one {
    background-color: #f5f5f5;
  }
}
@media (min-width: 768px) and (max-width: 992px) {
  .one .two {
    color: #000;
  }
}

Предупреждение!

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

Медиавыражения и группировка селекторов

Директива @media представляет собой замкнутую систему. Из школьного курса физики или химии известно, что замкнутая система — это такая система, которая не обменивается с окружающей средой ни веществом, ни энергией. В нашем случае энергией и веществом будут свойства и селекторы, объявленные внутри директивы. В идеальном случае, медиавыражения не могут воздействовать друг на друга. Получается, что группировать селекторы можно только внутри такой системы, не выходя за её пределы. Но, так как в реальности абсолютно замкнутых систем не бывает, воздействовать на неё извне мы сможем.

Пример 2.5.2

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

@media screen {
  .one {
    &:extend(.three, .two);
    background-color: #fff;
  }

  @media (min-width: 992px) {
    .two {
      &:extend(.one);
      color: #777;
    }
  }
}

.three {
  border-right: 1px solid #000;
}

Если выполнить компиляцию этого кода, то выполнится процедура объединения условий медиавыражения (пример 2.5.1), а вот группировки селекторов не произойдёт. Причём группировка не наблюдается ни в первом, ни во втором случае. Кроме того, изменения не коснутся и внешнего селектора. Отлично, значит утверждение о замкнутой системе верное.

@media screen {
  .one {
    background-color: #fff;
  }
}
@media screen and (min-width: 992px) {
  .two {
    color: #777;
  }
}
.three {
  border-right: 1px solid #000;
}

Пример 2.5.3

В этом примере будем рассматривать случай, когда мы можем воздействовать на замкнутую систему (медиавыражения). Для этого повторим поставленный в примере 2.5.2 эксперимент, но добавим группировку селекторов не в сами медиавыражения, а в отдельно стоящий селектор.

@media screen {
  .one {
    background-color: #fff;
  }

  @media (min-width: 992px) {
    .two {
      color: #777;
    }
  }
}

.test {
  &:extend(.one, .two);
  border-right: 1px solid #000;
}

После работы компилятора на выходе имеем CSS-код, в котором группировка селекторов всё таки выполняется. Происходит это из-за того, что извне воздействовать на медиавыражения можно.

@media screen {
  .one,
  .test {
    background-color: #fff;
  }
}
@media screen and (min-width: 992px) {
  .two,
  .test {
    color: #777;
  }
}
.test {
  border-right: 1px solid #000;
}