WeasyPrint

WeasyPrint превращает HTML-шаблоны и таблицы стилей в многостраничные PDF: можно сверстать счёт, отчёт, билет, книгу или печатную форму, задать формат листа и поля через CSS, добавить колонтитулы, нумерацию, оглавление, ссылки, вложения и доступные теги, а затем запустить выпуск одной командой либо из Python-кода.

Рабочий процесс строится вокруг исходного HTML и печатного CSS. Пользователь открывает терминал, указывает входной документ и имя выходного PDF, а подробную настройку делает в знакомых веб-разработчику файлах: правила @page управляют страницей, медиавыражения отделяют печатное оформление от экранного, а относительные пути подключают шрифты, изображения и дополнительные стили.

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

Скачать WeasyPrint

Оценка 9.7 Рекомендуем
  • Редактирование PDF
  • Русский интерфейс
  • Просто новичкам
Скачать бесплатно на Windows
Лучшая альтернатива
WeasyPrint
Оценка 8.5
  • Нет визуального редактора
  • Не выполняет JavaScript
  • Нужны HTML и CSS
Скачать WeasyPrint
Загрузка начнётся после нажатия

Как устроено управление и где искать результат

У WeasyPrint нет панели с лентой инструментов, холста и диалогов свойств. Основной интерфейс — команда weasyprint с двумя обязательными позиционными аргументами: источником HTML и файлом назначения. Источником служит путь к файлу, стандартный ввод или адрес страницы, а выходом обычно становится PDF. Такая схема хорошо подходит для повторяемого выпуска: одна и та же команда обрабатывает обновлённые данные без ручного открытия каждого документа.

Справка командной строки WeasyPrint с перечнем параметров

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

Готовый документ не открывается автоматически и не редактируется внутри программы. Проверку выполняют в любом PDF-просмотрщике, причём для сложной печатной формы полезно просмотреть не только первую страницу. Ошибки чаще проявляются в конце таблицы, на странице с длинным заголовком, при переносе сноски или после изменения количества строк. Поэтому тестовый набор должен включать минимальные, средние и предельные данные.

Диагностика воспринимается как часть интерфейса. Предупреждение о неподдерживаемом свойстве не всегда означает неудачу: браузерная таблица стилей может содержать правила для интерактивного экрана, которые не нужны в печати. Важнее отличить ожидаемое пропускание экранного эффекта от правила, без которого теряется содержимое. Для этого печатные стили удобно держать отдельно и подключать через параметр --stylesheet либо через медиавыражение print.

Первое преобразование и минимальная структура шаблона

Надёжный стартовый шаблон содержит корректную кодировку, язык документа, заголовок, основной текст и небольшую таблицу стилей. Язык нужен не только для семантики: он влияет на переносы слов и на корректность доступного PDF. Заголовок попадает в метаданные, а печатный CSS определяет геометрию листа. Даже для одностраничного счёта лучше сразу задать размеры и поля явно, чтобы результат не зависел от предположений автора шаблона.

<!doctype html>
<html lang="ru">
<head>
  <meta charset="utf-8">
  <title>Счёт № 145</title>
  <style>
    @page { size: A4; margin: 18mm 16mm 20mm; }
    body { font-family: sans-serif; font-size: 10pt; }
  </style>
</head>
<body>
  <h1>Счёт № 145</h1>
  <p>Сумма к оплате: 24 800 ₽</p>
</body>
</html>

Команда вида weasyprint invoice.html invoice.pdf читает разметку, загружает связанные ресурсы, рассчитывает раскладку и записывает PDF. Если вход поступает через стандартный ввод или передаётся строкой из Python, программа не может сама догадаться, относительно какой папки искать картинки и шрифты. В таком случае базовый путь необходимо указать отдельно; иначе HTML откроется, но относительные ресурсы пропадут.

Преобразование HTML в PDF и проверка свойств готового файла в терминале

После первой генерации стоит проверить число страниц, формат листа, наличие шрифтов и активных ссылок. Размер файла сам по себе мало говорит о качестве: крупный PDF может содержать несжатые фотографии или полностью встроенные шрифты, а слишком маленький — потерянные изображения. Полезно открыть свойства документа, увеличить мелкий текст до 300–400 процентов и убедиться, что он остаётся векторным, а не превратился в картинку.

Если шаблон формируется системой отчётности, сначала сохраните полученный HTML как отдельный тестовый файл. Это разделяет ошибки данных и ошибки рендеринга. Когда тот же HTML стабильно создаёт правильный PDF из командной строки, причину сбоя в приложении следует искать в рабочей директории, правах, переменных окружения, сетевых запросах или параметрах вызова, а не в макете.

Относительные пути, базовый адрес и загрузка ресурсов

Изображения, CSS, SVG и шрифты разрешаются по тем же принципам, что и в веб-документе, но без контекста вкладки браузера. Для файла на диске базой обычно становится его папка. Для документа, загруженного по сети, базой служит адрес документа. Для строки HTML базу задают параметром base_url в Python или ключом --base-url в командной строке. Это один из самых частых источников ситуации, когда текст виден, а фирменный знак и оформление отсутствуют.

Структура проекта упрощает перенос между компьютерами, если все ресурсы лежат внутри одного каталога: HTML в корне, стили в папке css, изображения в img, шрифты в fonts. Тогда шаблон не содержит абсолютных путей конкретного пользователя. При развёртывании в контейнере достаточно скопировать всю папку и сохранить одинаковую рабочую директорию.

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

Управляемый загрузчик ресурсов особенно полезен в приложении с авторизацией. Обычный запрос не знает сессионные cookie вашего веб-фреймворка, поэтому закрытая картинка из личного кабинета может вернуть страницу входа вместо изображения. Пользовательская функция может сопоставить внутренний адрес с файлом, добавить требуемый заголовок или взять байты из объектного хранилища. Она же позволяет запретить нежелательные схемы и каталоги.

При поиске пропавшего ресурса проверьте путь с учётом регистра букв: на одной файловой системе Logo.svg и logo.svg могут считаться одинаковыми, а на другой — разными файлами. Затем включите подробный журнал и убедитесь, что возвращён ожидаемый MIME-тип. Сервер, который отдаёт HTML-страницу ошибки с кодом успеха, формально доступен, но изображением не является.

Размер страницы, ориентация, поля и область печати

Формат документа задаёт правило @page. Свойство size принимает стандартное имя листа, две длины или сочетание формата и ориентации. Поля задаются обычным margin. Командных ключей для ширины листа и отступов нет: это сознательно оставлено CSS, чтобы геометрия хранилась вместе с макетом и одинаково работала при ручном и программном запуске.

@page {
  size: A4 landscape;
  margin: 12mm 15mm 18mm;
}

@page :first {
  margin-top: 28mm;
}

@page chapter:left {
  margin-left: 24mm;
  margin-right: 18mm;
}

Псевдоклассы страниц позволяют оформлять первую, левую, правую и пустую страницы по-разному. Именованные страницы нужны, когда в одном PDF сочетаются разные форматы: например, титульный лист A4, широкая ведомость в альбомной ориентации и приложение на другом размере. Элементу назначают свойство page, после чего его раздел начинается на странице с соответствующим именем.

В печатной верстке важно различать размер листа и доступную область содержимого. Если A4 имеет ширину 210 мм, а слева и справа задано по 20 мм, строка получает примерно 170 мм. Граница, внутренний отступ и минимальная ширина таблицы дополнительно уменьшают место. Когда блок выходит за край, увеличение формата скрывает проблему, но не исправляет расчёт; лучше найти элемент с фиксированной шириной или длинной непереносимой строкой.

Страница образца WeasyPrint с типографикой и таблицей параметров макета

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

Единицы CSS интерпретируются последовательно: физические миллиметры и сантиметры подходят для печатных размеров, пункты — для типографики, пиксели — для веб-подобных расчётов. Параметр масштабирования в Python затрагивает все единицы, включая физические, поэтому его нельзя использовать как безобидное увеличение качества. Для корректного A4 значение масштаба обычно оставляют равным единице.

Разрывы страниц и управление потоком

Автоматическая пагинация старается размещать блоки в естественном порядке, но деловой документ почти всегда нуждается в подсказках. Свойства break-before, break-after и break-inside управляют началом раздела, завершением блока и допустимостью разрыва внутри него. Старые имена page-break-* встречаются в готовых шаблонах, однако новые свойства понятнее, особенно когда используются колонки.

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

Заголовок не должен отделяться от первого абзаца. Для этого заголовку задают запрет разрыва после, а следующему блоку — контроль висячих и сиротских строк через orphans и widows. Эти свойства не гарантируют идеальный книжный набор при любой длине, но существенно уменьшают страницы с одной строкой вверху или внизу.

Новая глава может начинаться с правой страницы. Значение break-before: right вставит пустую страницу, если это требуется для разворота. Пустая страница доступна через псевдокласс :blank, поэтому на ней можно убрать обычные колонтитулы. Такой приём важен для книг и инструкций, но избыточен для электронного отчёта, где лишний лист воспринимается как ошибка.

Для отладки разрывов полезно временно добавить цветные контуры основным контейнерам и уменьшить документ до данных, которые воспроизводят сбой. Если разрыв меняется после удаления далёкой картинки, причина может быть не в самом проблемном месте, а в перерасчёте высоты предыдущего блока. Минимальный пример помогает отличить ограничение CSS от ошибки в вложенности HTML.

Колонтитулы, номера страниц и повторяющиеся элементы

Поля страницы могут содержать текст, счётчики, изображение и переносимый элемент. Самый простой номер выводится в нижней центральной области через @bottom-center и функцию counter(page). Общее число листов доступно как counter(pages). Комбинация формирует подпись Страница 3 из 18 без предварительного знания длины документа.

@page {
  @bottom-center {
    content: "Страница " counter(page) " из " counter(pages);
    font-size: 8pt;
  }
  @top-right {
    content: string(section-title);
  }
}

h2 { string-set: section-title content(); }

Функция string-set сохраняет содержимое выбранного элемента и делает его доступным в полях страницы. Так в верхнем колонтитуле можно показывать название текущей главы. Важна точка обновления: если заголовок находится внизу страницы, строка может измениться именно на этой странице. Для сложной книги нужно проверить границы разделов и выбрать вариант значения, соответствующий началу или последнему появлению.

Когда колонтитул состоит из логотипа, адреса и линии, удобнее использовать running element. Исходный HTML-блок получает позиционирование running, а поле страницы вставляет его функцией element(). В отличие от абсолютного позиционирования, такой блок повторяется на каждой странице и не перекрывает основной поток при правильно рассчитанных полях.

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

Для первой страницы обычно нужен отдельный вариант без номера или с фирменной шапкой. Это делается правилом @page :first, а не скрытием элемента внутри HTML. Левые и правые страницы книги могут зеркально размещать номер у внешнего края. В отчёте, который просматривают на экране, симметричный нижний центр часто удобнее, поскольку не зависит от режима разворота.

Шрифты, кириллица и переносы слов

WeasyPrint использует шрифтовую подсистему операционной среды и правила @font-face. Если нужный шрифт установлен и находится через системный каталог, достаточно указать семейство. Для воспроизводимого результата лучше включить файлы шрифтов в проект и описать начертания явно. Тогда сервер, рабочая станция и контейнер не подменят гарнитуру разными метрически несовместимыми вариантами.

@font-face {
  font-family: "Report Sans";
  src: url("fonts/report-regular.woff2") format("woff2");
  font-weight: 400;
}
@font-face {
  font-family: "Report Sans";
  src: url("fonts/report-bold.woff2") format("woff2");
  font-weight: 700;
}
body { font-family: "Report Sans", sans-serif; }

Каждое начертание следует объявлять отдельно. Искусственное утолщение может визуально отличаться от фирменного bold и давать другую ширину строк. Для кириллицы файл обязан содержать нужные глифы; наличие латинского алфавита ещё не подтверждает поддержку русских букв, знака рубля, длинного тире и специальных символов. Тестовая строка должна включать все категории знаков, используемые в реальных данных.

Автоматические переносы активируются свойством hyphens: auto и зависят от языка элемента. Указание lang="ru" помогает выбрать русские правила. Переносы полезны в узких колонках и таблицах, но в артикулах, номерах договоров и адресах электронной почты их обычно отключают. Для точечного разрешения разрыва можно вставлять мягкий перенос, однако скрытые символы усложняют поиск и копирование текста.

Оптический результат зависит от межстрочного интервала, ширины колонки и реальных метрик шрифта. Значение line-height без единицы масштабируется вместе с размером текста и обычно предсказуемее фиксированного количества пикселей. В таблицах слишком плотная строка ухудшает читаемость, а слишком свободная резко увеличивает число страниц. Настройку следует проверять на буквах с верхними и нижними выносными элементами и на многострочных ячейках.

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

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

Таблицы, колонки, Flexbox и Grid в печатном макете

Таблицы подходят для данных с настоящими строками и столбцами: позиций счёта, сравнительных показателей, спецификаций. Заголовок таблицы, оформленный через thead, может повторяться на новых страницах. Нижняя часть tfoot полезна для итогов, но поведение при очень большом содержимом нужно проверить на целевом просмотрщике. Семантическая структура даёт движку больше информации, чем набор блоков с имитацией колонок.

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

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

Счёт, сформированный WeasyPrint, с таблицей позиций и итоговой суммой

Многоколоночная раскладка подходит для справочников, коротких заметок и указателей. Свойства количества и ширины колонок позволяют движку распределить поток, а column-span выводит заголовок на всю ширину. В печати следует проверить место перехода между колонками: большой неразрывный объект может оставить заметную пустоту в конце предыдущей колонки.

Страница отчёта WeasyPrint с многоколоночным содержимым

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

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

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

Изображения, SVG, фон и цвет

Растровые изображения вставляются как обычные элементы или фоны. Для фотографии важны физический размер на странице и реальное разрешение. Картинка шириной 1200 пикселей, растянутая на большую полосу, может выглядеть приемлемо на экране и недостаточно чётко в печати. Ограничение DPI позволяет уменьшить избыточные данные, но не создаёт деталей, которых нет в исходнике.

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

Свойство object-fit помогает разместить фотографию в заданной рамке без искажения пропорций. Режим cover обрезает лишнее, contain оставляет поля. Для персональных фотографий и сканов документов автоматическое кадрирование может удалить важную область, поэтому положение объекта задают явно или готовят изображение до генерации.

Фоновые цвета и градиенты входят в PDF, но итог следует оценивать в том цветовом процессе, для которого документ предназначен. Экранный RGB и печатный CMYK решают разные задачи. Для обычного электронного PDF разумен профиль sRGB. Для полиграфии используют определённый выходной профиль и согласованные цвета; простая замена функции цвета не гарантирует соответствие требованиям типографии.

Оптимизация изображений без потери качества уменьшает избыточность, а параметр качества JPEG даёт контролируемый компромисс между размером и артефактами. Сначала стоит удалить заведомо слишком большие исходники и выбрать подходящий формат: схема и логотип обычно лучше в SVG или PNG, фотография — в JPEG. Затем можно включать автоматическую оптимизацию и сравнивать PDF визуально.

Прозрачность и тени полезны для экранных отчётов, но специальные архивные или полиграфические варианты PDF могут предъявлять ограничения. В таких случаях дизайн проверяют валидатором выбранного стандарта. WeasyPrint старается сформировать соответствующий файл, однако некорректный цветовой профиль, неподходящее изображение или структура HTML способны нарушить требования независимо от успешного завершения команды.

Оглавление, закладки, ссылки и перекрёстные ссылки

Заголовки HTML могут автоматически образовывать закладки PDF. Уровень и подпись управляются CSS-свойствами закладок, поэтому служебный заголовок можно исключить, а длинный — заменить более короткой подписью. Иерархия должна быть последовательной: скачок от первого уровня сразу к четвёртому затрудняет навигацию и ухудшает структуру доступного документа.

Оглавление отчёта WeasyPrint с номерами страниц

Печатное оглавление строится на внутренних целях и счётчиках. Функция целевого счётчика позволяет вывести номер страницы, где находится выбранный раздел. Линия точек между названием и номером создаётся лидером. Такой список обновляется при каждом рендеринге, поэтому автору не приходится пересчитывать номера после добавления главы.

Внутренняя ссылка ведёт к идентификатору элемента и остаётся активной в PDF-просмотрщике. Внешние ссылки тоже становятся кликабельными. В печатной версии адрес не всегда виден, поэтому смысл ссылки должен быть понятен из текста. Для документов, которые будут распечатывать, можно отдельным печатным правилом добавлять короткий адрес или QR-код, подготовленный заранее.

Перекрёстная ссылка может показывать номер страницы, название цели или оба значения. Это удобно для инструкций: см. раздел “Настройка”, стр. 12. Важно, чтобы идентификаторы были уникальны. Дублирование id в шаблоне с повторяющимися компонентами приводит к переходу на непредсказуемую цель.

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

Метаданные, вложения и заполняемые поля

Название из элемента title, авторы, описание, ключевые слова и даты могут переноситься в свойства PDF. Язык берётся из атрибута корневого HTML. Эти данные улучшают поиск и помогают системам документооборота, но не заменяют видимые реквизиты. Номер договора или счёта, который важен пользователю, должен присутствовать на странице, а не только в метаданных.

К документу можно прикреплять файлы. Вложение добавляется через соответствующий HTML-элемент, параметр командной строки или объект Python. Практические примеры — исходный XML электронной накладной, таблица расчётов, текстовое примечание. Перед распространением проверьте, что вложение действительно включено и что используемый просмотрщик показывает список прикреплённых файлов.

Обычные поля HTML по умолчанию выглядят в PDF как статическое содержимое. Опция PDF-форм преобразует поддерживаемые элементы ввода в интерактивные поля. Можно включить все формы или пометить отдельные элементы через свойство appearance. Поддержка поведения зависит от PDF-просмотрщика: один клиент корректно показывает выпадающий список и отправку данных, другой ограничивается текстовым полем.

Письмо и печатная форма, созданные средствами WeasyPrint

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

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

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

Архивные, доступные и полиграфические варианты PDF

Параметр варианта PDF позволяет запросить PDF/A, PDF/UA или PDF/X. Это не косметическая метка, а набор требований к структуре, шрифтам, цветам и разрешённым возможностям. Успешно созданный файл ещё нужно проверить профильным валидатором, поскольку соответствие зависит от исходного HTML, CSS, изображений, метаданных и выбранного профиля.

PDF/A предназначен для долговременного хранения. Он требует встроенных шрифтов и определённых цветовых условий, ограничивает мультимедиа и другие возможности, мешающие воспроизводимости. Варианты с суффиксом u сохраняют соответствие текста Unicode, что полезно для поиска и извлечения. Вариант A-3 допускает вложения произвольных форматов и потому применяется в гибридных электронных счетах.

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

PDF/UA ориентирован на доступность. Правильная структура начинается в HTML: логичная последовательность заголовков, семантические списки и таблицы, альтернативные описания значимых изображений, заданный язык и осмысленный заголовок. Автоматически починить бессемантический набор позиционированных блоков на этапе экспорта невозможно.

Тегированный PDF можно запросить отдельно, но наличие тегов не гарантирует удобную навигацию. Проверьте порядок чтения, названия ссылок, заголовки таблиц и отсутствие декоративных изображений в потоке доступности. Данные, переданные только цветом, должны иметь текстовое или графическое различие, понятное без цвета.

PDF/X предназначен для обмена полиграфическими материалами. Он требует выходного цветового профиля и дисциплины в использовании цветов. Вариант X-4 допускает прозрачность, что упрощает современный дизайн по сравнению с более строгими старыми профилями. Тем не менее шрифты, выпуск под обрез и разрешение изображений остаются ответственностью автора шаблона.

Гибридный электронный счёт Factur-X или ZUGFeRD объединяет видимую PDF-страницу и структурированный XML. WeasyPrint может включить подготовленные метаданные и XML как вложение с заданным отношением, после чего сформировать подходящий PDF/A. Содержимое XML программа не рассчитывает за бухгалтерскую систему: суммы, стороны и налоговые поля должны быть сформированы и проверены приложением.

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

Параметры командной строки для стабильного выпуска

Пользовательская таблица стилей подключается ключом -s; ключ можно повторять. Это удобно для отделения базового дизайна, печатных поправок и оформления конкретного клиента. Порядок каскада имеет значение, поэтому переопределения держат в последнем файле и избегают чрезмерного использования !important, которое затрудняет диагностику.

Кодировку входного HTML можно задать явно, если источник не содержит корректной декларации. Однако правильнее исправить генератор и записывать UTF-8 с метатегом. Принудительная кодировка — средство работы с наследуемыми данными, а не замена корректного формата. Если часть текста приходит из другой кодировки уже повреждённой строкой, рендерер не сможет восстановить исходные символы.

Медиатип по умолчанию ориентирован на печать. Параметр media type позволяет выбрать другой набор правил @media, но для PDF обычно логично поддерживать именно print. Если экранная версия страницы зависит от скриптов или скрывает важные блоки до интерактивного действия, следует создать отдельный печатный шаблон, а не пытаться воспроизвести состояние браузера.

Параметры сетевого загрузчика задают тайм-аут, разрешённые протоколы, поведение редиректов и реакцию на HTTP-ошибки. Для автоматического процесса полезно останавливать выпуск при ошибке критического ресурса. Иначе сервер может выдать PDF без логотипа или подписи и формально завершить задачу успешно. Для необязательной иллюстрации допустима мягкая деградация, но она должна быть осознанной.

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

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

Параметры шрифтов позволяют сохранить полные файлы и подсказки. Неподжатый PDF облегчает технический разбор внутренних потоков, но заметно увеличивает размер и не нужен получателю. Подробный журнал полезен во время разработки, тихий — в стабильной очереди, а отладочный режим включают на конкретной неудачной задаче, чтобы журнал не вырос до неуправляемого объёма.

Работа через Python API

Класс HTML принимает имя файла, строку, файловый объект или адрес. Метод write_pdf сразу записывает PDF либо возвращает байты, если путь не задан. Для веб-ответа удобно получить байты в памяти, но крупный отчёт может заметно увеличить потребление памяти. При пакетном выпуске файл назначения часто практичнее.

from weasyprint import HTML

HTML(
    filename="report.html",
    base_url="templates"
).write_pdf(
    "report.pdf",
    optimize_images=True
)

Объект CSS позволяет подключить стиль из файла или строки. Если используются правила @font-face в нескольких таблицах, им передают одну конфигурацию шрифтов. Это обеспечивает согласованную обработку гарнитур. Объекты CSS предназначены для передачи в рендеринг, а не для редактирования уже разобранных правил через публичный интерфейс.

Метод render возвращает объект документа. Через него доступны страницы, метаданные, закладки и дальнейшая запись. Можно выбрать отдельные страницы или собрать новый документ из их копий, например вывести только нечётные листы для проверки. При этом изменения исходного HTML после рендеринга не меняют уже рассчитанный документ: нужно выполнить раскладку заново.

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

Вложения создаются объектом Attachment. Для каждого можно задать имя, описание, даты и отношение к документу. Отношение особенно важно в стандартизованном электронном счёте, где XML считается данными, а не случайным приложением. Имена вложений следует нормализовать и проверять, чтобы пользователь не получил несколько файлов с одинаковым названием.

Функция-финишер позволяет выполнить низкоуровневую обработку PDF непосредственно перед записью трейлера. Это инструмент для специалистов, знакомых с внутренней моделью PDF; обычные метаданные, вложения и варианты лучше задавать штатными параметрами. Ошибка в финишере способна создать файл, который открывается не во всех просмотрщиках.

Пользовательский загрузчик ресурсов связывает WeasyPrint с хранилищем приложения. Новый интерфейс загрузчика позволяет ограничивать протоколы, управлять редиректами и ошибками. Возвращаемый ответ обязан точно описывать данные и тип содержимого. После чтения поток нужно корректно закрывать, особенно при большом числе изображений.

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

Шаблонизаторы и интеграция с веб-приложением

Jinja, Django Templates и другие шаблонизаторы сначала формируют обычный HTML, после чего WeasyPrint выполняет раскладку. Эти этапы полезно разделять в коде: получить данные, отрендерить HTML, проверить обязательные поля, затем создать PDF. При ошибке можно сохранить обезличенный HTML-пример и воспроизвести проблему вне веб-запроса.

Данные должны экранироваться по правилам HTML. Строка клиента не должна превращаться в тег или CSS. Если приложение сознательно разрешает ограниченную разметку, её очищают белым списком до передачи в шаблон. Это важно и для внешнего вида, и для безопасности: встроенный стиль способен изменить размеры страницы, скрыть блок или инициировать загрузку ресурса.

Статические файлы веб-фреймворка часто имеют адреса, доступные браузеру, но недоступные процессу рендеринга без авторизации или запущенного сервера. Более надёжный путь — преобразовать их в файловые пути либо обслуживать через пользовательский загрузчик. В тестах следует воспроизводить ту же схему, что и в рабочей среде, иначе локальная успешная генерация не гарантирует серверный результат.

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

Для мгновенного небольшого документа байты можно вернуть в HTTP-ответе с корректным типом и безопасным именем файла. Имя из пользовательских данных очищают от управляющих символов и разделителей пути. Заголовок загрузки кодируют так, чтобы кириллица отображалась в основных браузерах. Сам PDF не следует кэшировать публично, если он содержит персональные или финансовые сведения.

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

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

Счета, акты и другие документы с расчётами

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

Таблица позиций должна выдерживать длинное название, нулевую скидку, несколько ставок налога и отсутствие необязательного артикула. Числовые столбцы выравнивают по правому краю и запрещают нежелательный перенос внутри суммы. Заголовок повторяется на новых страницах, а блок итогов удерживается вместе, если он помещается на листе.

Реквизиты продавца и покупателя удобно строить двумя колонками, которые переходят в одну при недостатке места. Для официального бланка лучше заранее определить максимальную длину адреса и названия организации. Уменьшать шрифт всего документа из-за одного длинного поля не стоит; можно разрешить перенос и увеличить высоту конкретного блока.

Номер, дата и валюта должны присутствовать в видимом заголовке и метаданных, если это требуется процессом. QR-код или штрихкод готовят как SVG либо качественное растровое изображение без интерполяции. После оптимизации PDF код обязательно считывают реальным сканером или библиотекой — визуально чёткие полосы ещё не гарантируют корректное декодирование.

Для гибридного электронного счёта XML формируется из тех же проверенных данных, что и видимая таблица. Автоматический тест сравнивает итоговую сумму и идентификатор в обоих представлениях. Это предотвращает ситуацию, когда PDF выглядит правильно, а вложенные машинные данные относятся к предыдущему пересчёту.

Многостраничные отчёты и аналитические документы

Отчёт обычно сочетает титульный лист, оглавление, пояснительный текст, таблицы и диаграммы. Каждому типу блока назначают предсказуемые правила разрыва. Титул получает отдельную страницу, заголовки удерживаются с началом раздела, а большие таблицы могут свободно продолжаться. Оглавление строится после того, как все цели присутствуют в HTML.

Титульная страница отчёта, созданного WeasyPrint

Диаграммы лучше передавать как SVG с текстом, если используемая библиотека создаёт совместимую разметку. Скриншот графика делает подписи растровыми и ухудшает масштабирование. При большом количестве точек векторный файл может стать чрезмерно тяжёлым; тогда разумно упростить данные или подготовить растровую версию с рассчитанным разрешением.

Раздел многостраничного отчёта с текстом и выделенной цитатой данных

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

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

Отчёт с переменным объёмом проверяют на данных, где один раздел отсутствует. Оглавление не должно содержать пустую цель, а нумерация последующих глав должна оставаться корректной. Условная генерация HTML удобнее, чем скрытие пустого раздела через CSS, потому что скрытый контент может продолжать влиять на закладки или доступную структуру.

Билеты, пропуска и компактные печатные формы

Билет задаёт нестандартный размер через @page, а содержимое строится вокруг зон, которые должны остаться читаемыми после обрезки. Ключевые данные не размещают вплотную к краю. Штрихкод, имя, место и время имеют собственные минимальные размеры; декоративный фон подстраивается под них, а не наоборот.

Посадочный талон, сформированный WeasyPrint на широком листе

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

Переменные поля должны иметь ограничение длины. Очень длинная фамилия может уменьшаться в рамках заданного диапазона или переноситься в две строки, но нельзя позволять ей закрывать QR-код. Алгоритм выбора размера лучше реализовать в шаблоне ограниченными классами, а не произвольным вычислением для каждой буквы.

Тонкие линии и мелкий текст могут исчезать на бюджетном принтере. Проверка при масштабе 100 процентов на мониторе недостаточна: напечатайте образец на целевом устройстве. Чёрный штрихкод должен иметь достаточный контраст, а фон под ним — быть чистым. Параметры оптимизации изображения не должны размывать код.

Книги, инструкции, письма и плакаты

Книжная верстка использует зеркальные поля, правые начала глав, колонтитулы с названием главы и автоматическое оглавление. В отличие от потока веб-страницы здесь важны развороты. Пустой лист между разделами может быть правильным, если новая часть должна начинаться справа, но его оформление следует отличить от случайно пустой страницы.

Художественная обложка книги из набора примеров WeasyPrint

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

Страница книги WeasyPrint с иллюстрацией, текстом и номером страницы

Письмо требует устойчивого расположения адреса, даты, обращения и подписи, но основной текст должен оставаться обычным потоком. Абсолютные координаты можно применить к адресу для конверта с окном, а абзацы ниже должны переноситься естественно. Когда письмо становится двухстраничным, на второй странице уместен другой верхний колонтитул.

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

Яркий одностраничный плакат, созданный WeasyPrint

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

Инструкция сочетает особенности книги и отчёта: оглавление, нумерованные шаги, предупреждения, рисунки и перекрёстные ссылки. Номер шага лучше хранить в структуре списка или CSS-счётчике, а не печатать вручную. После удаления шага автоматическая нумерация и ссылки должны оставаться согласованными.

Производительность, память и размер результата

Время рендеринга складывается из загрузки ресурсов, разбора HTML и CSS, расчёта раскладки, обработки изображений и записи PDF. Для ускорения сначала измеряют этапы. Медленная внешняя картинка не исправится настройкой шрифтов, а огромная таблица не станет быстрой от сетевого кэша.

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

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

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

Параллелизм ограничивают по памяти, а не только по числу процессорных ядер. Два тяжёлых отчёта могут работать быстрее восьми, если восемь начинают конкурировать за память и уходят в подкачку. Очередь должна знать вес задачи хотя бы приблизительно: число страниц входных данных и общий объём изображений дают полезный ориентир.

Размер PDF анализируют по составляющим. Если основную долю занимают изображения, меняют формат, размер и качество. Если шрифты — проверяют, не включено ли полное встраивание множества гарнитур. Если документ состоит преимущественно из векторного текста, неожиданно большой файл может указывать на повторение сложного SVG на каждой странице.

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

Безопасная обработка HTML и CSS

HTML, CSS и SVG из недоверенного источника нельзя воспринимать как безобидный текст. Они способны инициировать сетевые запросы, обращаться к локальным файлам, задавать огромные размеры и провоцировать длительную раскладку. Рендеринг пользовательского шаблона следует выполнять в изолированной среде с ограничениями времени, памяти, сети и файловой системы.

Процессу не нужны права администратора. Отдельный пользователь получает доступ только к каталогу задачи и заранее разрешённым ресурсам. Контейнер или песочница дополнительно ограничивает видимые файлы. Даже при пользовательском загрузчике защита на уровне операционной системы остаётся полезной на случай ошибки фильтра.

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

Схему file блокируют для недоверенных документов либо ограничивают определённой папкой. Проверка строкового префикса недостаточна: путь нужно нормализовать, разрешить символические ссылки и убедиться, что итоговый файл остаётся внутри разрешённого корня. Временные файлы создают с безопасными именами и удаляют после задачи.

Ограничение времени должно завершать весь рабочий процесс, а не только сетевой запрос. Специально подобранные размеры и взаимозависимые правила могут вызвать очень долгий расчёт без сети. Для надёжного прекращения фонового задания проще использовать отдельный процесс, который можно остановить, чем пытаться прервать вычисление внутри потока.

Ограничение размера входа полезно, но не достаточно. Небольшой CSS может задать огромную страницу или повторение. Поэтому проверяют длину HTML, число узлов, суммарный объём ресурсов и разумные диапазоны критичных параметров, а затем всё равно применяют системный лимит памяти и времени.

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

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

Если не находятся библиотеки или шрифты

Ошибка запуска до чтения HTML обычно связана с отсутствующей системной библиотекой или невозможностью найти её динамический файл. Сначала выполните информационную команду и сохраните полный текст ошибки. Затем сверяйте зависимости именно для своей системы: имя пакета в менеджере Linux, Homebrew и среде Windows может различаться, хотя библиотека выполняет одну функцию.

В Windows готовый командный пакет удобен для запуска из терминала. Для использования Python API требуется рабочая среда Python и доступные нативные зависимости. Если загрузчик DLL не видит каталог, его указывают через предусмотренную переменную директорий и перезапускают процесс. Изменение переменной после импорта библиотеки может оказаться слишком поздним.

В macOS проблема поиска динамической библиотеки иногда решается корректным путём Homebrew и переменной резервного поиска. Важно учитывать архитектуру: пакет для одной архитектуры не загружается процессом другой. Смешивание Python из одного менеджера и библиотек из другого усложняет пути; единый способ установки обычно надёжнее.

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

Отсутствующий шрифт проявляется заменой гарнитуры, квадратами или предупреждением. Проверьте системный список шрифтов и путь @font-face. Для удалённого шрифта проверьте тип ответа и разрешение загрузчика. Воспроизводимый проект хранит разрешённые файлы шрифтов рядом с шаблоном и не зависит от случайного набора на сервере.

Если кириллица есть, но отдельный символ пропал, это может быть неполное покрытие гарнитуры. Знак валюты, математический символ и пиктограмма часто находятся в другом шрифте. Явно задайте цепочку запасных семейств или используйте отдельный SVG-значок. Не заменяйте значимый текст иконкой без доступного текстового эквивалента.

Если пропали CSS, картинки или фон

Первый шаг — включить подробный журнал и определить, какой конкретно ресурс не загрузился. Затем откройте путь относительно базы, используемой рендерером. Ошибка часто возникает после передачи HTML строкой: браузерная страница имела адрес, а строка его потеряла. Указание правильного base_url возвращает контекст относительным ссылкам.

Проверьте, что таблица стилей действительно предназначена для print. Правило внутри @media screen закономерно не действует. Обратная проблема возникает, когда печатный блок скрыт экранным классом с более высокой специфичностью. Инструменты браузера помогают понять каскад, но окончательный результат надо проверять в WeasyPrint, поскольку набор поддерживаемых свойств отличается.

Предупреждение о неподдерживаемом свойстве означает, что это правило пропущено. Найдите печатный эквивалент или упростите блок. Свойства анимации, интерактивные состояния и многие эффекты интерфейса не нужны в статическом PDF. Критичные данные не должны появляться только после JavaScript: WeasyPrint не выполняет сценарии страницы.

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

Для картинки проверьте формат и содержимое. Расширение PNG не гарантирует, что файл действительно PNG. Сервер может вернуть страницу ошибки. Локальный файл может быть нулевой длины или недоступен пользователю службы. SVG следует открыть отдельно и проверить внешние ссылки внутри него.

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

Если ресурсы доступны только по защищённому адресу, обычный загрузчик не наследует сессию браузера. Передавайте их через пользовательский URL fetcher или файловый путь. Включать секретный токен прямо в HTML опасно: он может остаться в журнале, метаданных или отладочном файле.

Если съехала верстка или появились лишние страницы

Сначала сравните фактический размер страницы и поля с расчётом. Затем временно добавьте контуры блокам верхнего уровня. Элемент, выходящий за правый край, часто имеет фиксированную ширину плюс внутренние отступы при неподходящей модели box sizing. Универсальное правило box-sizing: border-box для компонентов делает расчёт предсказуемее.

Лишняя пустая страница в конце нередко создаётся принудительным разрывом после каждого повторяющегося блока. У последнего блока отмените разрыв. В книжном макете пустая страница может быть следствием требования начать раздел справа; тогда проверьте break-before и оформление :blank, а не удаляйте лист вслепую.

Большой пустой участок перед таблицей или карточкой может быть вызван запретом разрыва внутри. Если блок не помещается в оставшееся место, он переносится целиком. Оставьте неразрывным только заголовок с первой строкой или итоговый фрагмент. Для очень большого блока запрет всё равно не может сохранить его на одном листе.

Наложение колонтитула на текст означает, что поле страницы меньше содержимого margin box либо основной блок искусственно поднят отрицательным отступом. Увеличьте соответствующее поле и уберите обходные смещения. Размер колонтитула следует тестировать с самой длинной строкой, а не с коротким примером.

Разница с браузером не обязательно является ошибкой. WeasyPrint ориентирован на paged media и не использует полноценный браузерный движок. Проверьте поддерживаемые свойства и создайте печатное правило. Особенно внимательно относитесь к высоте в процентах, viewport-единицам, сложной сетке и элементам, рассчитанным на интерактивное изменение окна.

Если сбой появляется только на конкретных данных, сократите HTML до минимального случая. Поочерёдно удаляйте соседние блоки, сохраняя проблему. Часто виновата длинная строка без пробела, ячейка с большим SVG или неверно закрытый тег, который изменил структуру всего последующего документа.

Проверяйте результат в нескольких PDF-просмотрщиках, когда проблема касается форм, прозрачности или сложного цвета. Если геометрия текста отличается только при печати, изучите настройку масштабирования драйвера: режим подогнать меняет физический размер, хотя PDF сформирован правильно. Для бланка печатайте в масштабе 100 процентов.

Сравнение WeasyPrint с аналогами

ПрограммаЛучше подходит дляГлавное ограничение
WeasyPrintПечатные HTML/CSS-шаблоны, отчёты, счета, книги и интеграция с PythonНет визуального редактора и исполнения JavaScript
PDF CommanderРучное редактирование готовых PDF, перестановка страниц, подписи и повседневная работа без кодаНе предназначен для серверной генерации из HTML-шаблонов
wkhtmltopdfПреобразование существующих веб-страниц через командную строку с поведением WebKitСовременный CSS и сложная печатная верстка могут требовать обходных решений
PlaywrightДинамические страницы, которым требуется Chromium и выполнение JavaScript перед печатьюНужен полноценный браузер и больше ресурсов
PuppeteerАвтоматизация Chrome из JavaScript и PDF из интерактивного веб-интерфейсаОриентирован на экосистему Node.js и браузерный процесс
PrinceПрофессиональная издательская верстка HTML/CSS с развитой поддержкой печатных стандартовДля коммерческого применения требуется соответствующая лицензия
xhtml2pdfПростые PDF из HTML внутри Python-проектов с умеренными требованиями к оформлениюПоддержка современного CSS заметно уже

WeasyPrint выбирают, когда источник контролируется, данные уже доступны в Python, а страницы должны подчиняться печатному CSS с колонтитулами, счётчиками и автоматической пагинацией. Playwright или Puppeteer практичнее, если PDF нужно снимать с интерактивной страницы после выполнения JavaScript. Prince подходит издательским процессам, где важна расширенная печатная функциональность и приемлема коммерческая лицензия. PDF Commander полезнее сотруднику, которому надо открыть уже созданный файл, вручную исправить страницу или собрать документ без разработки шаблона. xhtml2pdf остаётся вариантом для более простого HTML, а wkhtmltopdf встречается в существующих системах, где макет уже подстроен под его движок.

Выбор следует делать на тестовом документе, а не по одному списку свойств. Подготовьте страницу с реальными шрифтами, широкой таблицей, длинным текстом, SVG, колонтитулом и ссылками. Сравните число исправлений в CSS, скорость, размер PDF, доступность текста и требования к окружению. Решение, которое сразу даёт правильный визуальный результат, но требует тяжёлого браузера, может быть хуже в массовой очереди; лёгкий движок, требующий переделки всех шаблонов, может оказаться дороже внедрения.

Практическая схема подготовки надёжного шаблона

Начните с семантического HTML без декоративных координат. Разделите документ на титул, секции, таблицы и служебные блоки. Укажите язык, заголовок и кодировку. Подключите печатную таблицу стилей и задайте @page. После этого добейтесь правильного потока текста до добавления сложного фона и декоративных элементов.

Подключите фиксированный набор шрифтов и проверьте кириллицу, цифры, валюту и специальные знаки. Настройте размеры, межстрочный интервал и переносы. Затем добавьте таблицы и проверьте повтор заголовков, длинные ячейки, итоговый блок и пустой набор данных. Только после устойчивой пагинации переходите к колонтитулам, оглавлению и перекрёстным ссылкам.

Ресурсы храните в предсказуемой структуре и всегда задавайте базу при генерации из строки. Для сети установите тайм-аут и политику ошибок. Для недоверенного ввода используйте отдельный процесс, ограничения и пользовательский загрузчик. Не позволяйте шаблону обращаться к произвольным локальным файлам.

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

Для визуальной регрессии храните несколько эталонных страниц, а не весь документ на сотни листов. Титул показывает шрифты и фон, середина таблицы — повтор заголовков, граница раздела — разрывы и колонтитулы, последняя страница — итоги и завершение. После изменения зависимостей сравните эти страницы и вручную просмотрите полный предельный документ.

Специальный вариант PDF включайте только вместе с профильной проверкой. Для PDF/UA тестируйте структуру и порядок чтения, для PDF/A — встраивание шрифтов и соответствие профилю, для PDF/X — цветовой профиль и выпуск. Для формы проверяйте ввод в нескольких просмотрщиках. Для вложений убеждайтесь, что они открываются и имеют правильное имя.

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

После стабилизации шаблон становится воспроизводимым производственным инструментом: данные меняются, а правила страницы, типографика и навигация остаются едиными. Именно в таком процессе сильные стороны WeasyPrint раскрываются лучше всего — печатный CSS хранит логику макета, командный вызов обеспечивает повторяемость, а Python API связывает генерацию с проверенными данными и автоматическими тестами.