Гид по технологиям

Обрезка текста в CSS: два подхода и кнопка «Развернуть» без JavaScript

6 min read Frontend Обновлено 06 Dec 2025
Обрезка текста в CSS: два способа и кнопка без JS
Обрезка текста в CSS: два способа и кнопка без JS

Человек работает за MacBook Pro

Ограничение объёма текста внутри элемента — частая задача веб‑верстки. Часто это карточки с трех‑ или четырехстрочным анонсом и кнопкой, которая раскрывает полный текст. Это можно решить комбинацией CSS + JavaScript, но также возможно обойтись только CSS. Ниже — подробный разбор двух методов, плюсы/минусы и готовые приёмы для продакшен‑кейсов.

Краткая структура примера

Исходная HTML‑структура простая и семантичная: секция содержит несколько article, в каждом — заголовок, параграф и input, который превратим в кнопку.

Пример HTML (index.html):





  
  Document
  



  

Article 1

300‑word text goes here

Article 2

200‑word text goes here

Article 3

100‑word text goes here

В примерах ниже я покажу CSS‑правила для раскладки, обрезки текста и для кнопки.

Техника WebKit (‑webkit‑line‑clamp)

Идея: использовать специфику WebKit — display: -webkit-box и -webkit-line-clamp для ограничения числа видимых строк.

Основной стиль страницы (style.css — начало):

*, *::before, *::after {
  box-sizing: border-box;
}

body {
  background: #f3f3f3;
  overflow: hidden;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial;
}

.card-group {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: .5rem;
  align-items: flex-start;
  padding: 1rem;
}

.card {
  background: white;
  padding: 1rem;
  border: 1px solid black;
  border-radius: .25em;
}

h2, p {
  margin: 0;
}

h2 {
  margin-bottom: 1rem;
}

А теперь — сам WebKit‑приём для ограничение числа строк:

.cuttoff-text {
  --max-lines: 3;
  overflow: hidden;

  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: var(--max-lines);
}

Плюсы:

  • Очень короткое решение.
  • Работает без вычисления высоты.

Минусы:

  • Требует display: -webkit-box — это сильно ограничивает варианты layout (не подходит, если элемент должен быть flex или grid контейнером).
  • Поведение зависит от реализации движка; можно получить разницу в переносах слов.
  • Поддержка у всех браузеров исторически разная (работает в Chromium/WebKit‑браузерах).

Images showing the articles section

Более гибкий подход: вычисляемая высота + градиент

Идея: установить фиксированную высоту, основанную на количестве строк и line‑height, а затем добавить плавный градиент‑фейд внизу для естественного перехода.

Преимущество этого метода в том, что блок может оставаться любым display (flex, grid и т.д.), и вы полностью контролируете высоту.

Пример CSS:

.cuttoff-text {
  --max-lines: 5;
  --line-height: 1.4;
  /* высота = число строк * размер шрифта * line-height */
  height: calc(var(--max-lines) * 1em * var(--line-height));
  line-height: var(--line-height);
  overflow: hidden;
  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, rgba(255,255,255,0), white);
}

Плюсы:

  • Поддерживает любые display‑режимы.
  • Можно тонко настроить визуальный эффект (длина фейда, цвет плашки и т.д.).

Минусы:

  • Нужно точно учитывать размер шрифта и line‑height (при динамическом масштабе/настройках пользователя возможны неточности).
  • Псевдоэлемент закрывает нижнюю область — нужно думать про доступность и выделение текста.

Screenshot of grid container with card using blur effect

Добавление динамической кнопки «Развернуть/Свернуть» без JavaScript

Мы используем input type=”checkbox” как переключатель и селектор :has() для изменения высоты контейнера. Обратите внимание на вопросы совместимости: :has() поддерживается в современных движках, но если вам нужен полифилл для старых браузеров, см. раздел «Альтернативы».

CSS для оформления кнопки‑переключателя:

.expand-btn {
  appearance: none;
  border: 1px solid black;
  padding: .5em;
  border-radius: .25em;
  cursor: pointer;
  margin-top: 1rem;
  display: inline-block;
}

.expand-btn:hover {
  background-color: #ccc;
}

/* Текст кнопки через content */
.expand-btn::before {
  content: "Развернуть";
}

.expand-btn:checked::before {
  content: "Свернуть";
}

Чтобы раскрывать текст, используем селектор :has в связке с соседством элементов. В примере элемент input идёт после параграфа, поэтому можно воспользоваться селектором у параграфа:

/* Когда рядом с cuttoff-text расположен checked .expand-btn — делаем высоту auto */
.cuttoff-text:has(+ .expand-btn:checked) {
  height: auto;
}

Замечания по доступности:

  • input должен иметь aria‑label или быть связан с
  • Предпочтительнее использовать реальную кнопочную семантику:

Screenshot showing a grid container with one expanded card and two collapsed ones

Альтернативы и гибридные варианты

  1. JavaScript‑fallback: используйте JS для переключения класса (например, .is‑expanded) у контейнера и управляйте высотой через max‑height с анимацией. Этот вариант универсален по совместимости и даёт плавные переходы.
  2. CSS с использованием details/summary: нативный раскрывающийся блок, доступный и простой, но менее гибкий по дизайну.
  3. Комбинация CSS‑only + JS: базовый функционал на CSS, а при наличии JS — улучшения (плавность, переходы, анимации).

Когда CSS‑only может не подойти:

  • Нужно плавное открытие/закрытие с высотой неизвестной высоты (в этом случае удобнее управлять max‑height через JS).
  • Поддержка старых браузеров, где :has или -webkit-line-clamp отсутствуют.

Практические советы и частые ошибки

  • Всегда учитывайте line‑height при расчёте фиксированной высоты; по умолчанию 1em ≈ размер шрифта.
  • Если пользователь увеличивает масштаб страницы, фиксированные расчёты на rem/em ведут себя лучше, чем px.
  • Псевдоэлемент для градиента не должен блокировать pointer‑events — устанавливайте pointer-events: none.
  • Если делаете «копируемый текст», тестируйте выделение: градиент может визуально скрыть конец, но выделение всё равно работает.
  • Для SEO и доступности не прячьте смысловой контент от поисковых роботов/скринридеров: используйте aria‑labels и отвечайте ожиданиям пользователя.

Совместимость и ограничения

  • -webkit-line-clamp — прост в применении, но требует display: -webkit-box.
  • :has — мощный селектор (очень удобен для CSS‑only паттернов), но его поддержка может отличаться в старых браузерах. Для критичных проектов делайте фолбэки.
  • Для мобильных браузеров учитывайте, как изменяется перенос строк при разных ширинах.

Таблица совместимости (ориентир):

ПриёмПоддержкаОграничения
-webkit-line-clampПоддерживается в WebKit/Chromium‑движкахТребует display: -webkit-box
Явная высота + градиентУниверсальнаНужно рассчитывать line‑height
:has()Современные браузерыМожет отсутствовать в устаревших версиях

Критерии приёмки

  1. Текст в карточке по умолчанию отображается не больше заданного числа строк на всех важных целевых разрешениях.
  2. Кнопка «Развернуть/Свернуть» читаемо сменяет своё состояние (визуально и для экранных читалок через aria‑атрибуты).
  3. При раскрывании весь текст доступен и копируется; макет не ломается.
  4. Проверены фолбэки для браузеров без :has (либо JS‑fallback, либо graceful degradation).

Чек‑лист по ролям

Для разработчика:

  • Реализовать расчёт высоты на основе line‑height и числа строк.
  • Добавить aria‑label/role для input/button.
  • Тестировать в ключевых браузерах (Desktop/Mobile).

Для дизайнера:

  • Уточнить поведение градиента (цвет/высота фейда).
  • Согласовать состояние кнопки в активном/hover состоянии.

Для QA:

  • Проверить текст при увеличенном шрифте (браузерные настройки).
  • Проверить копирование и выделение текста в усечённом виде.
  • Проверить фолбэки на старых браузерах.

Мини‑методология внедрения (шаги)

  1. Выбрать цель: нуждаетесь ли вы в точном числе видимых строк или только в визуальном ограничении?
  2. Выбрать метод: WebKit для простых случаев или вычисляемая высота для гибкости.
  3. Реализовать вариант, добавить accessibility атрибуты и тесты.
  4. Добавить фолбэк: либо JS (class toggle), либо graceful degradation.
  5. Провести cross‑browser тестирование и принять по критериям.

Decision tree

flowchart TD
  A[Нужно ограничить строки в блоке?] --> B{Нужна ли максимальная гибкость layout?}
  B -- Да --> C[Использовать вычисляемую высоту + градиент]
  B -- Нет --> D[Можно использовать -webkit-line-clamp]
  C --> E{Требуется кнопка «Развернуть» без JS?}
  D --> E
  E -- Да --> F{Поддерживает ли целевой браузер :has?}
  E -- Нет --> G[Использовать JS‑fallback для раскрытия]
  F -- Да --> H[Использовать :has + input checkbox]
  F -- Нет --> G

Шаблон — небольшой cheat‑sheet (быстрое решение)

/* 1) Базовая карточка */
.card { background:#fff; padding:1rem; border-radius:6px; }

/* 2) Обрезка через line‑clamp */
.cuttoff { display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:3; overflow:hidden; }

/* 3) Обрезка через высоту */
.cuttoff2 { --lh:1.4; --lines:4; height:calc(var(--lines) * 1em * var(--lh)); overflow:hidden; position:relative; }
.cuttoff2::before{ content:''; position:absolute; bottom:0; height:2.2em; width:100%; background:linear-gradient(to bottom, rgba(255,255,255,0), #fff); pointer-events:none; }

Советы по локализации и UI‑текстам

  • Переводите надписи кнопок: «Развернуть» / «Свернуть» — в большинстве локалей это ожидаемая семантика.
  • Если контент многоязычный, используйте aria‑labels с соответствующим языковым тегом.

Короткое резюме

  • Для простых случаев используйте -webkit‑line‑clamp, если он покрывает ваши целевые браузеры. Это быстрый путь.
  • Если нужен гибкий layout или вы хотите контролировать fade‑эффект, рассчитывайте высоту через line‑height и используйте псевдоэлемент для градиента.
  • Для кнопки раскрытия без JS используйте input + :has(), но обеспечьте фолбэк для старых браузеров.

Важно: всегда тестируйте поведение при масштабировании шрифтов и на мобильных устройствах.

Ключевые проверки:

  • Поведение в наиболее популярных браузерах, мобильная адаптация, корректность aria‑атрибутов.

Спасибо — если нужно, могу подготовить готовый репозиторий с рабочим примером, полифиллами и автотестами для нескольких браузеров.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Как устроить идеальную вечеринку для просмотра ТВ
Развлечения

Как устроить идеальную вечеринку для просмотра ТВ

Как распаковать несколько RAR‑файлов сразу
Инструменты

Как распаковать несколько RAR‑файлов сразу

Приватный просмотр в Linux: как и зачем
Приватность

Приватный просмотр в Linux: как и зачем

Windows 11 не видит iPod — способы исправить
Руководство

Windows 11 не видит iPod — способы исправить

PS5: как настроить игровые пресеты
Консоли

PS5: как настроить игровые пресеты

Как переключить камеру в Omegle на iPhone и Android
Руководство

Как переключить камеру в Omegle на iPhone и Android