Кастомизация сборки 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 для шаблонов.