2025, Oct 19 09:16

Не работают стили Markdown в HTML на Python: как исправить

Почему стили Markdown из CSS не применяются к HTML, сгенерированному в Python, и как это исправить: добавьте класс .markdown-body и правильную структуру.

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

Постановка задачи

HTML генерируется из Markdown, затем вставляется в минимальный документ с подключённой таблицей стилей. Страница открывается, но оформление остаётся «плоским».

from markdown import markdown as md_convert
md_source = '''
#Example
## Emphasis
**This is bold text**
__This is bold text__
 ...
'''
result_html = md_convert(md_source, extensions=['fenced_code','codehilite'])
stylesheet_url = '"css/github-markdown.css"'
page_html = f'<html><head><link rel="stylesheet" type="text/css" href={stylesheet_url}></head><body>{result_html}</body></html>'
print(page_html)

Сформированный HTML соответствует этому шаблону и отображается без ошибок, но без задуманных стилей Markdown. При этом в CSS правила описаны внутри класса вроде .markdown-body.

Почему стили не применяются

Таблица стилей использует скоуп‑селекторы вроде .markdown-body. То есть она предполагает, что отрендеренный Markdown находится внутри элемента с этим классом. Если в HTML нет такого класса на контейнере, селекторы не совпадают — и вы видите типографику и отступы по умолчанию от браузера. Ожидаемая структура выглядит так:

<body class="markdown-body"><h1>Example</h1> ...</body>

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

Как исправить структуру страницы

Решение — добавить нужный таблице стилей класс на контейнер страницы. Если повесить его на элемент body, правила применятся ко всему содержимому Markdown. В примере ниже также добавлена минимальная «шапка» документа, чтобы страница была полноценной.

from markdown import markdown as md_convert
md_source = '''
#Example
## Emphasis
**This is bold text**
__This is bold text__
 ...
'''
result_html = md_convert(md_source, extensions=['fenced_code','codehilite'])
stylesheet_url = '"css/github-markdown.css"'
page_html = f'''
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <link rel="stylesheet" type="text/css" href={stylesheet_url}>
    <title>Markdown Viewer</title>
  </head>
  <body class="markdown-body">
    {result_html}
  </body>
</html>
'''
print(page_html)

Так вы гарантируете, что селекторы .markdown-body из таблицы стилей совпадут, и страница отобразится с ожидаемой типографикой и отступами Markdown.

Почему это важно

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

Что запомнить

Если кажется, что стили игнорируются, проверьте CSS: не ограничены ли правила классом вроде .markdown-body. Затем убедитесь, что сгенерированный Markdown находится внутри элемента с этим классом. С таким контейнером HTML, полученный из Markdown, будет отображаться как задумано.

Статья основана на вопросе на StackOverflow от royer и ответе от royer.