Как реализовать адаптивный layout

В современном мире уже никуда не деться без адаптивных layout-ов. В данной статье разберем создание двух вариантов таких интерфейсов: один попроще, другой посложнее.

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

Layout №1 - как из колонок сделать строки

Дано:

  • три колонки: одна широкая, две узкие

Задача:

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

Нам понадобится следующий набор блоков:

  • wrapper в качестве контейнера
  • широкая колонка для контента
  • две узкие колонки

Зададим нашу исходную разметку в HTML:

<div class="wrapper">
  <div class="content">
    <h3>Content</h3>
    Lorem ipsum...
  </div>

  <div class="sidebar-left">
    <h3>Left</h3>
    Lorem ipsum...
  </div>

  <div class="sidebar-right">
    <h3>Right</h3>
    Lorem ipsum...
  </div>
</div>

Теперь займемся описанием стилей стандартного отображения. Возьмем за исходные условия - экран монитора.

Пусть контейнер будет немного отступать от краёв экрана, так что зададим ему ширину 80%, отцентруем и сделаем еще небольшой отступ сверху:

.wrapper {
  width: 80%;
  margin: 0 auto;
  padding-top: 20px;
}

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

.content {
  width: 54%;
  float: left;
  margin-right: 3%;
}

Ширину узких колонок зададим как 20%, и укажем плавающее расположение:

.sidebar-left {
  width: 20%;
  float: left;
  margin-right: 3%;
}

.sidebar-right {
  width: 20%;
  float: left;
}

В результате получим следующий layout:

Теперь потребуется немного уличной магии

Один из главных компонентов адаптивных layout-ов - применение так называемых CSS-медиазапросов. В сети полно информации о том что это и как это, так что не будем сильно останавливаться на этом пункте. Если коротко - используя оператор @media в описании стилей документа, можно указать размер и тип экрана для которого будут применены специфические правила разметки.

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

Самое важное, что необходимо понимать - @media используется для описания правил разметки, которые будут применены к нашему лейауту только при определенных условиях (например, размер экрана меньше заданного). Если проще - внутри @media описываем то, как должен выглядеть layout, если экран меньше/больше/и пр.

Итак, допустим, нам уже понятно для чего нужна @media, мы понимаем как должен выглядеть интерфейс для маленького экрана, но как сделать из колонок строки? Очень просто - внутри @media переопределяем стили наших блоков таким образом, чтобы убрать разметку колонками, а строками они станут сами собой, т.к. это стандартное отображение блоков.

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

@media (max-width: 767px)

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

.wrapper {
	width: 90%;
}

Растянем все наши блоки на всю ширину контейнера, теперь всё-таки это будут строки, а не колонки:

.content,
.sidebar-left,
.sidebar-right {
	width: 100%;
}

Теперь, важный момент - удаляем плавающее расположение блоков при помощи clear:

.sidebar-left,
.sidebar-right {
	clear: both;
}

И добавляем пару новых стилей, которые улучшают восприятие строчного layout'а - отступ сверху и полоска границы:

.sidebar-left,
.sidebar-right {
	margin-top: 20px;
	border-top: 1px solid #ccc;
}

В результате, для экранов шириной меньше чем 768px layout будет выглядеть следующим образом:

Живой пример

See the Pen Adaptive layout by Alexey Silichenko (@asilichenko) on CodePen.

Layout №2 - как изменить структуру разметки и порядок блоков

Исходный layout выглядит следующим образом:

необходимо сделать его адаптивным

Опишем разметку также как в предыдущем примере: один контейнер и несколько блоков внутри него:

  • заголовок, для элементов управления или дополнительной информации
  • название, например, продукта
  • изображение
  • описание
  • футер, для дополнительной иформации
<div class="wrapper">
  <div class="header">Header</div>
  <div class="title">Lorem ipsum dolor sit amet</div>
  <div class="cover"><img ... /></div>
  <div class="descr">Lorem ipsum...</div>
  <div class="footer">Footer</div>
</div>

Все блоки внутри контейнера расположены на одном уровне - так ими проще управлять, поскольку мы создаем не статический, а динамический layout, без использования javascript.

Как обычно, всё самое интересное - в CSS

Поскольку нам нужно управлять расположением элементов layout'а и по строками, и по столбцам, то укажем браузеру, что наш контейнер представляет собой grid-layout. Нам потребуется две колонки: ширина первой определяется содержимым (картинка), вторая - должна занимать всю оставшуюся ширину, и укажем небольшой отступ между ними:

.wrapper {
  display: grid;
  grid-template-columns: min-content auto;
  grid-gap: 10px;
}

Если всё так и оставить, то все блоки друг за другом паровозиком сформируют сетку 2x3:

это не совсем то, что нам нужно

Поскольку мы работаем с grid-разметкой, то чтобы заставить блок с картинкой занимать всю левую сторону необходимо чтобы в описании его стиля были указаны номера строк (точнее грид-линий), между которыми должен располагаться блок:

.cover {
  grid-row-start: 1;
  grid-row-end: 6; /* на 1 строку больше - для создания пустоты */
}

Номер завершающей строки нужно указать на 1 больше, для того, чтобы блоки во второй колонке не растягивались, заполняя всю высоту:

Для того, чтобы размерами картинки было удобнее управлять, конкретные размеры в пикселях задаются блоку-контейнеру, а размеры изображения задаются так, чтобы оно заполняло весь контейнер:

.cover {
  height: 225px;
  width: 165px;
}

.cover img {
  width: 100%;
}

Второй этап - layout для среднего размера экрана

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

Используем уже привычный @media

@media (max-width: 767px)

внутри которого задаем новые размеры изображения:

.cover {
	height: 150px;
	width: 110px;
}

и указываем, что теперь, оно должно находиться между 3 и 4 строчными грид-линиями:

.cover {
	grid-row-start: 3;
	grid-row-end: 4;
}

Далее, необходимо указать, что заголовок, название и футер должны занимать всю ширину грида, то есть располагаться между 1й и 3й вертикальными грид-линиями:

.header,
.title,
.footer {
	grid-column-start: 1;
	grid-column-end: 3;
}

В результате получим следующий layout на экранах шириной до 768px:

Третий этап - layout для небольшого экрана

Думаю, логика действий уже ясна, так что приступим.

На экране смартфона не так чтоб сильно много места, поэтому переведём все блоки в строчный режим, уберём лишние отступы, а к изображению применим плавающий стиль (спойлер: как это сделать - не так очевидно как кажется).

Укажем в новом @media-блоке ограничение по размеру экрана в 500px:

@media (max-width: 500px)

Стоит учитывать, что в данном случае мы переопределяем не только стили по-умолчанию, но и стили, указанные в @media для среднего экрана, т.е. все что задано в @media (max-width: 767px), очевидно будет применяется и для экранов менее 500px. Таким образом, нет необходимости в дублировании.

Сделаем контейнер картинки плавающим и добавим небольшой отступ до текста:

.cover {
	float: left;
	margin-right: 10px;
}

Но если так и оставить, то ничего не изменится! Как в принципе и должно быть, ведь мы указали корневому контейнеру отображать свое содержимое в виде грида, т.е. только колонки и только строки, и никаких плавающих блоков. Как же быть в таком случае? Очень просто - отменим корневому контейнеру необходимость отображаться гридом - указав, например, значение block (в любом случае, теперь раскладка блоков в виде таблицы нам уже не нужна):

.wrapper {
	display: block;
}

При этом, у нас конечно же удалятся и отступы между блоками, т.е. они были заданы для grid-раскладки.

Теперь, удалим все границы внутренних блоков, удалим закругления углов и заливку фона:

.wrapper div {
	border: none;
	border-radius: 0;
	background-color: transparent;
}

но зададим их корневому контейнеру:

.wrapper {
	border: 2px solid #f08c00;
	border-radius: 5px;
	background-color: #ffec99;
}

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

И вуаля, вот наш результат:

Живой пример

See the Pen Adaptive layout v2 by Alexey Silichenko (@asilichenko) on CodePen.

Вместо послесловия

Давно уже большую популярность имеет отображение графического интерфейса с мобильных устройств, и соответственно своего рода золотым правилом стало определение стилей по методике Mobile First. В данной же статье рассмотрено создание layout'a в обратном порядке, но лишь для упрощения понимания процесса. Для ваших проектов, вероятнее всего, более целесообразно - придеживаться методологии Mobile First. В таком случае, пусть формирование Mobile First layout'a будет вам домашним заданием ;-)


No comments:

Post a Comment

Why BQ28Z610 function Current() returns 0 mA

Fixing 0 mA Current Readings on the BQ28Z610 Device Custom driver for the BQ28Z610 device was connected directly via I2C. It is p...