Олег Марков
Тег параграфа p в HTML
Введение
Тег параграфа p — один из самых базовых и часто используемых элементов HTML. Он отвечает за разметку обычного текстового абзаца: отдельной смысловой мысли, блока текста, который логически завершен.
Кажется, что тут все очевидно: обернули текст в p — и готово. Но на практике вокруг этого тега возникает много вопросов. Например:
- как браузер обрабатывает несколько переносов строк внутри параграфа;
- чем p отличается от div при выводе текста;
- можно ли вкладывать один p в другой;
- как правильно делать отступы между абзацами;
- что будет, если не закрыть p.
Смотрите, я покажу вам, как тег p работает на уровне разметки, рендеринга и стилизации, а также разберем типичные ошибки и хорошие практики.
Основы тега p
Назначение и семантика
Тег p (paragraph) — блочный элемент, который обозначает параграф текста, то есть законченную мысль или часть текста, отделенную от других частей.
Главная идея: вы используете p, когда хотите сказать браузеру и другим системам (поисковикам, скринридерам) — "здесь абзац текста". Это важно:
- для визуального отображения (браузер сам добавляет отступы между параграфами);
- для доступности (скринридеры читают текст абзацами);
- для SEO (поисковые системы лучше понимают структуру текста).
Простейший пример:
<p>Это первый абзац текста на странице.</p>
<p>А это второй абзац, который отображается отдельно.</p>// Каждый p — отдельный параграф текста // Между ними браузер по умолчанию делает вертикальный отступ
Блочный характер тега p
Тег p — блочный элемент. Это значит, что:
- он всегда начинается с новой строки;
- по ширине по умолчанию занимает всю доступную ширину контейнера;
- следующий элемент также начнется с новой строки.
Давайте разберемся на примере:
<p>Первый абзац. Он занимает всю ширину контейнера.</p>
<p>Второй абзац. Он будет ниже первого, с отступом между ними.</p>
<span>Просто текст в span.</span>
<span>Еще текст в span.</span>// p — блочные элементы, они идут друг под другом // span — строчные элементы, идут подряд в одной строке (если помещаются)
Если вы попытаетесь расположить несколько абзацев в одну строку, обычного HTML для этого недостаточно — потребуется CSS (например, сделать p строчными или использовать flex-контейнер).
Обязательность закрывающего тега
С точки зрения HTML-спецификации, закрывающий тег p может быть опущен, браузер часто "додумывает" его самостоятельно. Но в реальной разработке лучше всегда явно закрывать p.
Плохой пример (браузер, скорее всего, подправит, но это неочевидно):
<p>Первый абзац
<p>Второй абзац// Браузер автоматически закроет первый абзац перед началом второго // Но такая запись делает код менее понятным и может привести к неожиданностям
Правильный пример:
<p>Первый абзац.</p>
<p>Второй абзац.</p>// Каждый абзац явно открыт и закрыт — код предсказуемый и понятный
Рекомендация: всегда закрывайте p вручную, даже если браузер "и так поймет".
Структура и разрешенное содержимое
Что можно помещать внутрь p
По стандарту HTML внутри тега p должны находиться фразовые (строчные) элементы и текст. То есть внутри можно:
- обычный текст;
- ссылки a;
- выделение текста strong, em, mark;
- span;
- inline-элементы вроде img (при необходимости);
- и другие "инлайновые" элементы.
Пример:
<p>
Это текст абзаца, в котором есть
<strong>важное слово</strong> и
<a href="/about">ссылка на другую страницу</a>.
</p>// strong — выделяет слово, но не ломает структуру абзаца // a — делает часть текста ссылкой
Еще пример с картинкой внутри параграфа:
<p>
<img src="avatar.jpg" alt="Аватар пользователя">
Это подпись к изображению, которая идет в одном абзаце.
</p>// img — строчный по типу, поэтому может находиться внутри p // alt — важен для доступности
Что нельзя помещать внутрь p
Внутри p нельзя размещать блочные элементы. Например:
- div;
- section, article;
- h1–h6 (заголовки);
- ul, ol (списки);
- table (таблица);
- другой p (вложенные параграфы недопустимы по стандарту).
Плохой пример:
<p>
Текст абзаца.
<div>Блочный элемент внутри параграфа.</div>
</p>// Такое вложение нарушает спецификацию HTML // Браузер попытается "починить" разметку, сам закроет p до div
Как это реально интерпретирует браузер:
<p>Текст абзаца.</p>
<div>Блочный элемент внутри параграфа.</div>// p будет автоматически закрыт до открытия div // В итоге структура страницы окажется не той, что вы ожидали
Точно так же нельзя вкладывать p внутрь p:
<p>
Первый абзац.
<p>Вложенный абзац (так делать не нужно).</p>
</p>// Браузер закроет первый p перед вторым // В результате вложенности не получится, будут два независимых абзаца
Рекомендация: если вам нужно логически сгруппировать несколько абзацев, оберните их в div, section или article, но не вкладывайте параграфы друг в друга.
Автоматическое закрытие p браузером
Теперь давайте посмотрим, как браузер ведет себя, если вы нарушаете правила и не закрываете p явно.
Пример:
<p>Первый абзац
<div>Какой-то блок</div>
<p>Второй абзац// Здесь явно закрывающий тег p отсутствует // Но браузер сам закрывает p перед div и в конце документа
Фактически браузер сформирует примерно такую структуру:
<p>Первый абзац</p>
<div>Какой-то блок</div>
<p>Второй абзац</p>// Это поведение иногда спасает разметку // Но полагаться на него не стоит — ошибки будет сложнее отлавливать
Отображение и стилизация параграфов
Отступы между абзацами: margin
По умолчанию браузеры добавляют внешний отступ margin сверху и снизу элементов p. Обычно это что-то вроде:
p {
margin-top: 1em;
margin-bottom: 1em;
}// em — единица, зависящая от размера шрифта // Отступы между абзацами примерно равны высоте строки
Если вы хотите контролировать расстояние между абзацами, лучше явно переопределить стили:
p {
margin: 0 0 1rem 0; /* верх 0, справа 0, низ 1rem, слева 0 */
}// Убираем верхний отступ, оставляем только нижний // Так абзацы не будут "наползать" на заголовки сверху
И пример HTML:
<p>Это первый абзац.</p>
<p>Это второй абзац. Он отстоит от первого на 1rem вниз.</p>// Отступ между двумя абзацами — это margin-bottom первого p
Внутренние отступы: padding
Иногда нужно сделать абзац визуально "воздушным", добавив отступы внутри блока. Для этого используем padding:
p.notice {
padding: 12px; /* внутренние отступы со всех сторон */
background-color: #f5f5f5;
border-left: 4px solid #999;
}<p class="notice">
Это абзац-уведомление с фоном и отступами.
</p>// padding добавляет пространство между текстом и границами блока // margin — отвечает за расстояние до других элементов вокруг
Межстрочный интервал: line-height
Для длинных абзацев важно обеспечить удобочитаемость. Часто line-height делают 1.4–1.6 для основного текста.
p {
font-size: 16px;
line-height: 1.5; /* высота строки = 1.5 * размер шрифта */
}<p>
Здесь я размещаю пример длинного абзаца, чтобы вы увидели,
как межстрочный интервал влияет на читаемость текста.
С увеличенным line-height текст воспринимается легче.
</p>// line-height влияет на вертикальное расстояние между строками внутри одного абзаца
Выравнивание текста: text-align
Абзацы по умолчанию выравниваются по левому краю (в левосторонних языках). Вы можете изменить выравнивание с помощью свойства text-align:
p.center {
text-align: center; /* по центру */
}
p.right {
text-align: right; /* по правому краю */
}
p.justify {
text-align: justify; /* по ширине, с растяжением строк */
}<p class="center">Этот абзац выровнен по центру.</p>
<p class="right">Этот абзац прижат к правому краю.</p>
<p class="justify">
Этот текст выравнивается по ширине. Браузер увеличивает интервалы
между словами так, чтобы каждая строка занимала всю ширину блока.
</p>// text-align влияет только на выравнивание текста внутри блока, но не на сам блок
Цвет, шрифт и другие стили
Тег p сам по себе отвечает только за структуру. Все визуальные характеристики задаются через CSS:
p {
color: #333; /* цвет текста */
font-family: system-ui, sans-serif;
font-size: 16px;
}
p.small {
font-size: 14px;
color: #666;
}
p.highlight {
font-weight: bold;
color: #b00020;
}<p>Обычный абзац с базовыми стилями.</p>
<p class="small">Немного более мелкий и светлый текст.</p>
<p class="highlight">Выделенный важный абзац.</p>// Классы позволяют применять разные стили к разным параграфам
Переносы строк и пробелы внутри p
Как браузер обрабатывает пробелы
По умолчанию браузер:
- сжимает несколько подряд идущих пробелов до одного;
- игнорирует переводы строк в коде (Enter) и табуляции;
- переносит текст по словам (с учетом пробелов и дефисов).
Давайте посмотрим, что это означает на практике:
<p>
Здесь я размещаю текст
с большим количеством пробелов
и переносов
строки.
</p>// В коде много пробелов и переносов // В браузере вы увидите обычный текст, где слова разделены одним пробелом
Результат в браузере будет примерно таким:
Здесь я размещаю текст с большим количеством пробелов и переносов строки.
То есть разметка внутри p не влияет на отображение пробелов и переносов, пока не подключены специальные стили.
Принудительный перенос строки: тег br
Если вам нужно явно перейти на новую строку внутри одного параграфа (но не начинать новый абзац), используйте тег br.
Пример:
<p>
Контактная информация:<br>
Телефон +7 000 000 00 00<br>
Email info@example.com
</p>// br добавляет разрыв строки внутри того же параграфа // Это не новый абзац, а просто перенос строки
Еще один пример:
<p>
Здесь первая строка.<br>
Здесь вторая строка, но это всё один абзац.
</p>// Если вам важна именно логическая отдельность блоков текста — лучше использовать несколько p // br хорошо подходит для адресов, стихов, коротких форм
Сохранение пробелов: white-space
Иногда нужно, чтобы браузер не сжимал пробелы и не игнорировал переводы строк. Для этого используется CSS-свойство white-space.
Пример:
p.preserve {
white-space: pre-line;
}<p class="preserve">
Здесь я пишу текст
на нескольких строках,
и хочу, чтобы переносы
сохранились.
</p>// pre-line сохраняет переносы строк, но всё равно сжимает несколько пробелов до одного
Если нужно сохранить и пробелы, и переводы строк, можно использовать white-space: pre или pre-wrap:
p.code-like {
white-space: pre-wrap; /* сохраняет и пробелы, и переносы */
font-family: monospace;
}<p class="code-like">
Строка 1 с пробелами
Строка 2 тоже с пробелами
</p>// pre-wrap удобно использовать, когда нужно показать текст "как есть" (например, фрагмент лога)
Тег p и другие текстовые элементы
Отличие p от div
div — универсальный блочный контейнер без семантики. p — семантический элемент именно для текстовых абзацев.
Сравнение:
<div>Текст, обернутый в div.</div>
<p>Текст, обернутый в p.</p>// Визуально по умолчанию они похожи: оба — блочные элементы // Семантически p говорит "это абзац", div — просто "контейнер"
Когда использовать p:
- для обычных текстовых абзацев, предложений, объяснений;
- для содержимого статей, новостей, описаний, документации.
Когда использовать div:
- для группировки нескольких элементов (включая параграфы);
- для создания блоков интерфейса (карточки, панели, формы), где нет конкретного текстового семантического значения.
Хороший пример комбинирования:
<article>
<h2>О компании</h2>
<div class="intro">
<p>Наша компания занимается разработкой веб-приложений.</p>
<p>Мы уделяем внимание качеству кода и удобству интерфейсов.</p>
</div>
</article>// article — большая смысловая единица // div.intro — группа абзацев // p — отдельные логические абзацы внутри группы
p и заголовки h1–h6
Заголовки h1–h6 используются для обозначения структуры и уровней разделов, а p — для содержимого внутри этих разделов.
Пример правильной структуры:
<h1>Документация продукта</h1>
<p>Краткое вступление по продукту.</p>
<h2>Установка</h2>
<p>Перед установкой убедитесь, что у вас есть доступ к системе.</p>
<h2>Настройка</h2>
<p>После установки перейдите к настройке окружения.</p>// Заголовки формируют иерархию документа // p содержит основной текст, объяснения, описания
Не стоит использовать p вместо заголовков только ради визуального эффекта. Структура документа должна отражаться в разметке, а не только в стиле.
p и списки (ul, ol)
Списки ul и ol сами по себе являются блочными элементами. Обычно:
- абзац вводит список;
- сам список оформляется с помощью li внутри ul или ol;
- внутри li также можно использовать p, если текст объемный.
Пример:
<p>Перед началом работы выполните следующие шаги:</p>
<ol>
<li>Установите необходимые зависимости.</li>
<li>Настройте переменные окружения.</li>
<li>Запустите приложение в тестовом режиме.</li>
</ol>// p — вводный текст // ol — нумерованный список шагов
Если элементы списка содержат длинные описания, их можно оформить как параграфы:
<ul>
<li>
<p>Первое преимущество — простота интеграции.</p>
<p>Вы можете подключить компонент всего в несколько строк кода.</p>
</li>
<li>
<p>Второе преимущество — гибкая настройка.</p>
</li>
</ul>// Каждый li может содержать несколько абзацев p // Это помогает структурировать большие описания внутри одного пункта
Практические рекомендации по использованию p
Делите текст на логические абзацы
Абзац — это не просто "кусок текста до первого пустого места", а законченная мысль. Старайтесь:
- не делать абзацы слишком длинными;
- разделять разные идеи на отдельные p;
- не злоупотреблять br там, где логичнее использовать новый абзац.
Пример неудачной разметки:
<p>
Наша компания занимается разработкой программного обеспечения. Мы работаем на рынке более 10 лет. Наши клиенты — крупные и средние компании. Мы предлагаем комплексные решения "под ключ" и поддерживаем проекты после запуска.
</p>// Один очень длинный абзац, сложно читать
Более удобочитаемый вариант:
<p>
Наша компания занимается разработкой программного обеспечения и работает на рынке более 10 лет.
</p>
<p>
Наши клиенты — крупные и средние компании. Мы предлагаем комплексные решения "под ключ" и поддерживаем проекты после запуска.
</p>// Две завершенные мысли — два абзаца
Не используйте p для обертки всего контента
Иногда начинающие разработчики оборачивают в p целые большие блоки, включая заголовки, списки и другие элементы. Это нарушает семантику и приводит к ошибкам.
Плохой пример:
<p>
<h2>О продукте</h2>
Наш продукт решает следующие задачи:
<ul>
<li>автоматизация процессов</li>
<li>сокращение времени обработки заказов</li>
</ul>
</p>// Внутри p — заголовок и список, что некорректно // p будет автоматически закрыт до h2, структура сломается
Правильный вариант:
<h2>О продукте</h2>
<p>Наш продукт решает следующие задачи:</p>
<ul>
<li>автоматизация процессов;</li>
<li>сокращение времени обработки заказов.</li>
</ul>// Каждый тип содержимого размечен своим семантическим элементом // p используется только для абзаца текста
Классы и идентификаторы на p
На p можно вешать классы и id для стилизации и скриптов:
<p id="intro" class="lead">
Это вводный абзац, который визуально отличается от остальных.
</p>p.lead {
font-size: 18px;
line-height: 1.7;
color: #222;
}// class — для общих стилей // id — для уникальной идентификации (например, якорь для ссылки)
Пример использования id как якоря:
<p id="terms">
Нажимая кнопку "Зарегистрироваться", вы соглашаетесь с условиями сервиса.
</p>
<a href="#terms">Перейти к условиям</a>// Ссылка переведет пользователя к указанному абзацу
Обработка p в JavaScript
Иногда нужно работать с абзацами через JavaScript: менять текст, добавлять классы, реагировать на события.
Пример:
<p id="message">Исходный текст сообщения.</p>
<button id="change">Изменить текст</button>
<script>
// Находим элементы по id
const message = document.getElementById('message');
const button = document.getElementById('change');
// Вешаем обработчик клика на кнопку
button.addEventListener('click', function () {
// Меняем содержимое абзаца
message.textContent = 'Текст был обновлен при клике на кнопку.';
});
</script>// Здесь JavaScript взаимодействует с p как с обычным DOM-элементом // textContent безопасно заменяет текст внутри абзаца
Еще пример, когда вы хотите выделить определенные абзацы:
<p>Обычный текст.</p>
<p class="important">Важный текст.</p>
<p>Снова обычный.</p>
<script>
// Находим все абзацы с классом important
const importantParagraphs = document.querySelectorAll('p.important');
// Добавляем им инлайн-стиль подсветки
importantParagraphs.forEach(function (p) {
// Здесь мы визуально выделяем абзац
p.style.backgroundColor = '#fff8e1';
});
</script>// querySelectorAll позволяет выбирать p по селекторам // Вы можете динамически изменять стили и классы
Распространенные ошибки и как их избежать
Ошибка 1. Вложенные параграфы
Как уже обсуждали, p не может содержать внутри себя другой p.
Плохой код:
<p>
Внешний абзац.
<p>Внутренний абзац.</p>
</p>// Браузер закроет внешний p до начала внутреннего // В результате структура окажется совсем не той, что в коде
Как исправить:
<p>Внешний абзац.</p>
<p>Внутренний абзац (на самом деле просто следующий).</p>// Просто используйте несколько независимых параграфов
Ошибка 2. Блочные элементы внутри p
Часто встречается ситуация, когда внутрь p попадают div или списки. Это также нарушает спецификацию.
Плохой код:
<p>
Текст абзаца.
<ul>
<li>Пункт 1</li>
<li>Пункт 2</li>
</ul>
</p>// ul — блочный элемент, не должен находиться внутри p // Браузер автоматом закроет p перед ul
Правильный подход:
<p>Текст перед списком.</p>
<ul>
<li>Пункт 1</li>
<li>Пункт 2</li>
</ul>// Абзац и список — равноправные блочные элементы // Они находятся на одном уровне вложенности
Ошибка 3. Использование p только ради отступов
Иногда вместо того, чтобы задать отступы через CSS, разработчики добавляют "пустые" параграфы, чтобы создать пространство.
Плохой пример:
<p>Первый абзац.</p>
<p></p> <!-- Пустой абзац для отступа -->
<p>Второй абзац.</p>// Такой пустой p не несет семантики и засоряет разметку // Для отступов нужно использовать стили
Правильный вариант:
<p>Первый абзац.</p>
<p>Второй абзац.</p>p {
margin-bottom: 16px; /* контролируем отступы через CSS */
}// Так вы отделяете структуру документа от его внешнего вида
Ошибка 4. Отсутствие логики в разбиении на абзацы
Иногда весь текст страницы заключают в один p, либо наоборот — разрывают предложения без необходимости.
Плохой пример (один огромный параграф):
<p>
Длинное описание товара, включающее несколько абзацев по смыслу,
но оформленное как один блок. Такой текст сложно читать и трудно
адаптировать под разные устройства. Логические границы абзацев не
обозначены, хотя по смыслу они здесь есть.
</p>Лучше:
<p>
Длинное описание товара, включающее несколько абзацев по смыслу, не стоит
оформлять как один блок.
</p>
<p>
Такой текст сложнее читать и труднее адаптировать под разные устройства.
Логические границы абзацев стоит обозначать явно.
</p>// Разделяйте текст по смыслу, а не только по длине
Ошибка 5. Избыточное использование br вместо p
br — это инструмент для переноса строки, а не для разделения логических блоков текста.
Плохой пример:
<p>
О компании<br><br>
Мы работаем с 2010 года.<br><br>
Мы ценим качество и надежность.
</p>// Здесь br используется как "эмуляция" абзацев // Логичнее использовать несколько p
Правильный вариант:
<h2>О компании</h2>
<p>Мы работаем с 2010 года.</p>
<p>Мы ценим качество и надежность.</p>// Заголовок отделяет раздел, абзацы содержат основной текст
br оставляйте для тех случаев, когда важна именно визуальная форма строки, а не логический абзац: адреса, стихи, контактные данные.
Заключение
Тег p — это базовый, но очень важный элемент HTML-разметки. Он отвечает не только за визуальные абзацы текста, но и за семантику документа: помогает браузерам, скринридерам и поисковым системам понимать структуру содержимого.
Ключевые моменты, на которые стоит опираться:
- p обозначает логически завершенный абзац текста;
- внутри p размещаются текст и строчные (inline) элементы, а не блочные;
- параграфы нужно закрывать явно;
- отступы и внешний вид абзацев контролируются через CSS, а не через "пустые" p или наборы br;
- корректное использование p улучшает читаемость, доступность и поддержку кода.
Если вы будете осознанно использовать тег p и разделять обязанности между HTML (структура и смысл) и CSS (внешний вид и отступы), работа с текстом в вебе станет предсказуемой и аккуратной.
Частозадаваемые технические вопросы по теме
Можно ли сделать несколько колонок абзацев с помощью p без таблиц?
Да, лучше использовать CSS-многоколоночную верстку или flex/grid. Пример с колонками:
<div class="columns">
<p>Первый абзац.</p>
<p>Второй абзац.</p>
<p>Третий абзац.</p>
</div>.columns {
column-count: 2; /* количество колонок */
column-gap: 24px; /* расстояние между колонками */
}// Браузер сам разобьет содержимое контейнера на колонки
Как убрать отступы только у первого или последнего абзаца в блоке?
Используйте псевдоклассы first-child и last-child:
.container p {
margin: 0 0 16px;
}
.container p:last-child {
margin-bottom: 0; /* убираем отступ у последнего */
}
.container p:first-child {
margin-top: 0; /* при необходимости убираем верхний отступ у первого */
}// Так вы контролируете отступы в рамках конкретного контейнера
Как обрезать длинный текст в p и добавить многоточие?
Используйте сочетание свойств CSS:
p.truncate {
white-space: nowrap; /* в одну строку */
overflow: hidden; /* скрываем лишнее */
text-overflow: ellipsis; /* добавляем многоточие */
}<p class="truncate">
Очень длинный текст, который не помещается в одну строку...
</p>// Для многострочного обрезания понадобится webkit-line-clamp и flexbox/box-ориентированные техники
Почему стиль для p не применяется в некоторых местах?
Часто проблема в специфичности селекторов или переопределении стилей. Мини-инструкция:
- Откройте инструменты разработчика в браузере.
- Выберите нужный p в инспекторе.
- Посмотрите, какие CSS-правила применяются и какие перечернуты.
- Увеличьте специфичность селектора (например, .content p вместо просто p) или измените порядок подключения таблиц стилей.
Как сделать, чтобы по клику на кнопку добавлялся новый абзац в конец блока?
Используйте JavaScript для создания и добавления элемента:
<div id="text-block">
<p>Исходный абзац.</p>
</div>
<button id="add">Добавить абзац</button>
<script>
// Находим контейнер и кнопку
const block = document.getElementById('text-block');
const button = document.getElementById('add');
button.addEventListener('click', function () {
const p = document.createElement('p'); // создаем новый p
p.textContent = 'Новый абзац текста.'; // задаем текст
block.appendChild(p); // добавляем в конец блока
});
</script>// Так вы динамически расширяете содержимое, сохраняя правильную структуру p внутри контейнера
Постройте личный план изучения Html до уровня Middle — бесплатно!
Html — часть карты развития Frontend
100+ шагов развития
30 бесплатных лекций
300 бонусных рублей на счет
Все гайды по Html
Лучшие курсы по теме

HTML и CSS
Антон Ларичев
TypeScript с нуля
Антон Ларичев