Кастомизация сборки PDF через WeasyPrint
WeasyPrint использует собственный движок отрисовки HTML. Движок поддерживает большинство возможностей языка стилей CSS, но не поддерживает скрипты JavaScript. Полный список особенностей движка приведён в разделе Supported Features документации WeasyPrint.
Способы кастомизации, специфичные для генерации PDF, преимущественно связаны с поддержкой следующих стандартов:
- CSS Paged Media (правило
@rule
, колонтитулы), - CSS Generated Content (свойства
content
иstring-set
), - CSS Lists and Counters (счётчики).
Шаблон для рендеринга страниц #
Файл print.html
используется как шаблон при рендеринге каждой страницы документации.
Для превращения шаблона в конечную HTML-страницу используется шаблонизатор Jinja. Руководство по синтаксису шаблонизатора можно найти на его официальном сайте: Template Designer Documentation.
Шаблону доступен набор переменных и функций, описанных в разделе API для шаблонов.
В Собираке отключена поддержка стандартного синтаксиса комментариев внутри шаблона Jinja, чтобы избежать коллизии с идентификаторами заголовков в Markdown. Чтобы добавить комментарий внутрь шаблона, используйте синтаксис со сдвоенными фигурными скобками: {{# Комментарий #}}
.
Статические файлы #
Все файлы, необходимые для корректного отображения темы (стили, изображения, шрифты), должны находиться в поддиректории _static
рядом с шаблоном. Шаблон должен ссылаться на эти файлы через относительные пути, например:
<link rel='stylesheet' href='_static/theme.css'/>
Плагин для обработки страниц #
В файле extension.py
может быть определён обработчик страниц — код на Python для дополнительной обработки содержимого перед рендерингом.
Класс плагина должен наследоваться от класса WeasyPrintProcessor
. Плагин имеет почти неограниченные возможности в рамках обработки отдельной страницы, см. API для обработчиков.
Нумерация заголовков #
Нумерация для каждого заголовка (или информация о том, что этот заголовок не нумеруется) доступна через объект RT
в момент применения темы. Один из способов перенести эту информацию в документ — в коде theme.py
привести её к строке и записать в атрибут data-number
заголовка (вы можете использовать другое название атрибута). Пример ниже реализует это для заголовков первого уровня:
class MyWeasyPrintProcessor(WeasyPrintProcessor):
async def process_header(self, header: Header, page: Page):
header, = await super().process_header(header, page)
if header.level == 1:
header.attributes['data-number'] = str(RT[page].number)
return header,
Стиль CSS может сослаться на содержимое этого атрибута через функцию attr()
— например, для псевдоселектора ::before
. Пример ниже отображает номер заголовка перед текстом заголовка серым цветом:
h1::before {
color: gray;
content: attr(data-number) '. ';
}
Колонтитулы #
Специальное правило @page
описывает стиль каждой страницы печатного документа. Свойство margin
этого правила определяет отступы, в которых не может быть размещён основной контент страницы, но на этих отступах могут быть размещён дополнительный контент — колонтитулы. Содержимое и стили колонтитулов настраиваются с помощью правил, вложенных в @page
.
Разные правила соответствуют разным зонам на полях: например, @top-left-corner
отвечает за зону выше и левее основного контента, а @top-left
— за зону выше, но не левее. Полный список доступных зон можно посмотреть по ссылке: Page-Margin Box Definitions.
Часто в колонтитулах требуется показывать заголовок текущей главы документа — иными словами, содержимое последнего встреченного заголовка. Это можно сделать с помощью свойств string-set
и content
. Пример ниже демонстрирует это на примере заголовков <h1>
: при обработке каждого такого заголовка обновляется содержимое строки current-title
(вы можете использовать другое название строки), а правило @top-left
подставляет эту строку в верхний левый угол страницы.
@page {
@top-left {
content: string(current-title);
}
}
h1 {
string-set: current-title content();
}
Нумерация страниц #
В любой момент в CSS доступен счётчик page
, равный номеру текущей страницы PDF-документа. Получить его текущее значение можно через функцию counter()
. Например, так можно подставить номер страницы в верхний правый колонтитул:
@page {
@top-right {
content: counter(page);
}
}
Помимо значения счётчика в текущем месте документа, существует способ получить значение для места, указанного в атрибуте href
текущего элемента. Для этого необходимо использовать функцию target-counter()
. Например, в момент обработки ссылки в оглавлении можно узнать, какое значение page
будет там, куда ведёт эта ссылка:
ul.toc a::after {
content: ' (стр. ' target-counter(attr(href), page) ')';
}
Обложка #
Тема по умолчанию размещает на первой странице PDF-документа простую обложку. По центру обложки отображается название документа (из настройки title
), а внизу — текущий год. Оба элемента можно заменить на произвольный текст, если добавить в variables
переменные COVER_CENTER
и COVER_BOTTOM
соответственно. Также можно добавить произвольный текст в верхней части обложки с помощью переменной COVER_TOP
.
Более тонкая настройка внешнего вида обложки требует написания собственных стилей CSS. Если вы хотите изменить внешний вид обложки в рамках темы по умолчанию, ознакомьтесь с её файлом _cover.scss
. В нём задан не только стиль для блока .cover
, но и параметры страницы cover
: размер отступов и скрытие колонтитулов. Тип страницы определён с помощью правила @page
и привязан к блоку .cover
через свойство page.
Пример ниже добавляет к стандартной обложке фон, а также меняет цвет всего текста на ней.
@page cover {
background-image: url('cover.png');
background-size: cover;
}
.cover {
color: white;
}
Горизонтальные страницы #
Тема, используемая Собиракой по умолчанию, определяет специальный тип страниц landscape
с горизонтальной ориентацией. Тип применяется к любой странице, на которой находится элемент со свойством page: landscape
.
Работа устройства показана на большой горизонтальной схеме ниже.
`<div style="page:landscape; page-break-after:always"></div>`{=html}

Подсветка кода #
Поскольку WeasyPrint не поддерживает JavaScript, подсветка блоков кода должна быть реализована во время сборки HTML-содержимого. Собирака реализует её с помощью библиотеки Pygments, но по умолчанию не подключает соответствующие стили CSS, оставляя это на усмотрение автора темы.
Самый простой способ добавить стиль — выбрать понравившийся на странице Styles официального сайта Pygments, а затем локально сгенерировать необходимый файл CSS. Например:
pygmentize -f html -S tango > _static/pygments-tango.css
Полученный файл укажите в стилях документа обычным способом:
<link rel='stylesheet' href='_static/pygments-tango.css'/>
Файлы стилей SASS #
Некоторые темы оформления (в том числе фирменная тема sobiraka2025
) используют препроцессор SASS и его языки SASS или SCSS для генерации стилей. Собирака запускает генерацию в рамках процесса сборки документации. Обратите внимание, что необходимая для этого команда sass
не входит в Собираку и должна быть установлена отдельно.
Исходный файл стиля должен располагаться по адресу sass/print.sass
или sass/print.scss
в директории темы. При необходимости он может подключать другие файлы с помощью SASS-директивы @use
.
Тема может включать в себя несколько вариантов оформления в поддиректории _flavors
. Для выбора нужного варианта следует указать его название в настройке pdf.theme.flavor
. Разработчик темы должен подключить выбранный пользователем вариант с помощью конструкции @use 'flavor'
. Какие именно SASS-переменные и миксины возможно переопределить таким способом, зависит от конкретной темы.
Также возможно добавление файлов SASS/SCSS из директории проекта. Файлы, указанные в pdf.theme.customization
, участвуют в генерации основного стиля наравне с собственными файлами темы. Из файлов, указанных в pdf.custom_styles
, генерируются дополнительные CSS-стили.
Теги <link>
со ссылками на все собранные стили CSS будут автоматически включены в переменную head
, которую рекомендуется подключить в HTML-шаблон, см. API для шаблонов.