Верстка адаптивных email-писем:
HTML, CSS и подводные камни
Email-рассылка выглядит отлично в браузере и разваливается в Outlook. Знакомая ситуация. Причина одна: email-клиенты рендерят HTML по собственным правилам, и эти правила далеки от веб-стандартов.
В этом руководстве - конкретный код: скелет письма, инлайн-стили, media queries, работа с картинками и тёмной темой. Каждый пример проверен в Gmail, Outlook 2019/365, Apple Mail и Яндекс.Почте.
Содержание
Почему таблицы, а не div
Веб ушёл от табличной верстки пятнадцать лет назад. Email - нет. Outlook на Windows использует движок рендеринга Microsoft Word (да, тот самый Word) для отображения HTML. Word не понимает flexbox, grid и большую часть position. Зато он нормально рендерит таблицы.
Gmail вырезает тег <style> из <head>, если письмо превышает 102 КБ. Yahoo Mail обрезает CSS-анимации. Mail.ru игнорирует max-width на div-элементах, но корректно применяет его на ячейках таблицы.
Итог: таблицы - основа раскладки email-письма. Это не рекомендация, а необходимость.
Базовый скелет письма
Каждое email-письмо начинается с одной и той же структуры. Внешняя таблица - 100% ширины, задаёт фон. Внутренняя - фиксированная ширина содержимого, обычно 600px. Это значение не случайное: большинство десктопных клиентов отображают панель preview шириной 600-700px.
<!DOCTYPE html>
<html lang="ru" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Тема письма</title>
<!--[if mso]>
<style>
table { border-collapse: collapse; }
.fallback-font { font-family: Arial, sans-serif; }
</style>
<![endif]-->
</head>
<body style="margin:0; padding:0; background-color:#f4f4f4;">
<!-- Внешняя обёртка -->
<table role="presentation" width="100%" cellpadding="0"
cellspacing="0" style="background-color:#f4f4f4;">
<tr>
<td align="center" style="padding: 20px 0;">
<!-- Контейнер 600px -->
<table role="presentation" width="600" cellpadding="0"
cellspacing="0"
style="background-color:#ffffff; max-width:600px;">
<tr>
<td style="padding: 40px 30px;">
<!-- Контент письма -->
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>Обратите внимание на несколько деталей. Атрибут role="presentation" сообщает скринридерам, что таблица используется для раскладки, а не для данных. Условный комментарий <!--[if mso]> подключает стили только для Outlook на Windows. cellpadding="0" и cellspacing="0" обнуляют отступы по умолчанию, которые у каждого клиента свои.
Инлайн-стили: обязательный минимум
Gmail, Yahoo Mail и ряд других клиентов вырезают или игнорируют блок <style> в <head>. Единственный способ гарантировать стили - прописать их в атрибуте style каждого элемента. Это громоздко, но альтернатив нет.
<!-- Заголовок -->
<td style="padding: 0 0 20px 0;">
<h1 style="margin: 0;
font-family: Arial, Helvetica, sans-serif;
font-size: 28px;
line-height: 1.3;
color: #1a1a1a;
font-weight: bold;">
Заголовок вашего письма
</h1>
</td>
<!-- Параграф -->
<td style="padding: 0 0 16px 0;">
<p style="margin: 0;
font-family: Arial, Helvetica, sans-serif;
font-size: 16px;
line-height: 1.6;
color: #4a4a4a;">
Текст параграфа. Каждое свойство — inline.
</p>
</td>
<!-- Кнопка (bulletproof) -->
<td style="padding: 20px 0;">
<table role="presentation" cellpadding="0" cellspacing="0">
<tr>
<td style="background-color: #4c49fa;
border-radius: 6px;
text-align: center;">
<a href="https://example.com"
target="_blank"
style="display: inline-block;
padding: 14px 32px;
font-family: Arial, Helvetica, sans-serif;
font-size: 16px;
font-weight: bold;
color: #ffffff;
text-decoration: none;">
Перейти к действию
</a>
</td>
</tr>
</table>
</td>Кнопка в примере выше - так называемая bulletproof button. Она не зависит от background-image (который часто блокируется) и сохраняет кликабельную область даже при отключённых картинках.
Совет: пишите стили руками только для прототипа. Для продакшена используйте CSS-инлайнер: juice (Node.js), premailer (Python/Ruby) или встроенный инструмент вашего ESP. Они возьмут обычный CSS из <style> и перенесут его в атрибуты style.
Адаптивность через media queries
Более 60% email-писем открывают на мобильных устройствах. Письмо шириной 600px на экране шириной 375px превращается в горизонтальный скролл, если не добавить адаптивность.
Поддержка media queries различается между клиентами. Apple Mail, iOS Mail, Samsung Mail - поддерживают полностью. Gmail app на Android - игнорирует <style> в <head>, но поддерживает инлайн media queries через <style> в <body>. Outlook на Windows - не поддерживает вовсе.
Рабочая стратегия: fluid layout в базе плюс media queries для клиентов, которые их понимают. Outlook получит фиксированную ширину через условный комментарий.
<style>
/* Базовые адаптивные стили */
@media only screen and (max-width: 620px) {
.email-container {
width: 100% !important;
max-width: 100% !important;
}
.stack-column {
display: block !important;
width: 100% !important;
}
.stack-column-center {
display: block !important;
width: 100% !important;
text-align: center !important;
}
.mobile-padding {
padding-left: 20px !important;
padding-right: 20px !important;
}
.mobile-hide {
display: none !important;
}
.mobile-font-large {
font-size: 22px !important;
line-height: 1.3 !important;
}
}
</style>
<!-- Двухколоночная раскладка, которая схлопывается -->
<table role="presentation" width="100%" cellpadding="0"
cellspacing="0">
<tr>
<td>
<!--[if mso]>
<table role="presentation" width="600" cellpadding="0"
cellspacing="0" align="center">
<tr>
<td width="290" valign="top">
<![endif]-->
<div class="stack-column"
style="display:inline-block; width:290px;
vertical-align:top;">
<table role="presentation" width="100%">
<tr>
<td style="padding: 10px;">
<!-- Левая колонка -->
</td>
</tr>
</table>
</div>
<!--[if mso]>
</td>
<td width="290" valign="top">
<![endif]-->
<div class="stack-column"
style="display:inline-block; width:290px;
vertical-align:top;">
<table role="presentation" width="100%">
<tr>
<td style="padding: 10px;">
<!-- Правая колонка -->
</td>
</tr>
</table>
</div>
<!--[if mso]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</table>Ключевой приём: display: inline-block на div-обёртках колонок. На десктопе две колонки стоят рядом. На мобильных media query переключает их в display: block; width: 100%, и они выстраиваются друг под другом. А для Outlook условный комментарий создаёт жёсткую табличную структуру с фиксированными ширинами.
Картинки и ретина
Три правила для изображений в email. Первое: всегда указывайте атрибуты width и height. Без них Outlook растянет картинку до полной ширины контейнера. Второе: добавляйте alt - текст с описанием, потому что Gmail, Outlook и корпоративные клиенты по умолчанию блокируют картинки. Третье: для retina-экранов загружайте изображение в 2x-разрешении и задавайте отображаемый размер через атрибуты.
<!-- Адаптивная картинка для retina -->
<img src="https://cdn.example.com/hero-1200.png"
alt="Описание изображения"
width="600"
height="300"
style="display: block;
width: 100%;
max-width: 600px;
height: auto;
border: 0;
outline: none;"
/>
<!-- Фоновая картинка с фолбэком для Outlook -->
<!--[if mso]>
<v:rect xmlns:v="urn:schemas-microsoft-com:vml"
fill="true" stroke="false"
style="width:600px; height:300px;">
<v:fill type="frame"
src="https://cdn.example.com/bg.png" />
<v:textbox inset="0,0,0,0">
<![endif]-->
<div style="background-image: url('https://cdn.example.com/bg.png');
background-size: cover;
background-position: center;
max-width: 600px;">
<table role="presentation" width="100%">
<tr>
<td style="padding: 40px 30px; color: #ffffff;">
<!-- Контент поверх фона -->
</td>
</tr>
</table>
</div>
<!--[if mso]>
</v:textbox>
</v:rect>
<![endif]-->VML-разметка (Vector Markup Language) - единственный способ заставить фоновое изображение работать в Outlook на Windows. Без неё Outlook покажет белый фон вместо картинки. Выглядит архаично, но работает стабильно вплоть до Outlook 2021 и Microsoft 365.
Тёмная тема
Apple Mail, Outlook.com и Gmail (частично) инвертируют цвета писем, когда у пользователя включена тёмная тема ОС. Белый фон становится тёмно-серым, чёрный текст - светлым. Проблема в том, что инверсия применяется автоматически и не всегда корректно: тёмно-синий логотип на белом фоне превращается в невидимый тёмно-синий логотип на тёмно-сером фоне.
/* Стили для тёмной темы */
@media (prefers-color-scheme: dark) {
.email-body {
background-color: #1a1a2e !important;
}
.email-container {
background-color: #16213e !important;
}
.text-primary {
color: #e0e0e0 !important;
}
.text-secondary {
color: #b0b0b0 !important;
}
}
/* Мета-тег для Apple Mail */
:root {
color-scheme: light dark;
supported-color-schemes: light dark;
}Мета-тег color-scheme говорит Apple Mail: «это письмо готово к тёмной теме, не инвертируй цвета автоматически - я задам их сам». Без этого мета-тега Apple Mail применит собственную инверсию, которая может исказить дизайн.
Практический совет: добавляйте прозрачный контур (stroke) вокруг тёмных логотипов - 2-3px белой или светлой обводки. Так логотип останется читаемым на любом фоне. Либо подготовьте две версии логотипа и переключайте их через media query.
Совместимость с email-клиентами
Разные клиенты поддерживают разный набор CSS-свойств. Вот таблица ключевых различий, которую стоит держать под рукой.
| Свойство | Gmail | Outlook | Apple Mail | Яндекс |
|---|---|---|---|---|
| media queries | Частично | Нет | Да | Да |
| flexbox / grid | Нет | Нет | Да | Нет |
| background-image | Да | VML | Да | Да |
| border-radius | Да | Нет | Да | Да |
| margin | Частично | Частично | Да | Да |
| <style> в <head> | До 102 КБ | Да | Да | Да |
| SVG | Нет | Нет | Да | Нет |
Из таблицы видно: единственный клиент с полной поддержкой современного CSS - Apple Mail. Все остальные требуют компромиссов. Стратегия progressive enhancement работает: делаете базовую версию на таблицах с инлайн-стилями, затем добавляете улучшения через <style> для клиентов, которые их поддерживают.
Outlook и Word-движок. Outlook 2007, 2010, 2013, 2016, 2019 и Microsoft 365 на Windows используют Word для рендеринга HTML. Outlook на macOS использует WebKit - и ведёт себя как Safari. Outlook.com (веб) - отдельная история со своими ограничениями. Не путайте их: это три разных движка под одним брендом.
Тестирование перед отправкой
Сверстать письмо - половина работы. Вторая половина - убедиться, что оно выглядит корректно в десятках клиентов. Ручная проверка в каждом клиенте нереальна, поэтому используют инструменты.
Litmus и Email on Acid делают скриншоты вашего письма в 90+ клиентах. Стоят от $80/мес, но для команд, которые отправляют регулярно, - окупаются. Бесплатная альтернатива - PutsMail (от Litmus): отправляет тестовое письмо на ваш ящик, без скриншотов, но достаточно, чтобы проверить Gmail и Outlook вручную.
Минимальный набор для ручного тестирования:
- Gmail (web) - самый массовый клиент в мире
- Outlook 2019/365 (Windows) - самый проблемный клиент из-за Word-движка
- Apple Mail (iOS) - 30-40% мобильных открытий
- Яндекс.Почта - для российской аудитории
- Mail.ru - второй по популярности в рунете
Не забудьте про валидацию базы. Идеально свёрстанное письмо бесполезно, если оно улетает на несуществующие адреса. Проверка списка получателей перед отправкой убирает hard bounces и защищает репутацию домена.
Чек-лист перед отправкой
Вот список того, что стоит проверить перед каждой рассылкой. Распечатайте или сохраните в закладки.
Раскладка построена на таблицах, а не на div/flexbox/grid
Все стили продублированы в inline-атрибуте style
Указаны width и height у каждого img, добавлен alt-текст
Картинки загружены в 2x для retina, формат PNG или JPEG
Кнопки сверстаны как bulletproof (таблица + ссылка)
Есть fallback для тёмной темы (color-scheme мета-тег)
Добавлены условные комментарии для Outlook (<!--[if mso]>)
Размер HTML не превышает 102 КБ (лимит Gmail)
Протестировано в Gmail, Outlook, Apple Mail, Яндекс
Есть plain-text версия письма
База получателей провалидирована
Письмо свёрстано. А база проверена?
Загрузите список email-адресов в uChecker - мы покажем, какие из них невалидны, какие ведут на спам-ловушки и какие давно заброшены. Результаты за минуты.
Проверить базу в uChecker