🔍 Начните печатать, чтобы искать по книге или перейти к нужной странице по номеру
Удобно листать не только прокруткой, но и клавишами‑стрелками:
Эта книга — пошаговая инструкция по вёрстке сайтов на языках ХТМЛ и ЦСС. Вы узнаете не только как сверстать сайт, но и как опубликовать его в интернете, настроить красивый шаринг в соцсети и подключить системы аналитики.
Отдельный раздел книги посвящён работе с верстальщиком: как ставить задачи, получать предсказуемый результат и правильно принимать и внедрять вёрстку.
Знакомство с ХТМЛ и ЦСС
Модули
Расстановка
Страницы
Спецэффекты
Контроль качества
Публикация
Как работать с верстальщиком
Эта книга — пошаговая инструкция по вёрстке сайтов на языках ХТМЛ и ЦСС. Вы узнаете не только как сверстать сайт, но и как опубликовать его в интернете, настроить красивый шаринг в соцсети и подключить системы аналитики.
Отдельный раздел книги посвящён работе с верстальщиком: как ставить задачи, получать предсказуемый результат и правильно принимать и внедрять вёрстку.
Знакомство с ХТМЛ и ЦСС
Модули
Расстановка
Страницы
Спецэффекты
Контроль качества
Публикация
Как работать с верстальщиком
Когда готов макет и общая сетка, первое, что мы хотим сделать — задать внешние поля и формат страницы. По умолчанию в браузерах содержимое тянется на всю ширину окна с полями в 8 пикселей.
Чтобы задать формат, используют обёртки, классы, задающие максимальную ширину, поля и положение содержимого на странице. Формат может быть резиновым, фиксированным или комбинированным.
Самая простая «резиновая» обёртка может выглядеть так:
.layoutContainer {
margin-left: 6%; /* Задаём правое и левое поле в 6% от ширины окна */
margin-right: 6%;
}
«Фиксированная» обёртка жёстко задаёт ширину:
.layoutContainer {
width: 960px;
margin-left: auto; /* Центрируем с помощью автомаржинов */
margin-right: auto;
padding-left: 20px; /* Добавляем фиксированные поля в 20 пк, чтобы содержимое не прилипало к краям окон шириной менее 960 пк*/
padding-right: 20px;
}
Их комбинация, обёртка с ограничением максимальной ширины и резиновыми полями, обычно выглядит так:
.layoutContainer {
max-width: 960px; /* Задаём максимальную ширину */
margin-left: auto;
margin-right: auto;
padding-left: 20px;
padding-right: 20px;
}
Обёрткой может быть общий контейнер, в который завёрнуто всё содержимое страницы, или класс, который добавляют «этажам» страницы.
Контейнер‑обёртка подойдёт для случаев, когда структура содержимого страниц одинаковая и однотипная, например, для статей в блоге.
Класс‑обёртка подойдёт для случаев, когда часть содержимого страницы может не подчиняться ограничениям. Скажем, шапка и подвал тянутся на всю ширину окна, а содержимое страницы — ограничено по ширине.
Когда готов макет и общая сетка, первое, что мы хотим сделать — задать внешние поля и формат страницы. По умолчанию в браузерах содержимое тянется на всю ширину окна с полями в 8 пикселей.
Чтобы задать формат, используют обёртки, классы, задающие максимальную ширину, поля и положение содержимого на странице. Формат может быть резиновым, фиксированным или комбинированным.
Самая простая «резиновая» обёртка может выглядеть так:
.layoutContainer {
margin-left: 6%; /* Задаём правое и левое поле в 6% от ширины окна */
margin-right: 6%;
}
«Фиксированная» обёртка жёстко задаёт ширину:
.layoutContainer {
width: 960px;
margin-left: auto; /* Центрируем с помощью автомаржинов */
margin-right: auto;
padding-left: 20px; /* Добавляем фиксированные поля в 20 пк, чтобы содержимое не прилипало к краям окон шириной менее 960 пк*/
padding-right: 20px;
}
Их комбинация, обёртка с ограничением максимальной ширины и резиновыми полями, обычно выглядит так:
.layoutContainer {
max-width: 960px; /* Задаём максимальную ширину */
margin-left: auto;
margin-right: auto;
padding-left: 20px;
padding-right: 20px;
}
Обёрткой может быть общий контейнер, в который завёрнуто всё содержимое страницы, или класс, который добавляют «этажам» страницы.
Контейнер‑обёртка подойдёт для случаев, когда структура содержимого страниц одинаковая и однотипная, например, для статей в блоге.
Класс‑обёртка подойдёт для случаев, когда часть содержимого страницы может не подчиняться ограничениям. Скажем, шапка и подвал тянутся на всю ширину окна, а содержимое страницы — ограничено по ширине.
Ваш дизайн может работать не на всех размерах экрана. На мобильном телефоне может не поместиться меню или некрасиво переноситься текст. Чтобы адаптировать страницу к мобильному телефону и другим устройствам, введём понятие «точек излома».
Точка излома, breakpoint, — ширина экрана, при которой одна версия вёрстки сменяется на другую. Например, при ширине экрана менее 991 пикселя меню могло бы занять всю ширину экрана и стать прокручиваемым. Используем для этого медиавыражения.
Чтобы решить, при каких условиях медиавыражения должны срабатывать, используют два подхода: по устройствам и по содержимому. В первом случае мы решаем, что у страницы есть отдельный дизайн для разных устройств, экранов: например, мобильных, лаптопов и десктопов. Затем для каждого из устройств определяем точки излома.
В большинстве популярных ЦСС‑фреймворков эти точки выглядят так:
| Узкие мобильные | < 576 пк |
| Мобильные | < 768 пк |
| Лаптопы | ≥ 768 пк |
| Десктопы | ≥ 992 пк |
| Широкие десктопы | ≥ 1400 пк |
Вы можете использовать любые другие значения, опираясь на статистику экранов посетителей сайта или на значения, заданные в вашем ЦСС‑фреймворке.
Например, на сайте бюро мы остановились на трёх типах устройств:
| Мобильные | ≤ 960 пк |
| Лаптопы | > 960 пк |
| Десктопы | > 1400 пк |
Советуем использовать как можно меньше устройств и точек излома. Чем их больше, тем больше вариантов раскладки нужно придумать, сверстать и проверить. Если шапка и подвал адаптируются к двум устройствам, это даёт
Медиавыражения
Ваш дизайн может работать не на всех размерах экрана. На мобильном телефоне может не поместиться меню или некрасиво переноситься текст. Чтобы адаптировать страницу к мобильному телефону и другим устройствам, введём понятие «точек излома».
Точка излома, breakpoint, — ширина экрана, при которой одна версия вёрстки сменяется на другую. Например, при ширине экрана менее 991 пикселя меню могло бы занять всю ширину экрана и стать прокручиваемым. Используем для этого медиавыражения.
Чтобы решить, при каких условиях медиавыражения должны срабатывать, используют два подхода: по устройствам и по содержимому. В первом случае мы решаем, что у страницы есть отдельный дизайн для разных устройств, экранов: например, мобильных, лаптопов и десктопов. Затем для каждого из устройств определяем точки излома.
В большинстве популярных ЦСС‑фреймворков эти точки выглядят так:
| Узкие мобильные | < 576 пк |
| Мобильные | < 768 пк |
| Лаптопы | ≥ 768 пк |
| Десктопы | ≥ 992 пк |
| Широкие десктопы | ≥ 1400 пк |
Вы можете использовать любые другие значения, опираясь на статистику экранов посетителей сайта или на значения, заданные в вашем ЦСС‑фреймворке.
Например, на сайте бюро мы остановились на трёх типах устройств:
| Мобильные | ≤ 960 пк |
| Лаптопы | > 960 пк |
| Десктопы | > 1400 пк |
Советуем использовать как можно меньше устройств и точек излома. Чем их больше, тем больше вариантов раскладки нужно придумать, сверстать и проверить. Если шапка и подвал адаптируются к двум устройствам, это даёт
Медиавыражения
Адаптация может понадобиться не только на уровне всего сайта, но и на уровне отдельных элементов. Например, адрес компании в подвале может постепенно сокращать свой текст, когда перестаёт помещаться:
Большая Новодмитровская улица, 36, строение 2
Большая Новодмитровская улица, 36, стр. 2
Б. Новодмитровская ул., 36, стр. 2
В таких случаях точки излома лучше выбирать исходя из содержимого и использовать Container Queries — медиавыражения, отталкивающиеся от размеров контейнера, а не от размеров окна:
<footer>
<div class="address">
Б<span class="sacrifice--second">ольшая</span><span>.</span> Новодмитровская ул<span class="sacrifice--second">ица</span><span>.</span>,
36, стр<span class="sacrifice--first">оение</span><span>.</span> 2
</div>
</footer>Для логичных переносов склеили неразрывными пробелами части адреса, сильно связанные друг с другом по смыслу: «Большая Новодмитровская улица», «36, строение 2»
.address {
container-type: inline-size; /* Объявляем .address контейнером, с шириной которого можно делать медиавыражения */
}
.address .sacrifice--first + span,
.address .sacrifice--first + span {
display: none; /* Скрываем спаны с точками, пока они не нужны */
}
@container (width <= 21em) { /* При ширине подвала менее 21em, используем первую волну сокращений */
.address .sacrifice--first {
display: none;
}
.address .sacrifice--first + span {
display: inline;
}
}
@container (width <= 19em) { /* При ширине подвала менее 19em, используем вторую волну сокращений */
.address .sacrifice--second {
display: none;
}
.address .sacrifice--second + span {
display: inline;
}
}
Конечно, можно было бы использовать и обычные медиавыражения с шириной экрана. Но это сделало бы вёрстку адреса более хрупкой и менее переносимой. Если в подвале у адреса появится сосед, адрес станет занимать меньше места. Текст придётся сокращать раньше, значит, придётся пересчитывать точки в медиавыражениях.
Container Queries. МДН
Адаптация может понадобиться не только на уровне всего сайта, но и на уровне отдельных элементов. Например, адрес компании в подвале может постепенно сокращать свой текст, когда перестаёт помещаться:
Большая Новодмитровская улица, 36, строение 2
Большая Новодмитровская улица, 36, стр. 2
Б. Новодмитровская ул., 36, стр. 2
В таких случаях точки излома лучше выбирать исходя из содержимого и использовать Container Queries — медиавыражения, отталкивающиеся от размеров контейнера, а не от размеров окна:
<footer>
<div class="address">
Б<span class="sacrifice--second">ольшая</span><span>.</span> Новодмитровская ул<span class="sacrifice--second">ица</span><span>.</span>,
36, стр<span class="sacrifice--first">оение</span><span>.</span> 2
</div>
</footer>Для логичных переносов склеили неразрывными пробелами части адреса, сильно связанные друг с другом по смыслу: «Большая Новодмитровская улица», «36, строение 2»
.address {
container-type: inline-size; /* Объявляем .address контейнером, с шириной которого можно делать медиавыражения */
}
.address .sacrifice--first + span,
.address .sacrifice--first + span {
display: none; /* Скрываем спаны с точками, пока они не нужны */
}
@container (width <= 21em) { /* При ширине подвала менее 21em, используем первую волну сокращений */
.address .sacrifice--first {
display: none;
}
.address .sacrifice--first + span {
display: inline;
}
}
@container (width <= 19em) { /* При ширине подвала менее 19em, используем вторую волну сокращений */
.address .sacrifice--second {
display: none;
}
.address .sacrifice--second + span {
display: inline;
}
}
Конечно, можно было бы использовать и обычные медиавыражения с шириной экрана. Но это сделало бы вёрстку адреса более хрупкой и менее переносимой. Если в подвале у адреса появится сосед, адрес станет занимать меньше места. Текст придётся сокращать раньше, значит, придётся пересчитывать точки в медиавыражениях.
Container Queries. МДН
Приведём примеры вёрстки типичных шапок, меню и подвалов сайтов. Сосредоточимся только на раскладке элементов, оставив типографику на усмотрение читателю.
Одни и те же элементы можно сверстать, используя разные способы: гриды, флексбоксы или строчные элементы. Поэтому вёрстка в этой и последующих главах — это не эталоны, высеченные в камне, а лишь примеры решения типовых задач в вёрстке.
Приведём примеры вёрстки типичных шапок, меню и подвалов сайтов. Сосредоточимся только на раскладке элементов, оставив типографику на усмотрение читателю.
Одни и те же элементы можно сверстать, используя разные способы: гриды, флексбоксы или строчные элементы. Поэтому вёрстка в этой и последующих главах — это не эталоны, высеченные в камне, а лишь примеры решения типовых задач в вёрстке.
Типичная шапка из трёх элементов: логотипа, меню и телефона
В контейнере <nav> — navigation — собирают ссылки для навигации по сайту
Если не свешивать круглый логотип за линию сетки, он будет казаться сдвинутым
Шапка и подвал сайта чаще всего имеют форму строк, прижатых к верху и низу страницы
Мы используем max‑content, а не min‑content, чтобы пункты меню из нескольких слов не переносились
Аналогично можно было бы выделить текущий пункт меню начертанием или цветом
По умолчанию содержимое грид‑ячеек выравнивается по верхнему краю
В гридах align‑items управляет выравниванием по вертикали, а justify‑items — по горизонтали
В гридах justify‑self управляет выравниванием внутри ячейки
Иногда подчёркивание делают с помощью border‑bottom, background‑image или box‑shadow
Сверстаем простую шапку «в линию», встречающуюся на большинстве сайтов. Сосредоточимся только на раскладке, опустив типографику и стили для сброса.
Вёрстка с чистого листа
Начнём с разметки. Соберём шапку в контейнере <header>. Для логотипа возьмём див с картинкой, завёрнутой в ссылку на главную страницу. Меню соберём в ненумерованный список <ul>. Телефон сделаем кликабельной ссылкой с хитрым протоколом tel:
<header class="header">
<div class="logo">
<a href="/">
<img src="logo.svg">
</a>
</div>
<nav class="nav">
<ul>
<li class="nav__item">
<a href="/products/">Продукция</a>
</li>
<li class="nav__item">
<a href="/services/">Услуги</a>
</li>
<li class="nav__item is__active">
<a href="/blog/">Блог</a>
</li>
<li class="nav__item">
<a href="/contacts/">Контакты</a>
</li>
</ul>
</nav>
<div class="tel">
<a href="tel:+74954005050">
+7 495 400‑50‑50
</a>
</div>
</header>
Стилизуем логотип. Зафиксируем его размеры и свесим кружок логотипа за линии сетки:
.logo {
width: 40px;
height: 40px;
margin: 0 -5px;
}
Стилизуем меню. Включим гриды и разложим пункты меню по колонкам:
.nav ul {
display: grid;
grid-auto-flow: column;
}
Определим автоматические колонки по максимальному содержимому и зададим отступ между пунктами меню:
.nav ul {
display: grid;
grid-auto-flow: column;
grid-auto-columns: max-content;
column-gap: 20px;
}
Стилизуем пункты меню. Увеличим кликабельную область ссылок и стилизуем текущий пункт меню:
.nav ul {
display: grid;
grid-auto-flow: column;
grid-auto-columns: max-content;
column-gap: 20px;
align-items: center;
}
.nav__item a {
position: relative;
z-index: 1;
}
.nav__item a::before {
content: '';
position: absolute;
inset: -3px -7px;
z-index: -1;
}
.nav__item.is__active a {
color: #fff;
text-decoration: none;
}
.nav__item.is__active a::before {
background-color: #ff5722;
border-radius: 8px;
}
Настроим раскладку шапки в целом. Включим гриды и разложим логотип, меню и телефон по колонкам. Заодно добавим шапке верхний падинг и сделаем её контейнером‑обёрткой, чтобы она не прилипала к краям и правильно управляла своей шириной:
.header {
display: grid;
grid-template-columns: min-content max-content 1fr;
column-gap: 20px;
padding-top: 10px;
}<header class="header layoutContainer">
<!-- … -->
</header>Обёртка для страницы
Отцентрируем всё по вертикали:
.header {
display: grid;
grid-template-columns: min-content max-content 1fr;
column-gap: 20px;
padding-top: 10px;
align-items: center;
line-height: 1;
}
Отожмём телефон к правому краю:
.header {
display: grid;
grid-template-columns: min-content max-content 1fr;
column-gap: 20px;
padding: 10px;
align-items: center;
}
.header .tel {
justify-self: end;
}Уберём подчеркивания у ссылок в шапке:
.header {
display: grid;
grid-template-columns: min-content max-content 1fr;
column-gap: 20px;
padding: 10px;
align-items: center;
}
.header .tel {
justify-self: end;
}
.header a {
text-decoration: none;
}Типичная шапка из трёх элементов: логотипа, меню и телефона
В контейнере <nav> — navigation — собирают ссылки для навигации по сайту
Если не свешивать круглый логотип за линию сетки, он будет казаться сдвинутым
Шапка и подвал сайта чаще всего имеют форму строк, прижатых к верху и низу страницы
Мы используем max‑content, а не min‑content, чтобы пункты меню из нескольких слов не переносились
Аналогично можно было бы выделить текущий пункт меню начертанием или цветом
По умолчанию содержимое грид‑ячеек выравнивается по верхнему краю
В гридах align‑items управляет выравниванием по вертикали, а justify‑items — по горизонтали
В гридах justify‑self управляет выравниванием внутри ячейки
Иногда подчёркивание делают с помощью border‑bottom, background‑image или box‑shadow
Сверстаем простую шапку «в линию», встречающуюся на большинстве сайтов. Сосредоточимся только на раскладке, опустив типографику и стили для сброса.
Вёрстка с чистого листа
Начнём с разметки. Соберём шапку в контейнере <header>. Для логотипа возьмём див с картинкой, завёрнутой в ссылку на главную страницу. Меню соберём в ненумерованный список <ul>. Телефон сделаем кликабельной ссылкой с хитрым протоколом tel:
<header class="header">
<div class="logo">
<a href="/">
<img src="logo.svg">
</a>
</div>
<nav class="nav">
<ul>
<li class="nav__item">
<a href="/products/">Продукция</a>
</li>
<li class="nav__item">
<a href="/services/">Услуги</a>
</li>
<li class="nav__item is__active">
<a href="/blog/">Блог</a>
</li>
<li class="nav__item">
<a href="/contacts/">Контакты</a>
</li>
</ul>
</nav>
<div class="tel">
<a href="tel:+74954005050">
+7 495 400‑50‑50
</a>
</div>
</header>
Стилизуем логотип. Зафиксируем его размеры и свесим кружок логотипа за линии сетки:
.logo {
width: 40px;
height: 40px;
margin: 0 -5px;
}
Стилизуем меню. Включим гриды и разложим пункты меню по колонкам:
.nav ul {
display: grid;
grid-auto-flow: column;
}
Определим автоматические колонки по максимальному содержимому и зададим отступ между пунктами меню:
.nav ul {
display: grid;
grid-auto-flow: column;
grid-auto-columns: max-content;
column-gap: 20px;
}
Стилизуем пункты меню. Увеличим кликабельную область ссылок и стилизуем текущий пункт меню:
.nav ul {
display: grid;
grid-auto-flow: column;
grid-auto-columns: max-content;
column-gap: 20px;
align-items: center;
}
.nav__item a {
position: relative;
z-index: 1;
}
.nav__item a::before {
content: '';
position: absolute;
inset: -3px -7px;
z-index: -1;
}
.nav__item.is__active a {
color: #fff;
text-decoration: none;
}
.nav__item.is__active a::before {
background-color: #ff5722;
border-radius: 8px;
}
Настроим раскладку шапки в целом. Включим гриды и разложим логотип, меню и телефон по колонкам. Заодно добавим шапке верхний падинг и сделаем её контейнером‑обёрткой, чтобы она не прилипала к краям и правильно управляла своей шириной:
.header {
display: grid;
grid-template-columns: min-content max-content 1fr;
column-gap: 20px;
padding-top: 10px;
}<header class="header layoutContainer">
<!-- … -->
</header>Обёртка для страницы
Отцентрируем всё по вертикали:
.header {
display: grid;
grid-template-columns: min-content max-content 1fr;
column-gap: 20px;
padding-top: 10px;
align-items: center;
line-height: 1;
}
Отожмём телефон к правому краю:
.header {
display: grid;
grid-template-columns: min-content max-content 1fr;
column-gap: 20px;
padding: 10px;
align-items: center;
}
.header .tel {
justify-self: end;
}Уберём подчеркивания у ссылок в шапке:
.header {
display: grid;
grid-template-columns: min-content max-content 1fr;
column-gap: 20px;
padding: 10px;
align-items: center;
}
.header .tel {
justify-self: end;
}
.header a {
text-decoration: none;
}