Немного про media queries


Вы не поверите, но на одном из сайтов Политеха я решил внедрить модный (а через годик — обязательный к использованию) Responsive design. Пока что по минимум, просто с media queries. И сделал небольшие выводы.

К.О.: media queries — часть спецификации CSS3, позволяющая уточнить область действия css-селектора. Представляет собой блок с указанием параметров устройства вывода, такие как тип, ширина и высота окна браузера, разрешение, ориентация в пространстве.

Мне нужно было задать разные значения блоков разметки для группы разрешений — менее 480px, от 480 до 800, от 800 до 1024, от 1024 до 1280 и более 1280.

Очевидно, что блоки media queries нужно располагать в порядке от меньшего разрешенияы к большему. Это позволит не извращаться в условиях, да и «интуитивно понятно».

Для нижней границы я использовал уточнение по верхней границе, а дальше плясал от нижней:

@media screen and (max-width:480px) {
    /* Селекторы */
}
@media screen and (min-width:480px) {
    /* Селекторы */
}
@media screen and (min-width:800px) {
    /* Селекторы */
}

Почему именно так? Браузер высчитывает реальное значение min-width исходя из размеров окна браузера, а max-width — от разрешения экрана, соответственно при разрешении 1920px сработают max-width(480px), max-width(800px) и так далее, вплоть до max-width(1920px).

Если же использовать только min-width, то для ширины менее 480 пикселов вообще не будут применяться никакие селекторы. А это совсем не то, что нам нужно.

Можем представить это правило графически:

Специфичность media-queries

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

Например, если мы хотим, чтобы блок header на разного рода смартфонах был высотой 30 пикселов, а в остальных случаях — 100 пикселов, то такой номер не прокатит:

@media screen and (max-width:480px) {
    header {
        height: 30px;
    }
}
header {
    height: 100px;
}

При любых условиях блок header будет высотой 100 пикселов. Почему так происходит — нам покажет инспектор:

Правила внутри @media применяются, но браузер встречает далее в таблице стилей ещё одно правило для header и применяет именно его. Поэтому изменим наш фрагмент кода:

@media screen and (max-width:480px) {
    header {
        height: 30px;
    }
}
@media screen and (min-width:480px) {
    header {
        height: 100px;
    }
}

Теперь мы можем выстроить более точное правило, по которому нужно сортировать блоки @media: свойства с max-width записываются от больших значений к меньшим, а блоки с min-widht — наоборот, от меньшего к большему.

А ведь с точки зрения скорости рендеринга (а вдруг вы — фанат БЭМ?) нужно всеми способами избегать переопределения свойств. Что же, изменим наш код ещё раз:

@media screen and (max-width:480px) {
    /* Селекторы */
}
@media screen and (min-width:480px) and (max-width:800px) {
    /* Селекторы */
}
@media screen and (min-width:800px) {
    /* Селекторы */
}

Теперь для каждого диапазона ширины экрана будет применяться только один блок стилевых правил. Проверьте сами в испекторе — я не вру!

Подключение media queries

Писать большую «портянку» css с media-queries утомительно, а уж искать в ней нужное место через пару недель — и того хуже. Что мы можем сделать?

Все хорошие мальчики давно познали правила css-менеджмента и подключают файлы при помощи @import. Что можно и чего нельзя делать с media queries?

Создадим три файла — media-small.css, media-normal.css и media-large.css, а потом попробуем подключить их.

Сначала — как делать нельзя. Нельзая вот так:

@media screen and (max-width:480px) {
    @import url(media-small.css);
}
@media screen and (min-width:480px) and (max-width:800px) {
    @import url(media-normal.css);
}
@media screen and (min-width:800px) {
    @import url(media-large.css);
}

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

Мы можем пойти двумя правильными путями — указать медиа-выражения в подключаемых файлах и просто импортировать их, или же указать условия применимости в самой директиве @import.

Первый вариант:

@import url(media-small.css);
@import url(media-normal.css);
@import url(media-large.css);

Второй вариант:

@import url(media-small.css) screen and (max-width:480px);
@import url(media-normal.css) screen and (min-width:480px) and (max-width:800px);
@import url(media-large.css) screen and (min-width:800px);

Я считаю, что разумнее пользоваться первым вариантом, поскольку рано или поздно придётся делать объединение всех таблиц стилей для выкладки на production. И вот в этом случае, при использовании первого способа будет гораздо проще автоматизировать процесс сборки финального файла стилей с гораздо меньшей вероятностью возникновения ошибок.

Responsive design всем, посоны!