Печатная версия страницы: рабочие приёмы для фронтенда
Пользователь жмёт Ctrl+P — и получает три страницы с обрезанной шапкой, тёмным фоном и ссылками, которые в бумаге бесполезны. Разбираем, как сделать печать предсказуемой без отдельного шаблона.

Классическая задача: интернет-магазин или сервис бронирования просит «сделать так, чтобы страница нормально печаталась». На экране всё красиво, а из принтера выходит три листа с половиной навигации, залитым тёмным фоном на весь лист и ссылками, по которым на бумаге не кликнешь. Соблазн — сделать отдельную страницу /print. Но в 90% случаев это лишняя сущность: браузеры давно умеют печатать по CSS, и хватает медиазапроса @media print плюс нескольких свойств, о которых обычно забывают.
Разберём на живом примере — странице заказа, которую нужно превратить в чек или накладную прямо из браузера. Покажу четыре приёма, у каждого своя цена, и таблицу, когда что применять.
Почему «просто спрятать лишнее» не работает
Первое, что делают: display: none на шапку и подвал в @media print. Это правильный старт, но проблема глубже. Печать отличается от экрана по нескольким осям сразу:
- Цвета и фон. Браузеры по умолчанию не печатают фоновые цвета и картинки — экономят тонер. Ваш белый текст на тёмной плашке станет белым текстом на белом листе, то есть исчезнет.
- Разрывы страниц. Таблица заказа может разорваться посередине строки, а заголовок раздела уехать на предыдущий лист отдельно от содержимого.
- Единицы измерения.
vh,vwи высота в процентах в печати ведут себя непредсказуемо: у листа нет «вьюпорта» в том же смысле. - Ссылки и интерактив. Кнопка «Оплатить» на бумаге — мусор. А вот адрес ссылки иногда стоит показать текстом.
Поэтому «спрятать лишнее» — это шаг один из четырёх, а не всё решение.
Приём 1. Базовый print-стиль
Начинаем с медиазапроса. Прячем всё, что не относится к сути документа, и заставляем браузер печатать фон там, где он несёт смысл.
/* print.css — подключается обычным link или собирается в бандл */
@media print {
/* скрываем интерфейс, который не нужен на бумаге */
header.site-header,
nav.main-nav,
.cart-actions,
.cookie-banner,
footer.site-footer {
display: none;
}
/* печатаем фоновые цвета плашек — иначе бейдж статуса пропадёт */
.order-status {
-webkit-print-color-adjust: exact; /* Chrome, Safari */
print-color-adjust: exact; /* стандартное свойство */
}
/* базовая типографика под лист A4 */
body {
font-size: 12pt;
color: #000;
background: #fff;
}
}
Свойство print-color-adjust: exact — то самое, о котором забывают. Без него браузер выкинет любые фоновые заливки. Префикс -webkit- всё ещё нужен для стабильности в Chromium и WebKit.
Правило простое: если фон несёт информацию (цвет статуса, зебра в таблице) — оставляйте его с print-color-adjust: exact. Если это декорация — пусть исчезает, тонер дороже.
Приём 2. Контроль разрывов страниц
Длинная накладная почти всегда разрывается неудачно. Управляют этим свойства группы break-* (современные) и их предшественники page-break-*.
@media print {
/* строку таблицы не рвём между листами */
.order-table tr {
break-inside: avoid;
}
/* заголовок раздела не должен оставаться один внизу листа */
.order-section h2 {
break-after: avoid;
}
/* итоговый блок печатаем с новой страницы */
.order-total {
break-before: page;
}
}
Современный синтаксис — break-inside, break-before, break-after. Старый — page-break-inside и так далее. Свежие браузеры (Chrome, Firefox, Safari последних лет) понимают оба, но break-inside: avoid для длинных блоков поддерживается неровно: если внутри <tr> очень высокий контент, браузер всё равно разорвёт его, чтобы не потерять данные. Проверяйте на реальных длинных заказах, а не на тестовом из двух позиций.
Приём 3. Показать адреса ссылок текстом
На бумаге ссылка Подробнее бесполезна — не видно, куда она ведёт. Иногда это критично: например, ссылка на отслеживание посылки. Псевдоэлемент ::after с attr(href) подставит адрес прямо в текст.
@media print {
/* дописываем URL после ссылок внутри контента */
.order-content a[href]::after {
content: " (" attr(href) ")";
font-size: 10pt;
color: #555;
}
/* но не для якорей и js-ссылок — там URL бесполезен */
.order-content a[href^="#"]::after,
.order-content a[href^="javascript:"]::after {
content: "";
}
}
Не применяйте это ко всем ссылкам подряд: в навигации и кнопках подставленные URL превратят лист в кашу. Ограничивайте селектор смысловой зоной документа.
Приём 4. Настройка самого листа через @page
Правило @page управляет полями листа и его размером. Полезно, когда дизайнер требует конкретные отступы под фирменный бланк.
@media print {
@page {
size: A4; /* или letter, или конкретные размеры: 210mm 297mm */
margin: 15mm; /* поля со всех сторон */
}
/* убираем внешние отступы у контейнера — их теперь задаёт @page */
.order-content {
margin: 0;
padding: 0;
}
}
Важное ограничение: колонтитулы с датой и нумерацией страниц (то, что печатает сам браузер сверху и снизу) из CSS вы полностью не уберёте и не переопределите — псевдоэлементы @page :first и @page { @top-center {} } из спецификации Paged Media в браузерах поддержаны частично или не поддержаны вовсе. Управление этими колонтитулами остаётся у пользователя в диалоге печати. Не обещайте заказчику пиксель-в-пиксель бланк без серверной генерации PDF.
Когда что выбирать
| Задача | Решение | Цена |
|---|---|---|
| Скрыть интерфейс, оставить контент | @media print + display: none | Минимальная, 20 минут работы |
| Сохранить цветные плашки статусов | print-color-adjust: exact | Одна строка, но тонер пользователя |
| Аккуратные разрывы длинных таблиц | break-inside / break-before | Нужно тестировать на реальных данных |
| Точный бланк с колонтитулами и нумерацией | Серверная генерация PDF (wkhtmltopdf, Puppeteer, Playwright) | Отдельный сервис, но полный контроль |
Граница простая: пока задача — «пусть печатается прилично», хватает CSS. Как только появляются требования «строго A4, наш логотип в углу каждого листа, нумерация 1 из 3» — это уже документ, а не веб-страница, и его генерируют на сервере. Пытаться выжать это из @media print — потратить неделю и всё равно упереться в колонтитулы браузера.
Что ломается на практике
- Тёмная тема. Если сайт поддерживает
prefers-color-scheme: dark, печать может унаследовать тёмные цвета. Явно задавайтеcolor: #000; background: #fffв print-блоке. - Flex и grid. Разрывы страниц внутри flex- и grid-контейнеров работают нестабильнее, чем в обычном потоке. Для печатной зоны иногда проще откатиться на блочную вёрстку.
- Ленивые картинки. Изображения с
loading="lazy", не попавшие во вьюпорт, могут не успеть загрузиться к моменту печати. Для печатной зоны отключайте ленивую загрузку. - Фиксированные элементы.
position: fixedв печати ведёт себя странно: элемент может продублироваться на каждом листе или пропасть. Прячьте такие блоки в print-стиле.
Как проверять результат
Не полагайтесь на реальный принтер — это медленно. В Chrome и Firefox эмуляция печати встроена в DevTools.
- Откройте DevTools, вкладка Rendering (в Chrome — через меню «три точки» → More tools → Rendering).
- В разделе Emulate CSS media type выберите
print— страница на экране покажет печатный вид, стили можно править вживую. - Для проверки разрывов и полей откройте предпросмотр печати (Ctrl+P / Cmd+P) — только он показывает реальную разбивку на листы.
- Прогоните на длинном заказе (20+ позиций), а не на тестовом — именно на объёме вылезают неудачные разрывы.
Что делать дальше
Соберите print-стили в отдельный файл и подключайте с media="print" — так они не грузятся при обычном просмотре и не мешают основным стилям. Если после этого заказчик всё равно требует точный бланк — переходите на серверную генерацию через Puppeteer или Playwright: они рендерят страницу в headless-браузере и отдают PDF с полным контролем над полями и колонтитулами. Инвалидация и кеширование готовых PDF — отдельная тема, здесь мы разбирали только браузерную печать.
Дефектный акт по фото: Осмотр по фотографиям: классификация дефектов, ссылки на нормы, требования к устранению. Готовый акт в Word.
Спросить за 80 ₽Источники: MDN — @media print и печатные стили, MDN — CSS Paged Media (@page, break-*)
Частые вопросы
А если у пользователя другой браузер — стили печати сработают?
Почему фоновые цвета не печатаются, хотя я задал background?
Нужна ли отдельная страница /print?
Как убрать дату и адрес сайта, которые браузер печатает сверху и снизу?
Таблица всё равно разрывается посреди строки, хотя я поставил break-inside: avoid — что не так?
Стоит ли грузить print.css всем пользователям?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.