Вёрстка по Flexbox. Часть 1: контейнер и оси

Чтение — около 9 минут· без учёта практики

В уроке «Блочная и строчная модель» мы выстроили меню сайта Тони в строку, сделав пункты блочно-строчными (inline-block). Такой способ работает, но у него есть недостатки: между пунктами появляются промежутки от пробелов в HTML, а выравнивать пункты по высоте и распределять между ними место неудобно. Для раскладки элементов в ряд или в колонку в CSS есть специальная модель — Flexbox.

Что такое Flexbox

Flexbox (от англ. flexible box — «гибкий блок») — модель раскладки CSS, которая выстраивает элементы вдоль одной линии: в строку или в колонку. Её описывает спецификация CSS Flexible Box Layout Module, и её поддерживают все современные браузеры. Flexbox позволяет быстро решать задачи, которые раньше требовали обходных путей:

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

Flexbox удобен для раскладки в одном направлении: меню, ряд кнопок, строка карточек. Для двумерных сеток, где важны и строки, и колонки сразу, есть модель Grid — её мы изучим в уроке «Вёрстка по Grid».

Флекс-контейнер и флекс-элементы

Чтобы верстать по Flexbox, элементу задают свойство display со значением flex. Такой элемент становится флекс-контейнером, а его дочерние элементы в обычном потоке — флекс-элементами. Контейнером может быть любой подходящий по смыслу элемент: список, раздел, шапка и так далее.

CSS
nav ul {
  display: flex; /* список становится флекс-контейнером, пункты li — флекс-элементами */
}

При желании сравните меню из урока о блочной модели и меню на Flexbox. У флекс-элементов нет промежутков от пробелов в HTML: расстояние между ними задаёт свойство gap, о нём ниже. Пункты списка и во флекс-контейнере остаются пунктами списка со своими маркерами, поэтому маркеры убирают свойством list-style: none. У блочно-строчных пунктов маркеров не было: inline-block заменяет значение list-item.

В первом списке между пунктами видны промежутки от переводов строк в HTML. Во втором промежутки задаёт gap. Измените gap на 2rem — расстояние вырастет, а пробелы в HTML на него не влияют.

index.html
HTML
<!doctype html>
<html lang="ru">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Меню: inline-block и Flexbox</title>
    <style>
      body { font-family: system-ui, sans-serif; background-color: linen; color: #2b211b; margin: 1rem; }
      .box { border: 2px dashed tan; padding: 0.5rem; margin-bottom: 1rem; }
      .box > * { background-color: #fffaf3; border: 1px solid saddlebrown; border-radius: 8px; padding: 0.4rem 0.8rem; }
      h3 { font-size: 1rem; margin: 0 0 0.25rem; }
      .inline li { display: inline-block; }
      .flex { display: flex; gap: 0.5rem; list-style: none; }
      ul { padding: 0.5rem; }
    </style>
  </head>
  <body>
    <h3>display: inline-block у пунктов</h3>
    <ul class="box inline">
      <li>Главная</li>
      <li>Мои игрушки</li>
      <li>Запись на прогулку</li>
    </ul>
    <h3>display: flex у списка</h3>
    <ul class="box flex">
      <li>Главная</li>
      <li>Мои игрушки</li>
      <li>Запись на прогулку</li>
    </ul>
  </body>
</html>

Обратите внимание на важный момент: флекс-элементами становятся только дочерние элементы контейнера, а не все его потомки. Элементы, вложенные в дочерние, располагаются как обычно. Если их тоже нужно выстроить по Flexbox, их родителю задают display: flex отдельно.

Если написать текст прямо внутри контейнера, браузер создаст для него анонимный флекс-элемент; одни пробелы между тегами такого элемента не создают. Поэтому для управления отдельными частями удобнее оборачивать их в подходящие HTML-элементы. Абсолютно позиционированные потомки не участвуют в распределении места Flexbox; позиционирование разберём позже.

Только дочерние элементы: попробуйте сами

Три блока div стоят в строку и одинаковой высоты, хотя текста в них разное количество. Абзацы внутри третьего блока — не флекс-элементы: они идут друг под другом. Добавьте правило .card div:last-child { display: flex; } — абзацы тоже встанут в строку.

index.html
HTML
<!doctype html>
<html lang="ru">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Флекс-элементы — только дочерние элементы</title>
    <style>
      body { font-family: system-ui, sans-serif; background-color: linen; color: #2b211b; margin: 1rem; }
      .box { border: 2px dashed tan; padding: 0.5rem; margin-bottom: 1rem; }
      .box > * { background-color: #fffaf3; border: 1px solid saddlebrown; border-radius: 8px; padding: 0.4rem 0.8rem; }
      h3 { font-size: 1rem; margin: 0 0 0.25rem; }
      .card { display: flex; gap: 0.5rem; }
    </style>
  </head>
  <body>
    <section class="box card">
      <div>Мячик</div>
      <div>Канат</div>
      <div>
        Косточка
        <p>Абзац внутри элемента — не флекс-элемент.</p>
        <p>Он стоит под соседним абзацем, как обычно.</p>
      </div>
    </section>
  </body>
</html>

Свойства раскладки, которые мы рассмотрим в этом уроке, задают контейнеру. flex-direction, flex-wrap и flex-flow работают только во Flexbox; свойства промежутков и выравнивания применяются и в других моделях раскладки, например в Grid, о котором мы уже говорили выше.

Строчный флекс-контейнер

По аналогии с блочными и строчными элементами флекс-контейнер может быть блочным или строчным. Значение flex создаёт блочный контейнер: как обычный блочный элемент, он начинается с новой строки и занимает всю доступную ширину. Значение inline-flex создаёт строчный контейнер: снаружи он ведёт себя как строчный элемент и при автоматической ширине подбирает размер по содержимому с учётом доступного места, а внутри раскладывает элементы по тем же правилам Flexbox.

flex и inline-flex: попробуйте сами

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

index.html
HTML
<!doctype html>
<html lang="ru">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Блочный и строчный флекс-контейнер</title>
    <style>
      body { font-family: system-ui, sans-serif; background-color: linen; color: #2b211b; margin: 1rem; }
      .box { border: 2px dashed tan; padding: 0.5rem; margin-bottom: 1rem; }
      .box > * { background-color: #fffaf3; border: 1px solid saddlebrown; border-radius: 8px; padding: 0.4rem 0.8rem; }
      h3 { font-size: 1rem; margin: 0 0 0.25rem; }
      .flex { display: flex; gap: 0.25rem; }
      .inline-flex { display: inline-flex; gap: 0.25rem; }
    </style>
  </head>
  <body>
    <h3>inline-flex</h3>
    <div class="box inline-flex"><span>мячик</span><span>канат</span></div>
    <div class="box inline-flex"><span>кость</span><span>тапок</span></div>
    <h3>flex</h3>
    <div class="box flex"><span>мячик</span><span>канат</span></div>
    <div class="box flex"><span>кость</span><span>тапок</span></div>
  </body>
</html>

Главная и поперечная оси

Флекс-элементы располагаются вдоль главной оси контейнера. Перпендикулярно ей проходит поперечная ось. От направления главной оси зависит, встанут элементы в строку или в колонку, а все свойства выравнивания во Flexbox описывают положение именно относительно этих осей, а не «горизонтали и вертикали».

Направление главной оси задаёт свойство flex-direction:

  • row — значение по умолчанию: элементы выстраиваются в строку, главная ось идёт в направлении текста. Для русского текста это слева направо, а на странице с письмом справа налево (атрибут dir="rtl" или свойство direction со значением rtl) — справа налево;
  • row-reverse — строка, но в обратном направлении: первый элемент оказывается в конце;
  • column — элементы выстраиваются в колонку сверху вниз при обычном горизонтальном письме;
  • column-reverse — колонка в обратном направлении, снизу вверх.
Схема работы свойства flex-direction: направление главной и поперечной осей при значениях row, row-reverse, column и column-reverse.

flex-direction: попробуйте сами

Один и тот же режим дня Тони в четырёх контейнерах с разным направлением. При column главная ось идёт сверху вниз, а поперечная — слева направо.

index.html
HTML
<!doctype html>
<html lang="ru">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Направление главной оси flex-direction</title>
    <style>
      body { font-family: system-ui, sans-serif; background-color: linen; color: #2b211b; margin: 1rem; }
      .box { border: 2px dashed tan; padding: 0.5rem; margin-bottom: 1rem; }
      .box > * { background-color: #fffaf3; border: 1px solid saddlebrown; border-radius: 8px; padding: 0.4rem 0.8rem; }
      h3 { font-size: 1rem; margin: 0 0 0.25rem; }
      .box { display: flex; gap: 0.5rem; }
      .row { flex-direction: row; }
      .row-reverse { flex-direction: row-reverse; }
      .column { flex-direction: column; }
      .column-reverse { flex-direction: column-reverse; }
    </style>
  </head>
  <body>
    <h3>row</h3>
    <div class="box row"><div>1. Подъём</div><div>2. Прогулка</div><div>3. Обед</div></div>
    <h3>row-reverse</h3>
    <div class="box row-reverse"><div>1. Подъём</div><div>2. Прогулка</div><div>3. Обед</div></div>
    <h3>column</h3>
    <div class="box column"><div>1. Подъём</div><div>2. Прогулка</div><div>3. Обед</div></div>
    <h3>column-reverse</h3>
    <div class="box column-reverse"><div>1. Подъём</div><div>2. Прогулка</div><div>3. Обед</div></div>
  </body>
</html>

Промежутки между элементами

Расстояние между флекс-элементами задаёт свойство gap контейнера. Промежуток появляется только между соседними элементами: ни перед первым, ни после последнего лишнего места нет. Одно значение задаёт одинаковый промежуток между элементами в строке и между строками, два значения через пробел — сначала между строками, затем между элементами в строке при направлении row. При column первое значение задаёт промежуток между элементами в колонке, второе — между колонками. Отдельно эти промежутки задают свойства row-gap и column-gap.

Раньше промежутки делали внешними отступами margin у элементов. Но отступ есть и у последнего элемента в строке: он сдвигает соседей и занимает место у края контейнера. С gap эта проблема не возникает.

margin или gap: попробуйте сами

В первом контейнере у каждого элемента внешний отступ справа и снизу: у правого края и под последней строкой остаются лишние полосы. Во втором промежутки только между элементами.

index.html
HTML
<!doctype html>
<html lang="ru">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Промежутки: margin или gap</title>
    <style>
      body { font-family: system-ui, sans-serif; background-color: linen; color: #2b211b; margin: 1rem; }
      .box { border: 2px dashed tan; padding: 0.5rem; margin-bottom: 1rem; }
      .box > * { background-color: #fffaf3; border: 1px solid saddlebrown; border-radius: 8px; padding: 0.4rem 0.8rem; }
      h3 { font-size: 1rem; margin: 0 0 0.25rem; }
      .box { display: flex; flex-wrap: wrap; width: 18rem; }
      .margin > * { margin-right: 0.5rem; margin-bottom: 0.5rem; }
      .gap { gap: 0.5rem; }
    </style>
  </head>
  <body>
    <h3>margin у каждого элемента</h3>
    <div class="box margin"><div>мячик</div><div>канат</div><div>кость</div><div>тапок</div><div>шарик</div></div>
    <h3>gap у контейнера</h3>
    <div class="box gap"><div>мячик</div><div>канат</div><div>кость</div><div>тапок</div><div>шарик</div></div>
  </body>
</html>

Перенос элементов

По умолчанию флекс-контейнер однострочный: все элементы стоят в одной строке, даже если им не хватает места. Они сжимаются, а если сжаться дальше нельзя, выходят за пределы контейнера. Сделать контейнер многострочным позволяет свойство flex-wrap:

  • nowrap — значение по умолчанию: все элементы в одной строке;
  • wrap — элементы, которым не хватает места, переносятся на следующую строку;
  • wrap-reverse — перенос, но новые строки появляются в обратном порядке: вторая строка над первой.
Схема работы свойства flex-wrap: однострочный контейнер и перенос элементов на новые строки.

flex-wrap: попробуйте сами

Пункты оглавления Тони в контейнерах шириной 20rem. При nowrap они сжимаются в одну строку и длинные подписи переносятся внутри пунктов. При wrap пункты переходят на новую строку целиком.

index.html
HTML
<!doctype html>
<html lang="ru">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Перенос flex-wrap</title>
    <style>
      body { font-family: system-ui, sans-serif; background-color: linen; color: #2b211b; margin: 1rem; }
      .box { border: 2px dashed tan; padding: 0.5rem; margin-bottom: 1rem; }
      .box > * { background-color: #fffaf3; border: 1px solid saddlebrown; border-radius: 8px; padding: 0.4rem 0.8rem; }
      h3 { font-size: 1rem; margin: 0 0 0.25rem; }
      .box { display: flex; gap: 0.5rem; width: 20rem; }
      .nowrap { flex-wrap: nowrap; }
      .wrap { flex-wrap: wrap; }
      .wrap-reverse { flex-wrap: wrap-reverse; }
    </style>
  </head>
  <body>
    <h3>nowrap</h3>
    <div class="box nowrap"><div>Моя любимая игрушка</div><div>Команды</div><div>Мой режим дня</div><div>Где я гуляю</div></div>
    <h3>wrap</h3>
    <div class="box wrap"><div>Моя любимая игрушка</div><div>Команды</div><div>Мой режим дня</div><div>Где я гуляю</div></div>
    <h3>wrap-reverse</h3>
    <div class="box wrap-reverse"><div>Моя любимая игрушка</div><div>Команды</div><div>Мой режим дня</div><div>Где я гуляю</div></div>
  </body>
</html>

Сокращённое свойство flex-flow

Свойство flex-flow объединяет flex-direction и flex-wrap в одном объявлении. Можно указать значение одного из свойств или оба через пробел — второе при этом принимает значение по умолчанию.

CSS
.toc {
  flex-flow: row wrap; /* то же, что flex-direction: row; flex-wrap: wrap; */
}

flex-flow: попробуйте сами

flex-flow: column — колонка без переноса, row wrap — строка с переносом, row-reverse wrap — строка с переносом в обратном направлении: первый пункт справа.

index.html
HTML
<!doctype html>
<html lang="ru">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Сокращённое свойство flex-flow</title>
    <style>
      body { font-family: system-ui, sans-serif; background-color: linen; color: #2b211b; margin: 1rem; }
      .box { border: 2px dashed tan; padding: 0.5rem; margin-bottom: 1rem; }
      .box > * { background-color: #fffaf3; border: 1px solid saddlebrown; border-radius: 8px; padding: 0.4rem 0.8rem; }
      h3 { font-size: 1rem; margin: 0 0 0.25rem; }
      .box { display: flex; gap: 0.5rem; width: 20rem; }
      .one { flex-flow: column; }
      .two { flex-flow: row wrap; }
      .three { flex-flow: row-reverse wrap; }
    </style>
  </head>
  <body>
    <h3>flex-flow: column</h3>
    <div class="box one"><div>Моя любимая игрушка</div><div>Команды</div><div>Мой режим дня</div></div>
    <h3>flex-flow: row wrap</h3>
    <div class="box two"><div>Моя любимая игрушка</div><div>Команды</div><div>Мой режим дня</div></div>
    <h3>flex-flow: row-reverse wrap</h3>
    <div class="box three"><div>Моя любимая игрушка</div><div>Команды</div><div>Мой режим дня</div></div>
  </body>
</html>

Выравнивание по главной оси

Свойство justify-content определяет, как распределить свободное место вдоль главной оси — между элементами и вокруг них. Когда элементы заполнили строку целиком, свободного места для промежутков нет. При переполнении выравнивание всё же действует: например, center центрирует строку, и она может выйти за оба края контейнера. Поэтому выравнивание не заменяет настройку переноса и сжатия элементов.

  • flex-start — элементы прижаты к началу главной оси. Так они стоят и по умолчанию;
  • flex-end — элементы прижаты к концу главной оси;
  • center — элементы стоят по центру;
  • space-between — первый элемент в начале, последний в конце, свободное место поровну между ними;
  • space-around — вокруг каждого элемента одинаковое место, поэтому у краёв промежуток вдвое меньше, чем между соседями;
  • space-evenly — все промежутки одинаковые, включая промежутки у краёв.
Схема работы свойства justify-content: положение элементов вдоль главной оси при разных значениях. Схема значения space-evenly свойства justify-content: одинаковые промежутки между элементами и у краёв контейнера.

justify-content: попробуйте сами

Три пункта меню в контейнерах с разными значениями justify-content. Добавьте одному из контейнеров flex-direction: column и высоту height: 12rem — выравнивание пойдёт сверху вниз, потому что главная ось стала вертикальной.

index.html
HTML
<!doctype html>
<html lang="ru">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Выравнивание по главной оси justify-content</title>
    <style>
      body { font-family: system-ui, sans-serif; background-color: linen; color: #2b211b; margin: 1rem; }
      .box { border: 2px dashed tan; padding: 0.5rem; margin-bottom: 1rem; }
      .box > * { background-color: #fffaf3; border: 1px solid saddlebrown; border-radius: 8px; padding: 0.4rem 0.8rem; }
      h3 { font-size: 1rem; margin: 0 0 0.25rem; }
      .box { display: flex; }
      .flex-start { justify-content: flex-start; }
      .flex-end { justify-content: flex-end; }
      .center { justify-content: center; }
      .space-between { justify-content: space-between; }
      .space-around { justify-content: space-around; }
      .space-evenly { justify-content: space-evenly; }
    </style>
  </head>
  <body>
    <h3>flex-start</h3>
    <div class="box flex-start"><div>Главная</div><div>Игрушки</div><div>Запись</div></div>
    <h3>flex-end</h3>
    <div class="box flex-end"><div>Главная</div><div>Игрушки</div><div>Запись</div></div>
    <h3>center</h3>
    <div class="box center"><div>Главная</div><div>Игрушки</div><div>Запись</div></div>
    <h3>space-between</h3>
    <div class="box space-between"><div>Главная</div><div>Игрушки</div><div>Запись</div></div>
    <h3>space-around</h3>
    <div class="box space-around"><div>Главная</div><div>Игрушки</div><div>Запись</div></div>
    <h3>space-evenly</h3>
    <div class="box space-evenly"><div>Главная</div><div>Игрушки</div><div>Запись</div></div>
  </body>
</html>

Выравнивание по поперечной оси

Свойство align-items выравнивает элементы вдоль поперечной оси — внутри строки, в которой они стоят. Его действие похоже на justify-content, только по перпендикулярной оси.

  • stretch — элементы растягиваются на всю высоту строки (при направлении column — на всю ширину), если размер по этой оси равен auto и нет автоматических отступов. Минимальный и максимальный размеры ограничивают растягивание. Так обычные колонки во Flexbox получают одинаковую высоту;
  • flex-start — элементы прижаты к началу поперечной оси;
  • flex-end — к концу поперечной оси;
  • center — по центру поперечной оси. Так блок центрируют по вертикали;
  • baseline — элементы выравниваются по базовой линии текста: буквы разного размера стоят на одной линии.
Схема работы свойства align-items: положение элементов вдоль поперечной оси при разных значениях.

align-items: попробуйте сами

У второго элемента шрифт крупнее. При stretch все элементы растянуты на высоту контейнера, при center стоят посередине, а при baseline у слов «Тони», «гав!» и «мячик» общая линия букв.

index.html
HTML
<!doctype html>
<html lang="ru">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Выравнивание по поперечной оси align-items</title>
    <style>
      body { font-family: system-ui, sans-serif; background-color: linen; color: #2b211b; margin: 1rem; }
      .box { border: 2px dashed tan; padding: 0.5rem; margin-bottom: 1rem; }
      .box > * { background-color: #fffaf3; border: 1px solid saddlebrown; border-radius: 8px; padding: 0.4rem 0.8rem; }
      h3 { font-size: 1rem; margin: 0 0 0.25rem; }
      .box { display: flex; gap: 0.5rem; height: 6rem; }
      .box > :nth-child(2) { font-size: 1.5rem; }
      .stretch { align-items: stretch; }
      .flex-start { align-items: flex-start; }
      .flex-end { align-items: flex-end; }
      .center { align-items: center; }
      .baseline { align-items: baseline; }
    </style>
  </head>
  <body>
    <h3>stretch</h3>
    <div class="box stretch"><div>Тони</div><div>гав!</div><div>мячик</div></div>
    <h3>flex-start</h3>
    <div class="box flex-start"><div>Тони</div><div>гав!</div><div>мячик</div></div>
    <h3>flex-end</h3>
    <div class="box flex-end"><div>Тони</div><div>гав!</div><div>мячик</div></div>
    <h3>center</h3>
    <div class="box center"><div>Тони</div><div>гав!</div><div>мячик</div></div>
    <h3>baseline</h3>
    <div class="box baseline"><div>Тони</div><div>гав!</div><div>мячик</div></div>
  </body>
</html>

Выравнивание строк

Если контейнер многострочный (flex-wrap: wrap или wrap-reverse) и вдоль поперечной оси у него есть свободное место, свойство align-content распределяет это место между строками. Оно работает с целыми строками, а align-items — с элементами внутри каждой строки. При nowrap свойство align-content ни на что не влияет. При wrap или wrap-reverse оно может действовать даже тогда, когда все элементы поместились в одну строку.

Значения те же, что у justify-content, и ещё stretch: по умолчанию строки растягиваются и делят свободное место поровну. flex-start, flex-end и center собирают строки в начале, в конце или по центру поперечной оси, а space-between, space-around и space-evenly распределяют между ними промежутки.

Схема работы свойства align-content: распределение строк многострочного контейнера вдоль поперечной оси. Схема значения space-evenly свойства align-content: одинаковые промежутки между строками и у краёв контейнера.

align-content: попробуйте сами

Сравните распределение строк в контейнерах высотой 10rem. В двух последних контейнерах фактически одна строка: при wrap её центрирует align-content, при nowrap это свойство не действует.

index.html
HTML
<!doctype html>
<html lang="ru">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Выравнивание строк align-content</title>
    <style>
      body { font-family: system-ui, sans-serif; background-color: linen; color: #2b211b; margin: 1rem; }
      .box { border: 2px dashed tan; padding: 0.5rem; margin-bottom: 1rem; }
      .box > * { background-color: #fffaf3; border: 1px solid saddlebrown; border-radius: 8px; padding: 0.4rem 0.8rem; }
      h3 { font-size: 1rem; margin: 0 0 0.25rem; }
      .box { display: flex; flex-wrap: wrap; gap: 0.5rem; width: 20rem; height: 10rem; }
      .stretch { align-content: stretch; }
      .flex-start { align-content: flex-start; }
      .center { align-content: center; }
      .space-between { align-content: space-between; }
      .one-row { align-content: center; align-items: flex-start; }
      .no-wrap { flex-wrap: nowrap; }
    </style>
  </head>
  <body>
    <h3>stretch</h3>
    <div class="box stretch"><div>Моя любимая игрушка</div><div>Команды</div><div>Мой режим дня</div><div>Где я гуляю</div></div>
    <h3>flex-start</h3>
    <div class="box flex-start"><div>Моя любимая игрушка</div><div>Команды</div><div>Мой режим дня</div><div>Где я гуляю</div></div>
    <h3>center</h3>
    <div class="box center"><div>Моя любимая игрушка</div><div>Команды</div><div>Мой режим дня</div><div>Где я гуляю</div></div>
    <h3>space-between</h3>
    <div class="box space-between"><div>Моя любимая игрушка</div><div>Команды</div><div>Мой режим дня</div><div>Где я гуляю</div></div>
    <h3>wrap: одна фактическая строка, align-content: center</h3>
    <div class="box one-row"><div>1</div><div>2</div><div>3</div></div>
    <h3>nowrap: align-content не действует</h3>
    <div class="box one-row no-wrap"><div>1</div><div>2</div><div>3</div></div>
  </body>
</html>

Flexbox в инструментах разработчика

На вкладке Elements инструментов разработчика Google Chrome рядом с флекс-контейнером стоит значок flex. Нажмите его, и браузер покажет на странице границы контейнера, элементов и промежутков gap. На вкладке Styles рядом с объявлением display: flex есть кнопка редактора Flexbox: в нём значения flex-direction, flex-wrap, justify-content, align-items и align-content переключаются кнопками с наглядными схемами. Так удобно подобрать значение, а затем перенести его в свою таблицу стилей.

Потренируйтесь

Меняйте свойства контейнера и следите, как располагаются пункты оглавления Тони. Ползунок «Ширина превью» сужает контейнер: так видно, когда пунктам перестаёт хватать места и как работает перенос. Свойства самих флекс-элементов рассмотрим во второй части урока.

Цвета и отступы элементов превью — только оформление, в код они не входят.

Контейнер .container

Главная ось: элементы выстраиваются в строку или в колонку, в прямом или обратном порядке. Справочник: flex-direction

Переносить ли элементы на новую линию, когда им не хватает места. Справочник: flex-wrap

Распределение элементов и свободного места вдоль главной оси. Справочник: justify-content

Выравнивание элементов поперёк главной оси внутри своей линии. Справочник: align-items

Распределение линий при переносе. Работает только с flex-wrap: wrap или wrap-reverse. Справочник: align-content

Расстояние между строками и колонками. Можно указать два значения: по вертикали и по горизонтали. Справочник: gap

Минимальная высота контейнера. Без свободного места выравнивание по поперечной оси незаметно. Справочник: min-height

Элементы

Выберите элемент в превью или в списке «Настраиваем», чтобы изменить его свойства. Общие настройки всех элементов — пункт «все элементы (.item)».

CSS
.container {
  display: flex;
  gap: 8px;
  min-height: 180px;
}

Свойства элементов и готовые макеты — в конструкторе Flexbox

Проверьте себя

Выберите ответ — объяснение появится сразу. Ответ можно менять.

1. Списку ul задано display: flex. Какие элементы стали флекс-элементами?
Показать ответ

Только пункты li — дочерние элементы списка — Флекс-элементами становятся только дочерние элементы контейнера. Ссылки внутри пунктов располагаются как обычно.

2. Чем контейнер с display: inline-flex отличается от контейнера с display: flex?
Показать ответ

Снаружи он ведёт себя как строчный элемент и занимает ширину по своим элементам — Строчный флекс-контейнер стоит в строке рядом с соседями, а внутри раскладывает элементы по тем же правилам Flexbox.

3. Контейнеру задано flex-direction: column. Куда направлена главная ось?
Показать ответ

Сверху вниз — При column элементы выстраиваются в колонку, главная ось идёт сверху вниз, а поперечная — в направлении текста.

4. Ссылки меню переставлены свойством flex-direction: row-reverse. В каком порядке клавиша Tab переводит между ними фокус?
Показать ответ

В порядке ссылок в HTML, хотя на экране они стоят в обратном порядке — Обратное направление меняет только вид. Фокус и экранный диктор следуют порядку в HTML, поэтому порядок по смыслу задают в разметке.

5. Чем свойство gap удобнее внешних отступов margin у флекс-элементов?
Показать ответ

Промежуток появляется только между соседними элементами, без лишнего места у краёв — Отступ margin есть и у крайних элементов, а gap задаёт расстояние только между соседями.

6. Пунктам оглавления не хватает места в одной строке. Какое свойство разрешит переносить их на новую строку?
Показать ответ

flex-wrap: wrap — По умолчанию контейнер однострочный (nowrap). Значение wrap делает его многострочным.

7. Какое значение justify-content ставит первый элемент в начало, последний в конец, а свободное место делит поровну между ними?
Показать ответ

space-between — При space-between у краёв промежутков нет, а между соседями они одинаковые.

8. Как по умолчанию располагаются флекс-элементы вдоль поперечной оси, если у них не задана высота?
Показать ответ

Растягиваются на всю высоту строки — По умолчанию элементы растягиваются вдоль поперечной оси, как при align-items: stretch. Поэтому колонки во Flexbox одинаковой высоты.

9. Однострочному контейнеру (flex-wrap: nowrap) задали align-content: center. Что изменится?
Показать ответ

Ничего: align-content распределяет строки только в многострочном контейнере — Чтобы выровнять элементы внутри единственной строки, используют align-items.

Задание

Ожидаемый результат: на страницах с навигацией пункты меню стоят в строку с равными промежутками и без маркеров. На главной пункты оглавления — «таблетки» с рамкой, а при сужении окна те, что не помещаются, переходят на новую строку. Проверьте на вкладке Elements: у nav ul и .toc есть значок flex.

Выполните задание

css/style.css
CSS
/* Общие стили сайта Тони */

/* Ширина и высота включают внутренние отступы и рамку — у всех элементов и псевдоэлементов */
*,
*::before,
*::after {
  box-sizing: border-box;
}

/* Шрифт заголовков Nunito (лицензия SIL Open Font License): кириллица и латиница в разных файлах */
@font-face {
  font-family: "Nunito";
  src: url("../assets/nunito-cyrillic-800-normal.woff2") format("woff2");
  font-weight: 800;
  font-display: swap; /* пока шрифт загружается, текст виден запасным шрифтом */
  unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: "Nunito";
  src: url("../assets/nunito-latin-800-normal.woff2") format("woff2");
  font-weight: 800;
  font-display: swap;
  unicode-range: U+0000-00FF, U+2000-206F, U+20AC, U+2122;
}

body {
  background-color: linen;
  color: #2b211b; /* цвет для потомков без собственного значения */
  font-size: 1.0625rem; /* 17px при настройке браузера по умолчанию */
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; /* системный шрифт устройства */
  line-height: 1.6; /* множитель: у каждого элемента интервал от его собственного размера шрифта */
  margin: 0; /* убираем отступ браузера: шапка и подвал во всю ширину окна */
}

/* Поля основного содержимого: текст не прижимается к краям окна */
main {
  padding: 1.5rem 1rem;
  max-width: 68rem; /* на широком экране строки не растягиваются на всё окно */
  margin: 0 auto; /* колонка по центру */
}

/* Изображения и видео не шире колонки, пропорции сохраняются */
img,
video {
  max-width: 100%;
  height: auto;
}

/* Фреймы, аудиоплеер, индикаторы и поля формы не выходят за колонку */
progress,
meter,
iframe,
audio,
input,
select,
textarea,
button {
  max-width: 100%;
}

/* Разрешаем группе полей сужаться вместе с колонкой. */
fieldset {
  min-width: 0;
}

/* Общий цвет заголовков — групповой селектор */
h1,
h2 {
  color: saddlebrown;
  font-family: "Nunito", "Trebuchet MS", system-ui, sans-serif;
  font-weight: 800;
  line-height: 1.2; /* крупному тексту хватает меньшего интервала */
}

/* Размеры заголовков в rem — от размера шрифта корня, а не родителя */
h1 {
  text-align: center;
  font-size: 2.5rem;
}

h2 {
  font-size: 1.75rem;
}

/* Вводный блок главной страницы */
.intro {
  background-color: hsl(30, 80%, 95%);
  padding: 1.5rem; /* фон вокруг текста; заодно не выпускает margin заголовка за пределы блока */
  border-radius: 16px; /* скругляется и фон, хотя рамки нет */
  /* Лапка в правом нижнем углу; цвет фона выше остаётся запасным, если картинка не загрузится */
  background-image: url("../assets/paw.svg");
  background-repeat: no-repeat;
  background-position: right 1rem bottom 1rem;
  background-size: 4rem;
}

/* Разделы главной — светлые карточки на фоне страницы */
main > section {
  background-color: #fffaf3;
  border: 1px solid hsl(28, 30%, 82%);
  border-radius: 16px;
  padding: 1.5rem;
  margin-top: 1.5rem;
}

/* Ширина вводных абзацев ограничена 60ch; количество букв в строке зависит от шрифта и текста */
.intro p {
  max-width: 60ch;
}

/* Важное предупреждение во вводном блоке — темнее основного акцента */
.intro strong {
  color: #6e3510;
}

/* Оглавление главной страницы */
.toc {
  background-color: white;
  border: 1px solid tan;
}

/* Подчёркивание ссылок чуть ниже букв: не задевает выносные элементы */
a {
  text-underline-offset: 3px;
}

/* Тонкая линия отделяет шапку от страницы */
header {
  border-bottom: 1px solid tan;
}

/* Меню в одну строку: пункты становятся блочно-строчными */
nav ul {
  margin: 0;
  padding: 0.5rem 1rem;
}

nav li {
  display: inline-block;
}

/* Ссылки меню в шапке — селектор потомков */
nav a {
  color: saddlebrown;
  text-decoration: none;
  display: inline-block; /* у строчной ссылки вертикальный padding не раздвигает строку */
  padding: 0.4rem 0.9rem;
  border-radius: 999px; /* «таблетка»: радиус больше половины высоты */
}

/* Ссылки оглавления главной страницы */
.toc a {
  color: #6b5d52; /* тёплый серый: контраст 6.34:1 на белом фоне оглавления */
}

/* Фотографии со скруглёнными углами */
figure img {
  border-radius: 8px;
}

figcaption {
  color: #6b5d52; /* тёплый серый: контраст 5.64:1 на фоне linen */
  font-size: 0.95rem;
}

footer {
  background-color: hsl(30, 50%, 90%);
  text-align: center;
  padding: 1rem;
}

/* Ссылка в подвале берёт цвет текста подвала */
footer a {
  color: inherit;
}

/* Поля формы получают шрифт страницы вместо шрифта браузера */
input,
select,
textarea,
button {
  font: inherit;
}

/* Ссылки темнеют при наведении указателя */
a:hover {
  color: #5c2d0c;
}

/* Ссылки меню подчёркиваются при наведении и фокусе с клавиатуры */
nav a:hover,
nav a:focus-visible {
  text-decoration: underline;
}

/* Заметная рамка фокуса у ссылок, полей и кнопок при работе с клавиатуры */
:focus-visible {
  outline: 3px solid #1f6feb;
  outline-offset: 3px;
}

/* Цитата из книги — шрифтом с засечками и курсивом */
blockquote {
  font-family: Georgia, "Times New Roman", serif;
  font-style: italic;
  border-left: 4px solid tan; /* черта слева выделяет цитату */
  padding-left: 1rem;
}

/* Подпись под цитатой — у правого края */
blockquote + figcaption {
  text-align: right;
}
index.html
HTML
<!doctype html>
<html lang="ru">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="Сайт карликового пинчера Тони: игрушки, режим дня и запись на прогулку.">
    <title>Сайт Тони</title>
    <link rel="stylesheet" href="css/style.css">
  </head>
  <body>
    <header>
      <!-- Меню сайта -->
      <nav>
        <ul>
          <li><a href="index.html">Главная</a></li>
          <li><a href="pages/toys.html">Мои игрушки</a></li>
          <li><a href="pages/signup.html">Запись на прогулку</a></li>
        </ul>
      </nav>
    </header>
    <main>
      <div class="intro">
        <h1 id="top">Привет! Меня зовут Тони</h1>
        <p>Я карликовый пинчер. Мне три года, я вешу 8&nbsp;кг и люблю гулять в любую погоду. Хозяин говорит: <q>Тони — лучший сторож в доме</q>.</p>
        <p>Мой день рождения — <time datetime="2023-09-22">22 сентября</time>. <strong>Пожалуйста, не кормите меня со стола!</strong></p>
        <p>Моя родословная записана в Российской кинологической федерации (<abbr title="Российская кинологическая федерация">РКФ</abbr>).</p>
      </div>
      <ul class="toc">
        <li><a href="#toy">Моя любимая игрушка</a></li>
        <li><a href="#commands">Команды, которые я знаю</a></li>
        <li><a href="#schedule">Мой режим дня</a></li>
        <li><a href="#walks">Где я гуляю</a></li>
        <li><a href="#song">Песня для прогулок</a></li>
      </ul>
      <section>
        <h2 id="toy">Моя любимая игрушка</h2>
        <p data-toy-id="17">Это канат с мячиком. Хозяин бросает его, а я приношу обратно — <em>почти</em> всегда. <a href="pages/toys.html">Посмотреть все игрушки Тони</a>.</p>
        <figure>
          <img src="assets/tony-toy.png" alt="Тони сидит и держит в зубах канат с красным мячиком" width="300" height="400" title="Мой канат &quot;Удав&quot;">
          <figcaption>Я и мой канат «Удав»</figcaption>
        </figure>
        <p><a href="assets/tony-toy.png" download>Скачать фотографию</a></p>
        <p>Подробнее о моей породе — в статье <a href="https://ru.wikipedia.org/wiki/Карликовый_пинчер" target="_blank">«Карликовый пинчер» в Википедии</a>.</p>
        <hr>
        <p>Вечером игра закончилась. Канат остался на полу, а я свернулся калачиком в кресле.</p>
      </section>
      <section>
        <h2>Мой стишок</h2>
        <p>
          Я маленький, но смелый,<br>
          Гуляю целый день,<br>
          А вечером на кресле<br>
          Сплю — и мне не лень.
        </p>
      </section>
      <section>
        <h2 id="commands">Команды, которые я знаю</h2>
        <p>Хозяин научил меня командам на немецком:</p>
        <dl>
          <dt lang="de">Sitz!</dt>
          <dd>сидеть</dd>
          <dt lang="de">Platz!</dt>
          <dd>лежать</dd>
          <dt lang="de">Fuß!</dt>
          <dd>рядом</dd>
        </dl>
        <details>
          <summary>Почему команды на немецком?</summary>
          <p>Карликовый пинчер — немецкая порода, и хозяину понравилась эта традиция.</p>
        </details>
      </section>
      <section>
        <h2 id="schedule">Мой режим дня</h2>
        <table>
          <caption>Режим дня Тони</caption>
          <thead>
            <tr>
              <th scope="col">Время</th>
              <th scope="col">Будни</th>
              <th scope="col">Выходные</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <th scope="row">07:00</th>
              <td>Прогулка, 20 минут</td>
              <td>Сплю</td>
            </tr>
            <tr>
              <th scope="row">08:00</th>
              <td colspan="2">Завтрак</td>
            </tr>
            <tr>
              <th scope="row">13:00</th>
              <td>Жду хозяина и сплю</td>
              <td>Прогулка в парке, 1 час</td>
            </tr>
            <tr>
              <th scope="row">19:00</th>
              <td colspan="2">Ужин</td>
            </tr>
            <tr>
              <th scope="row">21:00</th>
              <td colspan="2">Вечерняя прогулка</td>
            </tr>
          </tbody>
        </table>
      </section>
      <section>
        <h2 id="progress">Мои успехи</h2>
        <p>Учу команду «Апорт»: пройдено 3 занятия из 5. <progress value="3" max="5">3 из 5</progress></p>
        <p>Прогулка сегодня: 40 минут. <meter value="40" min="0" max="90" low="30" high="60" optimum="75">40 из 90 минут</meter></p>
      </section>
      <section>
        <h2 id="walks">Где я гуляю</h2>
        <p>Я люблю гулять в сквере у дома.</p>
        <p>
          <a href="pages/walks.html" target="walk">Маршрут</a> |
          <a href="assets/tony.png" target="walk">Фото с прогулки</a>
        </p>
        <iframe src="pages/walks.html" name="walk" title="Маршрут и фото прогулки Тони" width="320" height="420"></iframe>
        <h3>Видео с прогулки</h3>
        <p>Субтитры помогут, если вы смотрите видео без звука.</p>
        <video width="180" height="320" poster="assets/walk.jpg" controls>
          <source src="assets/walk.mp4" type="video/mp4">
          <track src="assets/ru.vtt" kind="subtitles" srclang="ru" label="Русский" default>
          <p><a href="assets/walk.mp4">Скачать видео</a></p>
        </video>
        <h3>Как я лаю</h3>
        <p>Так я разговариваю с хозяином — у нас целый диалог!</p>
        <audio controls>
          <source src="assets/bark.mp3" type="audio/mpeg">
          <p><a href="assets/bark.mp3">Скачать запись</a></p>
        </audio>
      </section>
      <section>
        <h2 id="song">Песня для прогулок</h2>
        <p>Хозяин включает эту песню, когда мы выходим гулять.</p>
        <iframe width="480" height="270" src="https://www.youtube.com/embed/ojULkWEUsPs?start=17" title="Baha Men — Who Let the Dogs Out" loading="lazy" allow="fullscreen"></iframe>
        <p><a href="https://www.youtube.com/watch?v=ojULkWEUsPs">Baha Men — Who Let the Dogs Out на YouTube</a></p>
      </section>
      <section>
        <h2>Моя любимая книга</h2>
        <p>Хозяин читал мне вслух рассказ <cite>«Каштанка»</cite> Антона Чехова. Он начинается так:</p>
        <figure>
          <blockquote>
            <p>Молодая рыжая собака — помесь таксы с дворняжкой — очень похожая мордой на лисицу, бегала взад и вперёд по тротуару и беспокойно оглядывалась по сторонам.</p>
          </blockquote>
          <figcaption>— Антон Чехов, <cite>«Каштанка»</cite></figcaption>
        </figure>
      </section>
      <p><a href="#top">Наверх</a></p>
    </main>
    <footer>
      <p><small>&copy; 2026 Тони и его хозяин</small></p>
      <address>Написать хозяину Тони: <a href="mailto:tony@example.com">tony@example.com</a></address>
    </footer>
  </body>
</html>
pages/signup.html
HTML
<!doctype html>
<html lang="ru">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="Запишитесь на совместную прогулку с карликовым пинчером Тони.">
    <title>Запись на прогулку с Тони</title>
    <link rel="stylesheet" href="../css/style.css">
  </head>
  <body>
    <header>
      <nav>
        <ul>
          <li><a href="../index.html">Главная</a></li>
          <li><a href="toys.html">Мои игрушки</a></li>
          <li><a href="signup.html">Запись на прогулку</a></li>
        </ul>
      </nav>
    </header>
    <main>
      <h1>Запись на прогулку</h1>
      <p>Гуляйте вместе с Тони! Оставьте заявку, и хозяин Тони напишет вам, чтобы договориться о встрече.</p>
      <p><a href="../index.html#walks">Где мы гуляем</a></p>
      <form>
        <fieldset>
          <legend>О вас</legend>
          <p>
            <label for="owner">Ваше имя</label>
            <input type="text" id="owner" name="owner" autocomplete="name" required>
          </p>
          <p>
            <label for="email">Электронная почта</label>
            <input type="email" id="email" name="email" autocomplete="email" placeholder="anna@example.com" required>
          </p>
        </fieldset>
        <fieldset>
          <legend>Ваша собака</legend>
          <p>
            <label for="breed">Порода</label>
            <input type="text" id="breed" name="breed" list="breeds">
            <datalist id="breeds">
              <option value="Карликовый пинчер"></option>
              <option value="Такса"></option>
              <option value="Йоркширский терьер"></option>
              <option value="Беспородная"></option>
            </datalist>
          </p>
          <p>
            <label for="dogs">Сколько собак придёт</label>
            <input type="number" id="dogs" name="dogs" min="1" max="3" value="1">
          </p>
        </fieldset>
        <fieldset>
          <legend>Когда гулять</legend>
          <p>
            <label for="date">Дата</label>
            <input type="date" id="date" name="date" required>
          </p>
          <label><input type="radio" name="time" value="morning" checked> Утром</label>
          <label><input type="radio" name="time" value="evening"> Вечером</label>
        </fieldset>
        <fieldset>
          <legend>Прогулка</legend>
          <p>
            <label for="leader">Ведёт прогулку</label>
            <input type="text" id="leader" name="leader" value="Тони" readonly>
          </p>
          <p>
            <label for="route">Маршрут</label>
            <select id="route" name="route">
              <optgroup label="В городе">
                <option value="square">Сквер у дома</option>
                <option value="pond" selected>Пруд с утками</option>
              </optgroup>
              <optgroup label="За городом">
                <option value="forest">Лес</option>
                <option value="river" disabled>Берег реки — закрыт до весны</option>
              </optgroup>
            </select>
          </p>
          <p>
            <label for="wishes">Пожелания</label><br>
            <textarea id="wishes" name="wishes" rows="4" cols="40" maxlength="300" placeholder="Например: моя собака боится велосипедов"></textarea>
          </p>
        </fieldset>
        <fieldset>
          <legend>Что взять с собой</legend>
          <label><input type="checkbox" name="take" value="ball"> Мячик</label>
          <label><input type="checkbox" name="take" value="rope"> Канат</label>
        </fieldset>
        <p>
          <button type="submit">Записаться на прогулку</button>
          <button type="reset">Очистить форму</button>
        </p>
      </form>
    </main>
    <footer>
      <p><small>&copy; 2026 Тони и его хозяин</small></p>
      <address>Написать хозяину Тони: <a href="mailto:tony@example.com">tony@example.com</a></address>
    </footer>
  </body>
</html>
pages/toys.html
HTML
<!doctype html>
<html lang="ru">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="Любимые игрушки Тони и правила игры в канат.">
    <title>Игрушки Тони</title>
    <link rel="stylesheet" href="../css/style.css">
  </head>
  <body>
    <header>
      <nav>
        <ul>
          <li><a href="../index.html">Главная</a></li>
          <li><a href="toys.html">Мои игрушки</a></li>
          <li><a href="signup.html">Запись на прогулку</a></li>
        </ul>
      </nav>
    </header>
    <main>
      <h1>Мои игрушки</h1>
      <ul>
        <li>Канат с мячиком «Удав» — моя любимая игрушка</li>
        <li>Резиновая косточка — для вечеров, когда гулять уже поздно</li>
        <li>Пищащий ёжик — его я прячу <del>под диваном</del> <ins>в своей лежанке</ins></li>
      </ul>
      <img src="../assets/tony.png" alt="Тони сидит и смотрит в камеру" width="300" height="400">
      <h2>Как играть со мной в канат</h2>
      <ol>
        <li>Покажите мне канат.</li>
        <li>Бросьте его подальше.</li>
        <li>Подождите, пока я принесу его обратно.</li>
        <li>Похвалите меня — и всё сначала!</li>
      </ol>
      <section>
        <h2 id="album">Мой фотоальбом</h2>
        <ul>
          <li>
            <figure>
              <img src="../assets/album-puppy.png" alt="Тони-щенок сидит и смотрит в камеру" width="300" height="400">
              <figcaption>Я в детстве</figcaption>
            </figure>
          </li>
          <li>
            <figure>
              <img src="../assets/album-squirrel.png" alt="Тони лежит в обнимку с плюшевой белкой" width="300" height="400">
              <figcaption>С плюшевой белкой</figcaption>
            </figure>
          </li>
          <li>
            <figure>
              <img src="../assets/album-hoodie.png" alt="Тони стоит в бежевой толстовке с капюшоном" width="300" height="400">
              <figcaption>В худи для холодной погоды</figcaption>
            </figure>
          </li>
          <li>
            <figure>
              <img src="../assets/album-harness.png" alt="Тони в оранжевой шлейке ждёт прогулку" width="300" height="400">
              <figcaption>Шлейка надета — идём гулять!</figcaption>
            </figure>
          </li>
          <li>
            <figure>
              <img src="../assets/album-laugh.png" alt="Тони лежит, запрокинув голову, и широко открыл пасть, будто смеётся" width="300" height="400">
              <figcaption>Смеюсь над шуткой хозяина</figcaption>
            </figure>
          </li>
          <li>
            <figure>
              <img src="../assets/album-sleep.png" alt="Тони спит, положив голову на лапы" width="300" height="319">
              <figcaption>После прогулки</figcaption>
            </figure>
          </li>
        </ul>
      </section>
      <p><a href="../index.html#commands">Какие команды я знаю</a></p>
      <p><a href="../index.html">Вернуться на главную</a></p>
    </main>
    <footer>
      <p><small>&copy; 2026 Тони и его хозяин</small></p>
      <address>Написать хозяину Тони: <a href="mailto:tony@example.com">tony@example.com</a></address>
    </footer>
  </body>
</html>
pages/walks.html
HTML
<!doctype html>
<html lang="ru">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="Маршрут прогулки Тони: сквер, пруд и поляна для игры с канатом.">
    <title>Где гуляет Тони</title>
    <link rel="stylesheet" href="../css/style.css">
  </head>
  <body>
    <h1>Мой маршрут</h1>
    <ol>
      <li>Сквер у дома.</li>
      <li>Пруд с утками.</li>
      <li>Поляна для игры с канатом.</li>
    </ol>
  </body>
</html>

Продолжите в VS Code

Внесите те же изменения в css/style.css своего сайта my-site, сохраните файл и откройте сайт в браузере. Проверка: меню на главной, в фотоальбоме и форме записи стоит в строку, оглавление на главной переносится при сужении окна. Если результат отличается, нажмите в редакторе «Показать решение» и сравните его со своим кодом.