- D: применяется специально для Django
- H: применяется к html
- J: применяется специально для Jinja
- M: применяется специально для Handlebars
- N: применяется специально для Nunjucks
- T: применяется в целом к шаблонам
djLint включает в себя множество правил для проверки стиля и валидности ваших шаблонов. Используйте все преимущества линтера, настроив его на использование предустановленного профиля для выбранного вами языка шаблонов.
djlint /path/to/templates --lint
# with custom extensions
djlint /path/to/templates -e html.dj --profile=django
# or to file
djlint /path/to/this.html.j2 --profile=jinja
Большинство правил включены по умолчанию. Правила могут быть отключены в командной строке с помощью флага --ignore. Правила могут быть включены с помощью флага --include.
Например:
djlint . --lint --include=H017,H035 --ignore=H013,H015
Это также можно сделать через Конфигурация файл.
| Код | Значение | По умолчанию |
|---|---|---|
| D004 | (Django) Статические урлы должны следовать шаблону {% static path/to/file %}. |
✔️ |
| D018 | (Django) Внутренние ссылки должны использовать шаблон {% url ... %}. |
✔️ |
| H005 | Html-тег должен иметь атрибут lang. |
✔️ |
| H006 | Тег img должен иметь атрибуты height и width. |
- |
| H007 | <!DOCTYPE ... > должен присутствовать перед тегом html. |
✔️ |
| H008 | Атрибуты должны быть заключены в двойные кавычки. | ✔️ |
| H009 | Имена тегов должны быть в нижнем регистре. | ✔️ |
| H010 | Имена атрибутов должны быть в нижнем регистре. | ✔️ |
| H011 | Значения атрибутов должны быть заключены в кавычки. | ✔️ |
| H012 | Вокруг атрибута = не должно быть пробелов. |
✔️ |
| H013 | Тег img должен иметь атрибуты alt. |
✔️ |
| H014 | Более 2 пустых строк. | ✔️ |
| H015 | После тегов h следует перевод строки. |
✔️ |
| H016 | Отсутствие тега title в html. |
✔️ |
| H017 | Пустые теги должны быть самозакрывающимися (противоречит правилу H018). | - |
| H018 | Пустые теги по своей природе являются самозакрывающимися и должны заканчиваться символом «>», а не «/>» (конфликт с: H017). | - |
| H019 | Замените javascript:abc() на событие on_ и реальный url. |
✔️ |
| H020 | Найдена пустая пара тегов. Рассмотрите возможность удаления. | ✔️ |
| H021 | Следует избегать инлайн-стилей. | ✔️ |
| H022 | Используйте HTTPS для внешних ссылок. | ✔️ |
| H023 | Не используйте ссылки на сущности. | ✔️ |
| H024 | Опускайте тип в скриптах и стилях. | ✔️ |
| H025 | Тег кажется бесхозным. | ✔️ |
| H026 | Пустые теги id и class могут быть удалены. | ✔️ |
| H029 | Рассмотрите возможность использования строчных значений метода формы. | ✔️ |
| H030 | Рассмотрите возможность добавления мета-описания. | ✔️ |
| H031 | Рассмотрите возможность добавления мета-ключевых слов. | - |
| H033 | В действии формы обнаружен лишний пробел. | ✔️ |
| J004 | (Jinja) Статические урлы должны следовать шаблону {{ url_for('static'...)}}. |
✔️ |
| J018 | (Jinja) Внутренние ссылки должны использовать шаблон {% url ... %}. |
✔️ |
| T001 | Переменные должны быть заключены в пробел. Например: {{ this }} |
✔️ |
| T002 | В тегах следует использовать двойные кавычки. Ex {% extends "this.html" %} |
- |
| T003 | Конечный блок должен иметь имя. Например: {% endblock body %}. |
- |
| T027 | В синтаксисе шаблона найдена незакрытая строка. | ✔️ |
| T028 | Рассмотрите возможность использования тегов без пробелов внутри значений атрибутов. {%- if/for -%} |
✔️ |
| T032 | В тегах шаблона обнаружены лишние пробелы. | ✔️ |
| T034 | Вы намеревались использовать {% … %} вместо {% … }%? | ✔️ |
| H035 | Meta должны быть самозакрывающимися. | - |
| H036 | Избегайте использования тегов br. |
- |
| H037 | Найдено дублирование атрибута. | ✔️ |
| T038 | Блочный тег не имеет соответствующего закрывающего тега. | ✔️ |
| T039 | Найден незакрытый тег шаблона. | ✔️ |
| T040 | Отсутствующее или пустое имя шаблона в теге extends или include. | ✔️ |
| H041 | Тег закрывается в другом блоке шаблона, чем тот, в котором он был открыт. | ✔️ |
| H042 | Атрибут for у label не имеет соответствующего id в этом файле. | ✔️ |
Первая буква кода соответствует схеме:
Переменные должны быть заключены в пробел. Например: {{ this }}
Синтаксис шаблона вроде {{user.name}} без внутренних пробелов труднее читать и сравнивать в diff, а непоследовательные пробелы по кодовой базе делают рефакторинг через grep (поиск переменной или тега) ненадёжным: одно и то же выражение существует в нескольких написаниях. Руководства по стилю и Django, и Jinja пишут {{ var }} и {% tag %} с одиночными пробелами.
Не применяется к профилям handlebars и golang.
Неправильно:
{{user.name}}
Правильно:
{{ user.name }}
В тегах следует использовать двойные кавычки. Ex {% extends "this.html" %}
Отключено по умолчанию; включается флагом --include=T002.
Смешение одинарных и двойных кавычек в тегах шаблона ({% extends %}, {% include %}, {% with %}, {% trans %}, {% now %}) приводит к тому, что одно и то же имя шаблона встречается в двух написаниях, и поиск или массовое переименование пропускает половину вхождений. Стандартизация на двойных кавычках делает аргументы тегов согласованными с кавычками HTML-атрибутов в остальной части файла.
Одинарные кавычки внутри значений HTML-атрибутов (например, <span title="{% trans 'x' %}">) не помечаются, так как двойные кавычки атрибута вынуждают использовать там одинарные.
Неправильно:
{% extends 'base.html' %}
Правильно:
{% extends "base.html" %}
Конечный блок должен иметь имя. Например: {% endblock body %}.
Когда {% block %} занимает много строк или блоки вложены, безымянный {% endblock %} не даёт понять, какой блок он закрывает, поэтому при правках легко закрыть не тот блок, и дочерние шаблоны переопределят не то содержимое. Имя у endblock документирует парность и позволяет как djLint, так и Django (который выбрасывает TemplateSyntaxError при несовпадающем имени endblock) поймать блок, закрытый не в том месте. Ошибки парности (незакрытые блоки, осиротевшие endblock и несовпадающие имена) проверяются правилом T038.
Отключено по умолчанию; включается флагом --include=T003.
Имя не требуется, когда блок открывается и закрывается на одной строке, например {% block title %}``{% endblock %}.
Неправильно:
{% block content %}
<p>hello</p>
{% endblock %}
Правильно:
{% block content %}
<p>hello</p>
{% endblock content %}
(Django) Статические урлы должны следовать шаблону {% static path/to/file %}.
Жёстко прописанные пути /static/ обходят тег Django {% static %}: шаблоны ломаются при изменении STATIC_URL (например, при переносе статики на CDN или развёртывании по под-пути) и никогда не подхватывают хэшированные имена файлов из ManifestStaticFilesStorage, что приводит к ошибкам 404 или устаревшим закэшированным ресурсам в продакшене.
Неправильно:
<link rel="stylesheet" href="/static/css/style.css">
Правильно:
<link rel="stylesheet" href="{% static 'css/style.css' %}">
(Jinja) Статические урлы должны следовать шаблону {{ url_for('static'...)}}.
Жёстко прописанные пути /static/ обходят url_for(‘static’, …) из Flask/Jinja: при монтировании приложения под URL-префиксом или изменении каталога/хоста статики ресурсы отдают 404, а добавляемые фреймворком query-строки для сброса кэша теряются.
Неправильно:
<link rel="stylesheet" href="/static/css/style.css">
Правильно:
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
Html-тег должен иметь атрибут lang.
Без атрибута lang на <html> скринридеры угадывают правила произношения и могут читать страницу не на том языке, а браузеры не могут корректно предложить перевод, расстановку переносов или локальные кавычки. Объявление языка страницы является критерием успеха 3.1.1 WCAG 2.1 (уровень A).
Неправильно:
<!DOCTYPE html>
<html>
</html>
Правильно:
<!DOCTYPE html>
<html lang="en">
</html>
Тег img должен иметь атрибуты height и width.
Отключено по умолчанию; включается флагом --include=H006.
Когда у <img> нет width и height, браузер не может зарезервировать место до загрузки изображения, и окружающий контент прыгает по мере загрузки картинок. Этот сдвиг вёрстки ухудшает Cumulative Layout Shift (метрику Core Web Vitals) и может приводить к промахам по кликам, пока страница не стабилизировалась.
Неправильно:
<img src="cat.png" alt="Cat">
Правильно:
<img src="cat.png" alt="Cat" width="120" height="80">
<!DOCTYPE ... > должен присутствовать перед тегом html.
Без <!DOCTYPE> перед тегом <html> браузеры рендерят страницу в режиме совместимости (quirks mode), эмулируя устаревшую блочную модель и поведение вёрстки, поэтому CSS отображается в браузерах по-разному. Теги шаблона и комментарии перед doctype допустимы; он должен предшествовать только самому тегу <html>.
Неправильно:
<html lang="en">
</html>
Правильно:
<!DOCTYPE html>
<html lang="en">
</html>
Атрибуты должны быть заключены в двойные кавычки.
Смешанные стили кавычек затрудняют чтение и поиск значений атрибутов, а значения в одинарных кавычках ломаются, как только в содержимом появляется апостроф. Двойные кавычки являются соглашением, принятым в спецификациях HTML, форматерах и большинстве руководств по стилю, поэтому стандартизация на них держит шаблоны в согласии с остальной экосистемой.
Неправильно:
<div class='content'></div>
Правильно:
<div class="content"></div>
Имена тегов должны быть в нижнем регистре.
HTML-парсеры принимают имена тегов в верхнем регистре, но сериализации XHTML и XML чувствительны к регистру и отвергают их, а смешанный регистр делает текстовый поиск и ревью diff ненадёжными (grep по <h1> не найдёт <H1>). Имена тегов в нижнем регистре сохраняют переносимость и единообразие шаблонов.
Неправильно:
<H1>Welcome</H1>
Правильно:
<h1>Welcome</h1>
Имена атрибутов должны быть в нижнем регистре.
Имена атрибутов в верхнем регистре недопустимы в сериализациях XHTML/XML и ломают текстовый поиск по шаблонам (grep по src= не найдёт SRC=). DOM всё равно нормализует имена HTML-атрибутов к нижнему регистру, поэтому написание в верхнем регистре добавляет разнобой без всякой пользы.
Неправильно:
<img SRC="cat.png" alt="Cat" width="120" height="80">
Правильно:
<img src="cat.png" alt="Cat" width="120" height="80">
Значения атрибутов должны быть заключены в кавычки.
Значение атрибута без кавычек заканчивается на первом пробеле, поэтому значение вроде class=btn primary молча теряет всё после пробела (браузер считает “primary” отдельным булевым атрибутом). Особенно хрупки значения из переменных шаблона: любой отрендеренный пробел, “=” или “>” ломает тег. Кавычки делают границы значения явными и безопасными.
Неправильно:
<div class=test></div>
Правильно:
<div class="test"></div>
Вокруг атрибута = не должно быть пробелов.
С пробелами вокруг “=” тег читается как три отдельных токена и находится в одной правке от развала: перенос строки или обрезка посередине оставляет голый булев атрибут и обрывок текста. Слитная запись name=“value” является ещё и тем, чего ожидают простые текстовые инструменты (grep, поиск с заменой), поэтому разнобой в пробелах мешает надёжно находить и рефакторить атрибуты.
Неправильно:
<div class = "test"></div>
Правильно:
<div class="test"></div>
Тег img должен иметь атрибуты alt.
Без атрибута alt скринридеры произносят имя файла изображения или вообще ничего, что нарушает WCAG 1.1.1 (Non-text Content). Текст alt является ещё и тем, что видят пользователи, когда изображение не загрузилось. Декоративным изображениям следует давать явно пустой alt=“”, чтобы вспомогательные технологии знали, что их нужно пропустить; это тоже удовлетворяет правилу.
Неправильно:
<img src="cat.jpg" height="200" width="300">
Правильно:
<img src="cat.jpg" height="200" width="300" alt="A sleeping cat">
Более 2 пустых строк.
Серии пустых строк никак не влияют на отрендеренную страницу (HTML схлопывает пробелы), но раздувают шаблоны и создают шумные diff при изменении соседних строк. Форматер djLint по умолчанию удаляет их полностью (оставляя не более max_blank_lines пустых строк, по умолчанию 0), поэтому оставшиеся серии указывают на неотформатированный код.
Неправильно:
<div>one</div>
<p>two</p>
Правильно:
<div>one</div>
<p>two</p>
После тегов h следует перевод строки.
Заголовки являются блочными ориентирами, задающими структуру документа; когда следующий элемент лепится на ту же строку, что и закрывающий h-тег, эта структура прячется в исходнике, а правки любого из элементов выглядят в diff как изменения обоих. Перевод строки после каждого заголовка держит визуальную структуру шаблона в соответствии со структурой отрендеренного документа.
Неправильно:
<h1>Heading</h1><p>Intro text.</p>
Правильно:
<h1>Heading</h1>
<p>Intro text.</p>
Отсутствие тега title в html.
Спецификация HTML требует элемент title в каждом документе. Без него вкладки браузера, закладки и история показывают голый URL вместо названия страницы, поисковые системы теряют основную метку страницы, а пользователи скринридеров теряют первое, что объявляется при загрузке, что нарушает WCAG 2.4.2 (Page Titled, уровень A).
Срабатывает только на файлах с полным документом <html>…</html>, поэтому фрагменты и дочерние шаблоны, расширяющие базовый, никогда не помечаются. Оболочкам SPA, задающим заголовок на клиенте, статический <title> всё равно нужен: именно он виден при первой отрисовке, краулерам и при отказе JavaScript.
Неправильно:
<html lang="en">
<body>Content</body>
</html>
Правильно:
<html lang="en">
<head>
<title>My page</title>
</head>
<body>Content</body>
</html>
Пустые теги должны быть самозакрывающимися (противоречит правилу H018).
Шаблоны, которые должны также разбираться как XML/XHTML (или скармливаться XML-инструментам), не принимают пустые (void) элементы без закрывающего слэша, а смешение <br> и <br /> по кодовой базе даёт непоследовательные diff. Это правило вводит соглашение в стиле XHTML, чтобы каждый пустой элемент закрывался одинаково.
Отключено по умолчанию; включается флагом --include=H017. Взаимоисключимо с H018: включайте только одно из двух соглашений.
Неправильно:
<br>
<meta charset="utf-8">
Правильно:
<br />
<meta charset="utf-8" />
(Django) Внутренние ссылки должны использовать шаблон {% url ... %}.
Жёстко прописанные внутренние URL незаметно устаревают, когда путь маршрута меняется в urls.py, порождая битые ссылки и нерабочие action у форм, которые не поймает ни один тест URLconf. {% url %} строит путь по имени маршрута, поэтому переименование пути обновляет все ссылки сразу.
Неправильно:
<a href="/accounts/login">Login</a>
Правильно:
<a href="{% url 'login' %}">Login</a>
Пустые теги по своей природе являются самозакрывающимися и должны заканчиваться символом «>», а не «/>» (конфликт с: H017).
В живом стандарте HTML завершающий слэш у пустого (void) элемента ничего не значит (парсер его игнорирует), поэтому запись <br /> намекает на XML-подобное самозакрытие, которого в HTML нет, и может подтолкнуть читателей ставить слэши у непустых тегов, где лишний / молча отбрасывается и маскирует ошибки с незакрытыми тегами. Это правило требует, чтобы пустые элементы заканчивались простым >.
Отключено по умолчанию; включается флагом --include=H018. Взаимоисключимо с H017: включайте только одно из двух соглашений. SVG <path /> исключён: SVG является XML, и слэш там обязателен.
Неправильно:
<br />
<meta charset="utf-8" />
Правильно:
<br>
<meta charset="utf-8">
(Jinja) Внутренние ссылки должны использовать шаблон {% url ... %}.
Жёстко прописанные внутренние URL незаметно ломаются, когда меняется путь маршрута или приложение монтируется под префиксом, оставляя мёртвые ссылки и формы, отправляющие данные на 404. url_for() строит URL по имени эндпоинта, поэтому изменения маршрутов автоматически распространяются на все шаблоны.
Неправильно:
<a href="/accounts/login">Login</a>
Правильно:
<a href="{{ url_for('login') }}">Login</a>
Замените javascript:abc() на событие on_ и реальный url.
URL вида javascript: ломают клик средней кнопкой и открытие в новой вкладке, не работают при отключённом или не загрузившемся JavaScript, блокируются строгими Content Security Policy и являются классическим каналом XSS-инъекций. Используйте в href настоящий URL, а поведение подключайте обработчиком события. При строгой CSP инлайновые обработчики on* тоже блокируются. Показанный onclick лишь минимальная правка внутри шаблона; предпочтительнее вешать слушатель через addEventListener из файла скрипта.
Неправильно:
<a href="javascript:openPopup()">Open popup</a>
Правильно:
<a href="{% url 'popup' %}" onclick="openPopup(event)">Open popup</a>
Найдена пустая пара тегов. Рассмотрите возможность удаления.
Пустая пара тегов не рендерит контент, но всё равно создаёт DOM-узел, который может подхватить из стилей отступы, рамки или промежутки flex/grid, порождая фантомные зазоры, которые трудно отследить; обычно это остаток разметки от прежней правки. Теги, которые в обычной разметке законно бывают пустыми (td, th, li, dt, dd, slot), исключены. Теги с любым атрибутом (точки монтирования JS вроде <div id="app">``</div>, элементы иконочных шрифтов вроде <i class="fa fa-user">``</i>) тоже не помечаются; правилу соответствуют только совершенно пустые пары без атрибутов.
Неправильно:
<p>Saved.</p>
<span> </span>
Правильно:
<p>Saved.</p>
Следует избегать инлайн-стилей.
Инлайн-стили имеют более высокую специфичность, чем любой селектор в таблице стилей, поэтому переопределять их потом приходится через !important; они блокируются Content Security Policy без ‘unsafe-inline’ в style-src; и они размазывают оформление по шаблонам, так что смена темы или дизайна означает правку разметки вместо одной таблицы стилей. Перенесите объявление в CSS-класс. Одно законное исключение составляют шаблоны HTML-писем: многие почтовые клиенты вырезают блоки <style>, и инлайн-стили там стандартный приём, поэтому исключите каталоги почтовых шаблонов или отключите для них это правило.
Неправильно:
<div style="color: red;">Wrong username or password.</div>
Правильно:
<div class="error">Wrong username or password.</div>
Используйте HTTPS для внешних ссылок.
Обычные http:// подресурсы на странице, отдаваемой по HTTPS, являются смешанным контентом: скрипты, стили и iframe браузеры блокируют сразу, а изображения автоматически апгрейдят или показывают предупреждение. Ссылка <a> на http:// страницу смешанным контентом не является, но всё равно отправляет посетителей по незашифрованному соединению, открытому для перехвата и подмены. Ссылки на внутренние хосты, у которых действительно нет TLS, тоже будут помечены: глушите такие места блоком {# djlint:off H022 #}, а не отключайте правило целиком.
Неправильно:
<a href="http://example.com">Example</a>
Правильно:
<a href="https://example.com">Example</a>
Не используйте ссылки на сущности.
Документы HTML5 используют UTF-8, поэтому литеральный символ работает везде, и именно его реально читают ревьюеры; опечатка в ссылке на сущность (например, &mdsah;) браузером не ловится и выводится как есть, битым текстом. djLint разрешает только сущности, несущие синтаксический смысл или невидимые на экране, такие как <, >, &, ", и ­.
Неправильно:
<p>Dates 1900 — 2000</p>
Правильно:
<p>Dates 1900 — 2000</p>
Опускайте тип в скриптах и стилях.
text/javascript и text/css являются значениями по умолчанию в HTML5 для <script> и <style>, так что этот атрибут представляет собой мёртвый груз, который браузер игнорирует; спецификация WHATWG прямо предписывает его опускать. Отказ от него также избавляет от устаревших MIME-строк, ломающих элемент при копировании на модульные скрипты (где type=“module” действительно важен).
Неправильно:
<script type="text/javascript" src="app.js">
Правильно:
<script src="app.js"></script>
Тег кажется бесхозным.
Тег без парного открывающего или закрывающего тега заставляет механизм восстановления после ошибок в браузере угадывать, где кончается элемент, и последующая разметка проглатывается не тем элементом: вёрстка, CSS-селекторы и DOM-запросы JavaScript ломаются молча и по-разному в разных браузерах. H025 также сообщает об <ol> или <ul>, открытом внутри <p>: HTML-парсер закрывает абзац перед списком, поэтому разметка никогда не вкладывается так, как написана.
Неправильно:
<div>
<p>Hello</p>
Правильно:
<div>
<p>Hello</p>
</div>
Пустые теги id и class могут быть удалены.
Пустой атрибут id или class ничего не делает (на него не могут нацелиться ни стили, ни скрипты), а пустой id ещё и невалидный HTML (значение id не может быть пустой строкой). Обычно это признак ошибки в шаблоне, где предполагалась подстановка переменной, поэтому удаление или заполнение атрибута не даёт этой ошибке прятаться на виду.
Неправильно:
<div id="" class="">content</div>
Правильно:
<div>content</div>
В синтаксисе шаблона найдена незакрытая строка.
Кавычка, открытая, но не закрытая внутри {% ... %} или {{ ... }}, заставляет шаблонизатор неверно разобрать тег: Django и Jinja либо выбрасывают TemplateSyntaxError при рендеринге, либо молча поглощают остаток аргументов тега как строковое содержимое: страница отвечает ошибкой 500 или рендерится с пропавшими аргументами.
Неправильно:
{% trans "Welcome %}
Правильно:
{% trans "Welcome" %}
Рассмотрите возможность использования тегов без пробелов внутри значений атрибутов. {%- if/for -%}
Теги шаблона внутри значения атрибута выводят в итоговый атрибут окружающие их пробелы и переводы строк, поэтому href или src, собранный обычными тегами {% if %}/{% for %}, может содержать лишние пробелы и давать битые URL. Теги управления пробелами Jinja/Nunjucks ({%- ... -%}) убирают эти окружающие пробелы, и атрибут рендерится одним чистым значением. Атрибут class исключён: лишние пробелы между именами классов безвредны.
Не применяется к профилю django: теги шаблонов Django не поддерживают управление пробелами {%- -%}.
Неправильно:
<a href="{% if x %}/home{% endif %}"></a>
Правильно:
<a href="{%- if x -%}/home{%- endif -%}"></a>
Рассмотрите возможность использования строчных значений метода формы.
Спецификация HTML определяет ключевые слова метода формы в нижнем регистре (get, post); варианты в верхнем регистре браузеры принимают лишь за счёт регистронезависимого сопоставления. Каноническая запись в нижнем регистре делает шаблоны единообразными и удобными для grep и избавляет от претензий строгих валидаторов и XHTML-инструментов.
Неправильно:
<form method="POST"></form>
Правильно:
<form method="post"></form>
Рассмотрите возможность добавления мета-описания.
Поисковые системы используют meta description как сниппет под заголовком страницы в выдаче; без него они синтезируют сниппет из произвольного текста страницы, что снижает кликабельность и даёт плохие превью ссылок, когда страницей делятся.
Срабатывает только на файлах с полным документом <html>…</html>. Аргумент про сниппет относится к публично индексируемым страницам; для приложений за авторизацией или интранета это правило часто отключают.
Неправильно:
<html lang="en">
<head><title>Home</title></head>
<body>Welcome</body>
</html>
Правильно:
<html lang="en">
<head>
<title>Home</title>
<meta name="description" content="A short summary of this page.">
</head>
<body>Welcome</body>
</html>
Рассмотрите возможность добавления мета-ключевых слов.
Отключено по умолчанию; включается флагом --include=H031.
Метаданные с ключевыми словами до сих пор используются некоторыми инструментами поиска по сайту, интранет-индексаторами и старыми краулерами, поэтому страница без <meta name="keywords"> может быть для них невидимой. Крупные публичные поисковики, впрочем, его игнорируют, поэтому команды, не зависящие от таких инструментов, часто отключают это правило.
Срабатывает только на файлах с полным документом <html>...</html>.
Неправильно:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Home</title>
<meta name="description" content="A short summary.">
</head>
</html>
Правильно:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Home</title>
<meta name="description" content="A short summary.">
<meta name="keywords" content="django, templates">
</head>
</html>
В тегах шаблона обнаружены лишние пробелы.
Последовательности пробелов или табов между аргументами тега шаблона являются невидимым шумом: они прячут реальные отличия в diff, мешают заметить пропущенный аргумент и расходятся с одиночными пробелами, которые выдаёт форматер djLint, вызывая бессмысленный цикл переформатирований. Пробелы внутри строк в кавычках сохраняются и не помечаются.
Неправильно:
{% static 'css/style.css' %}
Правильно:
{% static 'css/style.css' %}
В действии формы обнаружен лишний пробел.
Начальные и конечные пробелы внутри значения action формы становятся частью итогового URL. Браузеры убирают их при разборе, но небраузерные клиенты и тесты, обращающиеся к литеральному значению, могут этого не делать, а лишний пробел вокруг тега {% url %} почти всегда указывает на опечатку, из-за которой URL отправки формы не проходит сопоставление маршрутов на сервере.
Неправильно:
<form action="{% url 'search' %} " method="get">
<button>Search</button>
</form>
Правильно:
<form action="{% url 'search' %}" method="get">
<button>Search</button>
</form>
Вы намеревались использовать {% ... %} вместо {% ... }%?
}% почти всегда опечатка вместо %}. Шаблонизатор не распознаёт }% как разделитель тега, поэтому тег вообще не разбирается: сырой текст {% … }% утекает в отрендеренный HTML, либо движок выбрасывает синтаксическую ошибку, наткнувшись на незакрытый тег.
Неправильно:
{% include "footer.html" }%
Правильно:
{% include "footer.html" %}
Meta должны быть самозакрывающимися.
В чистом HTML5 завершающий слэш у <meta> необязателен, но шаблоны, которые дополнительно проходят через XML/XHTML-инструменты (XML-валидаторы, почтовые конвейеры, XSLT), не разбираются, если пустые элементы не самозакрыты. Включение этого правила держит теги <meta> в XHTML-совместимой форме <meta ... />, чтобы одна и та же разметка переживала оба парсера.
Отключено по умолчанию; включается флагом --include=H035. Подмножество H017 (которое требует завершающий слэш у всех пустых тегов, включая meta): включайте H035 отдельно, только если XHTML-форма нужна лишь для meta. Взаимоисключимо с H018; не включайте оба.
Неправильно:
<meta name="viewport" content="width=device-width">
Правильно:
<meta name="viewport" content="width=device-width" />
Избегайте использования тегов br.
<br> кодирует оформление в разметке: использование его для отступов или имитации абзацев ломает перенос текста на узких экранах и вредит доступности, так как скринридеры объявляют принудительные разрывы вместо естественной паузы между блоками. Отдельным мыслям место в отдельных блочных элементах, а вертикальным отступам место в CSS-margin. Учтите, что <br> уместен там, где разрыв строки является частью самого содержимого (почтовые адреса, стихи, тексты песен), а правило не умеет отличать такие случаи от презентационных: оно помечает каждый <br>. Оставьте его выключенным, если ваши шаблоны рендерят подобный контент.
Отключено по умолчанию; включается флагом --include=H036.
Неправильно:
<p>Shipping is free.<br>Delivery takes 3 days.</p>
Правильно:
<p>Shipping is free.</p>
<p>Delivery takes 3 days.</p>
Найдено дублирование атрибута.
Дублирующиеся атрибуты являются невалидным HTML: браузеры оставляют только первое вхождение и молча отбрасывают остальные, поэтому второе значение class или style никогда не применяется, что скрывает реальные ошибки. Проверка учитывает шаблоны: атрибут, повторённый во взаимоисключающих ветках ({% if %}/{% else %}), не помечается, поскольку отрендерится только одна копия.
Неправильно:
<div class="card" id="profile" class="active">...</div>
Правильно:
<div class="card active" id="profile">...</div>
Блочный тег не имеет соответствующего закрывающего тега.
Блочный тег вроде {% if %}, {% for %} или {% macro %} без парного закрывающего тега означает гарантированный TemplateSyntaxError в Django и Jinja: страница не рендерится в момент запроса, а это правило ловит проблему до деплоя. Оно также помечает осиротевшие закрывающие теги без открывающего и неправильно переплетённые блоки (например, {% if %}``{% for %}``{% endif %}).
Парность {% block %}/{% endblock %} и несовпадающие имена endblock проверяются этим правилом; T003 (отключено по умолчанию) дополнительно требует имя у каждого многострочного {% endblock %}. Пользовательские блочные теги, зарегистрированные через custom_blocks, тоже проверяются, включая их самозакрывающуюся форму / %}.
Неправильно:
{% if user.is_authenticated %}
<p>Welcome back!</p>
Правильно:
{% if user.is_authenticated %}
<p>Welcome back!</p>
{% endif %}
Найден незакрытый тег шаблона.
Тег шаблона, открытый {{ или {%, но не закрытый парным }} или %}, не разбирается как тег: Django/Jinja либо выбрасывают TemplateSyntaxError, либо выводят сырые фигурные скобки на страницу, а всё до следующего разделителя может быть молча поглощено. Такие опечатки (одна пропущенная скобка, несовпадающий разделитель) легко пропустить на ревью, потому что шаблон может частично рендериться.
Неправильно:
<p>{{ user.name }</p>
Правильно:
<p>{{ user.name }}</p>
Отсутствующее или пустое имя шаблона в теге extends или include.
Тег {% extends %} или {% include %} с отсутствующим, пустым или состоящим из одних пробелов именем шаблона не может ничего загрузить: Django выбрасывает TemplateSyntaxError, когда имя отсутствует совсем, и TemplateDoesNotExist при рендеринге, когда оно пустое; страница отвечает 500 в продакшене, хотя сам файл шаблона выглядит синтаксически правдоподобно.
Неправильно:
{% extends "" %}
Правильно:
{% extends "base.html" %}
Тег закрывается в другом блоке шаблона, чем тот, в котором он был открыт.
Когда HTML-тег открыт в одном {% block %}, а закрыт в другом, дочерний шаблон, переопределяющий только один из этих блоков, наследует половину элемента, и в отрендеренной странице появляется несбалансированная разметка: браузеры непредсказуемо автозакрывают или перевкладывают элементы, ломая вёрстку и CSS-селекторы далеко от фактически отредактированного шаблона. Если каждый элемент открывается и закрывается в одном и том же блоке, любой блок можно безопасно переопределять независимо.
Неправильно:
{% block content %}
<div class="wrapper">
{% endblock content %}
{% block footer %}
</div>
{% endblock footer %}
Правильно:
{% block content %}
<div class="wrapper">
</div>
{% endblock content %}
{% block footer %}
{% endblock footer %}
Атрибут for у label не имеет соответствующего id в этом файле.
Отключено по умолчанию; включается флагом --include=H042.
Проверка выполняется только для файлов, которые можно анализировать надёжно: если файл содержит что-либо, способное отрендерить id, которого в этом файле не видно (вывод {{ ... }} вроде виджета формы, {% include %} или {% extends %}, либо неизвестный тег шаблона), правило молчит для этого файла. Там, где оно работает, каждое срабатывание означает действительно сломанную связь.
Неправильно:
<label for="email">Email</label>
<input id="username">
Правильно:
<label for="email">Email</label>
<input id="email">
Мы приветствуем запросы с новыми правилами!
Хорошее правило состоит из
Пожалуйста, включите тест для проверки правила.
Создайте файл .djlint_rules.yaml рядом с вашим pyproject.toml. Правила могут быть добавлены в этот файл, и djLint подхватит их.
Файл правил в другом месте можно указать с помощью CLI-опции --rules.
Хорошее правило выглядит следующим образом:
- rule:
name: T001
message: Найти трихотилломанию
flags: re.DOTALL|re.I
patterns:
- трихотилломанию