От автора: несмотря на заголовок, эта статья не посвящена каким-либо попыткам избавиться от медиа запросов. Медиа запросы невероятно полезны, я использую их везде. Однако они не решают все наши проблемы с адаптивным дизайном.
Зачастую лучше вносить изменения в расположение элементов по размерам их контейнера, а не вьюпорта. Для решения этой проблемы родилась концепция элементных запросов. И все же в концепции элементных запросов есть изьяны, и Mat Marquis продемонстрировал их и переформулировал концепцию в контейнерные запросы. К сожалению, и эта концепция до сих пор не идеальна.
Когда-нибудь контейнерные запросы смогут решить поставленные задачи, а пока что я собрал парочку способов и техник, с помощью которых можно решить эти проблемы.
Flexbox с flex-wrap
Flex-wrap может решить массу проблем, касающихся ответа на размеры контейнера. Например, часто нужно расположить два элемента рядом, если есть место. Если места недостаточно, элементы должны располагаться один над другим. В демо ниже показан этот пример в действии:
Никаких трюков, просто flexbox и flex-wrap, и все работает. С помощью flexbox можно делать много чего. Можно не просто создавать две колонки, но я не стал усложнять демо. Основные моменты техники очень просты:
1 2 3 4 5 6 |
<div class="container"> <div class="img">...</div> <div class="content">...</div> </div> ... |
1 2 3 4 5 6 7 8 9 10 11 |
.container { display: flex; flex-wrap: wrap; flex-direction: row; } .container .content, .container .img { flex: 1 0 12em; /* Замените 12em на свой брейкпоинт. */ } |
Для правильной работы важно понимать, что из себя представляют свойства flex-grow, flex-shrink и flex-basis. У Zoe Gillenwater есть очень полезный совет по flexbox, помогающий понять связь между этими свойствами.
Техника великолепной четверки
Переключение ширины по брейкпоинтам с помощью свойств width, min-width, max-width и calc (или «техника великолепной четверки») было детищем Rémi Parmentier. Изначально созданная для адаптивных электронных писем, эта техника может легко использоваться и на обычных веб-страницах. Как показал Thierry, эта техника открыла новые возможности в создании самоадаптирующихся модулей. Например:
1 2 3 4 5 6 |
{ min-width: 50%; width: calc((25em - 100%) * 1000); max-width: 100%; /* Измените 25em на свой брейкпоинт. */ } |
Техника работает, так как если width задана в процентах, проценты считаются от ширины контейнера элемента. Функция calc сравнивает это значение с желаемым брейкпоинтом и генерирует очень большое положительное число (если ширина меньше брейкпоинта) или очень отрицательное число (если ширина больше брейкпоинта), или ноль, если ширина совпадает. Большое положительное число записывается в max-width, большое отрицательное или ноль записываются в min-width.
В примере выше мы задали брейкпоинт 25em. Если шрифт равен 16px, это значение переводится в 400px. Если контейнер 400px или выше (т.е. равен или больше брейкпоинта), ширина равна нулю или большому отрицательному числу:
(400 — 400 = 0) * 1000 = 0 or (400 — 401 = -1) * 1000 = -1000
С такими значениями у нас срабатывает min-width, и результирующая ширина элемента в примере выше будет равна 50%. Однако если контейнер 399px и ниже (т.е. меньше брейкпоинта), ширина равна большому положительному числу:
(400 — 399 = 1) * 1000 = 1000
В этом случае срабатывает max-width, и результирующая ширина будет равна 100%. Рисунок ниже должен помочь визуализировать этот процесс:
Четыре демо ниже по-разному используют эту технику для переключения ширины элемента в ответ на ширину контейнера.
Изображение с обтеканием – полная ширина/частичная ширина
В этом демо я использовал технику великолепной четверки вместе со свойством float для переключения изображения с полной ширины на половину в зависимости от ширины контейнера:
Как и в примере с flexbox выше, эта техника позволяет элементам переключаться между одноколоночным видом при маленькой ширине и видом с обтеканием при достаточной ширине.
Изображение с обтеканием – видимый/скрытый
Эта техника адаптирована с предыдущей. Здесь инвертирован результат вычислений, и удалено свойство min-width, что создает переключатель вкл/выкл. Удобно для скрытия декоративных элементов в маленьких контейнерах, ведь они могут занимать ценное пространство:
И для ясности:
1 2 3 4 5 6 7 |
{ /* Удалено свойство min-width, нам нужно, чтобы ширина была равна нулю, а отрицательная ширина также считалась нулем */ /* Инвертированный множитель: */ width: calc((25em - 100%) * -1000); max-width: 100%; /* Смените 25em на свой брейкпоинт. */ } |
Текст и изображение – наложение/стек
Аналогичным образом с предыдущими техниками я использовал дополнительный div, чтобы поместить текст поверх изображения. Если изображение слишком маленькое, и текст его закрывает, он помещается под изображение. Эта часть немного сложная, попробую объяснить.
1 2 3 4 |
.pull { /* Помещаем текст поверх изображения: */ margin-bottom: -10em; } |
Отрицательный margin располагает контент поверх изображения. Однако когда ширина контейнера пересекает брейкпоинт, нам необходимо отключать это свойство. Но у нас нет свойств min/max-margin, поэтому мы не можем использовать технику великолепной четверки.
Как бы то ни было, если padding задан в процентах, то это проценты от ширины контейнера, и padding-top и –bottom повлияют на высоту элемента. Зная это, мы можем использовать calc для создания padding-bottom, которое на основе ширины контейнера будет переключаться между нулем и очень большим значением:
padding-bottom: calc((30em — 100%) * 1000);
Напрямую к .pull мы это применить не можем, у нас нет свойств min/max-padding, чтобы ограничить эти значения. Выход – поместить переключатель padding’а на псевдоэлемент для принудительной смены высоты, а также использовать max-height на .pull и ограничивать высоту на значение отрицательного margin’а. Так мы эффективно компенсируем этот margin.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
.pull { /* Помещаем текст поверх изображения: */ margin-bottom: -10em; /* Не даем контейнеру быть больше: */ max-height: 10em; /* Прячем все, что вылезает за края: */ overflow: hidden; } .pull::before { content: ""; display: block; padding-bottom: calc((30em - 100%) * 1000); /* Смените 30em на свой брейкпоинт */ } |
Эффект градиента перекрытия реализован с помощью переключателя вкл/выкл, как описано ранее:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
.image::after { content: ""; display: block; position: absolute; left: 0; top: 0; /* Gradient to make the text more legible: */ background-image: linear-gradient(to bottom, rgba(0,20,30,0) 0%,rgba(0,20,30,0) 50%,rgba(0,20,30,1) 100%); /* Extra .5% to prevent bleed due to rounding issues: */ height: 100.5%; /* Toggle gradient overlay at the same breakpoint as the 'pull': */ width: calc((30em - 100%) * -1000); /* Change 30em to your breakpoint */ max-width: 100%; } |
Усечение списка
Последняя разработанная мной техника была вдохновлена шаблоном Priority Plus с сайта CSS tricks. Техника довольно простая и не требует JS:
Здесь опять используется техника великолепной четверки, только на этот раз на высоте контейнера, а не ширине.
1 2 3 4 5 6 7 8 |
<div class="outer"> <div class="inner"> <div class="item">...</div> ... <div class="control">...</div> </div> </div> ... |
1 2 3 4 5 6 7 8 |
.outer { height: 2.25em; overflow: hidden; } .outer:target { height: auto; } |
Высота внешнего контейнера фиксирована и прячет любые заступы, только если это не :target.
1 2 3 4 |
.inner { display: flex; flex-wrap: wrap; } |
Внутренний контейнер представляет собой флекс-контейнер со свойством flex-wrap. Когда элементы будут перепрыгивать на строки ниже, высота контейнера будет увеличиваться. Элементы ниже первой сроки прячутся свойством overflow:hidden на контейнере .outer, создавая эффект усечения.
1 2 3 4 5 6 7 8 9 10 11 12 |
.control { height: calc((2.25em - 100%) * -1000); max-height: 2.25em; } :target .control--open { display: none; } :target .control--close { display: block; } |
Элементы more/less видны только, если высота контейнера превышает брейкпоинт (который равен высоте главных ссылок). Состояние :target определяет, какой элемент будет видимым.
Умное выравнивание текста в CSS
Очень удобно выравнивать текст по центру или по левому краю в зависимости от доступного пространства в контейнере по сравнение с длиной текста. Техника за авторством Vijay Sharma делает это очень легко.
Бонус: хак flex-grow 9999
В нашу коллекцию отлично подходит трюк Joren Van Hee – хак flex-grow 9999.
Смотрите, никаких медиа запросов от Vasilis van Gemert
Выступление Vasilis van Gemert смотрите, никаких медиа запросов придало мне импульс на изучение адаптивного дизайна без медиа запросов, что, в свою очередь, привело к написанию этой статьи. Стоит посмотреть его выступление, оно включает в себя парочку других идей, которые, хотя и полезны, не совсем вписываются в тему того, что я здесь представил.
Заключение
Много чего невозможно выполнить без элементных/контейнерных запросов. Список очень длинный, это цвета, размер шрифта, высота строки, рамки и тени, margin и padding. Все это должно настраиваться с помощью элементных/контейнерных запросов в ответ на состояние родительского контейнера, но, увы, в ближайшее время нет никаких признаков, что это воплотится в реальность. Тем не менее, надеюсь, что когда-нибудь что-либо из написанного мной вам пригодится.
Автор: Andy Kirk
Источник: //www.sitepoint.com/
Редакция: Команда webformyself.