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

Обрезка текста в 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
Автор
Редакция

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

Несколько аккаунтов Skype: Multi Skype Launcher
Программное обеспечение

Несколько аккаунтов Skype: Multi Skype Launcher

Журнал для работы: повысить продуктивность
Productivity

Журнал для работы: повысить продуктивность

Персональные звуки уведомлений на Android
Android.

Персональные звуки уведомлений на Android

Скачивание шоу Hulu для офлайн‑просмотра
Стриминг

Скачивание шоу Hulu для офлайн‑просмотра

Microsoft Start: персонализированная новостная лента
Новости

Microsoft Start: персонализированная новостная лента

Как изменить имя в Epic Games быстро
Гайды

Как изменить имя в Epic Games быстро