Ограничение количества строк текста в элементе с помощью CSS
Используйте CSS, чтобы сокращать текст до фиксированного числа строк и добавлять кнопку «Развернуть/Свернуть» без JavaScript. В статье показаны два подхода: WebKit-специфичный метод с -webkit-line-clamp и более гибкий метод с вычислением высоты и градиентом. Плюс — советы по доступности, совместимости и набор тестов.

Ограничение количества текста в блоке — частая задача веб-дизайна. Обычно вы видите превью-отрывок из трёх-четырёх строк с кнопкой «Развернуть», которая показывает полный текст. Это можно сделать с помощью CSS + JavaScript, но и чистым CSS — двумя основными способами. В этой статье вы найдёте: пошаговые примеры, рабочие фрагменты кода, рекомендации по доступности и совместимости, тесты и чек-листы.
Важно: в примерах используется имя класса .cuttoff-text (с двумя буквами t). Это именно то имя, которое встречается в исходных фрагментах кода — вы можете заменить его на своё, но тогда не забудьте править CSS и HTML одновременно.
Определения
- line-clamp — CSS-приём, позволяющий «обрезать» текст по числу строк; в современной практике часто реализуется через -webkit-line-clamp.
- has() — селектор, позволяющий в CSS применять правила к элементам, которые имеют указанного потомка или соседний элемент в определённом состоянии.
Техника WebKit
Создайте пустую папку и два файла: index.html и style.css.
В index.html добавьте базовый HTML-шаблон:
Document
Внутри
вставьте разметку карточек (семантичная структура: section → article):
Article 1
300-word text goes here
Article 2
200-word text goes here
Article 1
100-word text goes here
Структура проста: секция содержит три статьи, каждая статья — заголовок, абзац и input, который будет стилизован под кнопку.
Пример визуала на этапе верстки:

Добавьте базовые стили в style.css — сброс боксовой модели, фон и поведение контейнера:
*, *::before, *::after {
box-sizing: border-box;
}
body {
background: #f3f3f3;
overflow: hidden;
}Сделайте grid-контейнер для карточек и стилизуйте сами карточки:
.card-group {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: .5rem;
align-items: flex-start;
}
.card {
background: white;
padding: 1rem;
border: 1px solid black;
border-radius: .25em;
}
h2, p {
margin: 0;
}
h2 {
margin-bottom: 1rem;
}Страница будет выглядеть так:

Чтобы ограничить текст тремя строками, используйте следующую запись:
.cuttoff-text {
--max-lines: 3;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: var(--max-lines);
}
Пояснение: задаём CSS-переменную –max-lines, скрываем переполнение и указываем display: -webkit-box вместе с -webkit-line-clamp для ограничения по числу строк.
Результат: на третьей строке появляется многоточие (ellipsis):

Ограничения этого метода:
- Требует display: -webkit-box — нельзя свободно использовать Flex или Grid на самом элементе с обрезкой.
- Менее переносим в сложные макеты. Технически работает в браузерах с WebKit/Blink, но поведение может отличаться.
Более гибкий подход
Этот метод даёт такую же конечную картинку, но вы сами контролируете высоту контейнера — это даёт гибкость: любой display, любая сетка и эффект градиента для плавного «затухания» текста.
Замените CSS блока .cuttoff-text на:
.cuttoff-text {
--max-lines: 5;
--line-height: 1.4;
height: calc(var(--max-lines) * 1em * var(--line-height));
line-height: var(--line-height);
position: relative;
}И пояснение: важна установка line-height, потому что итоговая высота — это умножение количества строк на размер строки (line-height × font-size). position: relative нужно для добавления псевдоэлемента с градиентом.
Добавьте градиентный псевдоэлемент, чтобы плавно скрывать последние строки:
.cuttoff-text::before {
content: "";
position: absolute;
height: calc(2em * var(--line-height));
width: 100%;
bottom: 0;
pointer-events: none;
background: linear-gradient(to bottom, transparent, white);
}Псевдоэлемент накладывает сверху градиент, создающий эффект «затухания» последней строки. pointer-events: none гарантирует, что накладываемая область не перехватит клики или выделение.
Результат с плавным градиентом:

Плюсы этого подхода:
- Можно использовать любые layout-системы (Grid, Flexbox) для родителя и соседей.
- Точный контроль над числом видимых строк через переменные.
- Удобнее адаптировать под разные точки останова (media queries).
Динамическая кнопка «Развернуть/Свернуть» без JavaScript
Мы уже вставили в HTML. Стилизуем input как кнопку:
.expand-btn {
appearance: none;
border: 1px solid black;
padding: .5em;
border-radius: .25em;
cursor: pointer;
margin-top: 1rem;
}
.expand-btn:hover {
background-color: #ccc;
}
.expand-btn::before {
content: "Expand"
}
.expand-btn:checked::before {
content: "Collapse"
}При клике текст у кнопки меняется с Expand на Collapse, но сам текст пока не разворачивается. Для связки состояния чекбокса и блока с текстом используем селектор has():
.cuttoff-text:has(+ .expand-btn:checked) {
height: auto;
}Эта запись говорит: если у элемента .cuttoff-text есть соседний (смежный) элемент .expand-btn в состоянии checked, — снимай ограничение по высоте (height: auto) и показывай весь текст.
Результат: одна карточка разворачивается, две другие остаются свернутыми.

Совет по доступности: используйте вместо незагруженного input чекбокса корректные aria-атрибуты и подписи. Пример доступного HTML:
- Добавьте aria-controls на кнопку, указывающий на id блока с текстом.
- Добавьте aria-expanded, синхронизируемый с состоянием input (при чистом CSS это сложнее; можно использовать скрытые тексты для скринаутеров).
Когда методы не подходят
- Динамически изменяемый контент (например, шрифты загружаются асинхронно) может изменить высоту строк и «сломать» расчёт высоты. Решение: применять font-display: swap и/или пересчитывать высоту на JS при загрузке шрифтов.
- Если нужно, чтобы обрезка была выполнена посимвольно (character-based) или по словам — нужны дополнительные приёмы и/или JS.
- Для старых браузеров без поддержки -webkit-line-clamp и :has() придётся использовать JavaScript-решение.
Альтернативные подходы
- Полностью на JS: измерять scrollHeight и ставить max-height + transition, а при раскрытии — удалять ограничение. Даёт лучшее кросс-браузерное поведение и контроль анимаций.
- С использованием mask-image вместо псевдоэлемента — полезно, если нужен более сложный графический эффект.
- Серверная генерация превью: отдавать сокращённый текст с сервера и полный — по запросу. Подходит для SEO и экономии трафика.
Совместимость и практические советы
- -webkit-line-clamp работает в движках WebKit и Blink, но не является стандартизованным свойством; проверяйте поддержку для целевой аудитории.
- :has() уже реализован в современных браузерах, но не во всех версиях — если ваша аудитория использует устаревшие браузеры, подготовьте fallback.
- Всегда тестируйте поведение при масштабировании, при смене шрифта и при переводе контента, где длина строк может значительно отличаться.
Таблица поддержки (обзорная, проверяйте актуальность на caniuse.com):
| Приём | Поддержка в современных браузерах | Замечания |
|---|---|---|
| -webkit-line-clamp | Да (WebKit/Blink) | Используйте в сочетании с display: -webkit-box |
| height calc (переменные) | Общая поддержка | Надёжно для гибких решений |
| :has() | Современные браузеры | Может отсутствовать в старых версиях |
Чек-лист перед выпуском
- Проверить поведение на мобильных точках останова.
- Убедиться, что кнопка доступна клавиатурой (Tab / Enter / Space).
- Проверить выделение/копирование текста в свернутом и развернутом состояниях.
- Тестировать с увеличенным размером шрифта и системным масштабированием.
- Прогон на старых браузерах и включение fallback-логики при необходимости.
Рольные рекомендации:
- Дизайнер: укажите желаемое число строк для карточек в макете и состояние «развернуто». Предложите визуальную индикацию (стрелка/иконка).
- Разработчик: используйте CSS-переменные для управления количеством строк и высотой строки; обеспечьте fallback.
- QA: проверьте взаимодействие с клавиатурой и скринридерами.
Критерии приёмки
- Текст на карточках обрезается до указанного числа строк в поддерживаемых браузерах.
- Кнопка «Развернуть» меняет текст на «Свернуть» и показывает/скрывает весь текст.
- В развернутом виде содержимое полностью доступно для копирования и навигации клавиатурой.
- Паддинги и отступы сохраняются, верстка не ломается при разном объёме текста.
Тестовые сценарии
- Открыть страницу на мобильном разрешении — карточки отображаются корректно, текст обрезается.
- Нажать Tab, фокус на кнопке, нажать Enter — карточка разворачивается.
- Увеличить системный шрифт (accessibility) — проверить, что текст не перекрывается.
- Отключить поддержку :has() (симулировать старый браузер) — убедиться, что есть fallback или стиль не ломается.
Мини-методология внедрения
- Добавьте компонент на локальную страницу как в примере.
- Выберите подход: WebKit-метод для простых случаев или гибкий метод для адаптивных макетов.
- Обновите переменные CSS для проектных значений (–max-lines, –line-height).
- Проведите кросс-браузерное тестирование и отловите места, где нужен JS-fallback.
- Добавьте aria-атрибуты и проведите тестирование со скринридером.
Короткое резюме
Ограничение количества строк текста можно реализовать полностью на CSS двумя способами: компактным WebKit-подходом с -webkit-line-clamp и более универсальным методом с вычислением высоты и градиентом. Для динамического раскрытия можно применить селектор :has() и стилизованный input-чекбокс. Всегда учитывайте поддержку браузеров и требования по доступности при выборе решения.
Важно
Проверяйте поддержку CSS-селекторов и свойств в целевых браузерах и добавляйте безопасные откаты для пользователей старых версий.
Ключевые ссылки и дальнейшее чтение
- Проверяйте актуальную совместимость на caniuse.com (по запросам “-webkit-line-clamp” и “:has()”)