От автора: на днях у нас в офисе зашла дискуссия об усечении текста, и я с тех пор задался вопросом, зашел ли CSS достаточно далеко, чтобы можно было правильно сделать усеченный текст, например, с помощью checkbox.
То есть поддерживает ли он следующее:
Несколько строк
Кнопку «Показать больше», которая отображает полный текст при нажатии
text-overflow: ellipsis не поддерживает несколько строк, но я вспомнил о свойстве line-clamp, которое можно использовать для получения многострочного усеченного текста. К счастью, на CSS Tricks есть хорошая рабочая демо-версия, плюс поддержка браузерами теперь довольно приличная. Здорово!
Практический курс по верстке адаптивного сайта с нуля!
Изучите курс и узнайте, как верстать современные сайты на HTML5 и CSS3
А как насчет кнопки «показать больше»?
Создание кнопки «показать больше» требует некоторой нестандартной хакерской работы с CSS. Я не мог использовать button или тег <a>, так как это работа для печально известного хака с чек-боксом, и для этого потребовался элемент метки и… чек-бокс! Итак, я получил следующую разметку:
<div class=»box»> <input type=»checkbox»id=»expanded»> <p>Hey,don’t cut me off like that. I want to speak my mind and don’tappreciate being put intoabox.</p> <!—Примечание:Ксожалению,яненашелкрасивыйспособвложитьбольшекнопок/метоквабзац,доилипослеусечения.—> <label for=»expanded»role=»button»>read more</label> </div> |
Поскольку я установил чек-бокс прямо перед абзацем, теперь я мог бы использовать псевдо-класс :checked для переключения, например так:
input:checked + p { -webkit-line-clamp:unset; } |
И действительно, это сделало именно то, что я хотел: нажмите кнопку, и мы переключаемся с усеченного текста к полному. Красиво.
Но… но… но это хак, а что насчет a11y??
В самом деле, хак с чек-боксом не такой уж проблемный в плане семантики, но и не очень доступный, так как большинство просто наивно устанавливают display: none для чек-бокса. Это приводит к нарушению навигации с клавиатуры, поскольку вы не можете переключиться через табуляцию на скрытый чек-бокс, и переключение на метку не помогает, поскольку клавиши пробела / ввода не перенаправляют событие на чек-бокс, как это происходит в случае нажатия кнопки (это имеет смысл, так как обычно вы бы выбрали бы чек-бокс вместо метки).
Я хочу, чтобы мои примеры и демонстрации были как можно более доступными, поэтому, чтобы решить эту проблему, я сначала сделал чек-бокс focusable / tabbable, хотя все еще невидимым, например, так:
input { opacity:0; position:absolute; pointer-events:none; } |
Практический курс по верстке адаптивного сайта с нуля!
Изучите курс и узнайте, как верстать современные сайты на HTML5 и CSS3
Узнать подробнее
Единственная оставшаяся проблема заключалась в том, что теперь я мог переключаться табуляцией на чсек-бокс, но у меня не было возможности узнать, без программы чтения с экрана, выделен ли он фокусом или нет … ну … он ведь невидим. Чтобы решить эту проблему, я заставил метку получать (примерно) стиль фокуса браузера по умолчанию, когда чек-бокс выделен фокусом:
input:focus ~ label { outline:-webkit-focus-ring-colorauto5px; } |
Проверьте комбинированную демонстрацию, попробуйте нажать на кнопку мышью, а затем с помощью клавиатуры и клавиши пробела!
Что если я не знаю, будет ли текст усекаться или нет? Как мне отображать кнопку динамически?
Я попытался выяснить, что я могу сделать, чтобы динамически отображать кнопку, когда произвольный текст в абзаце слишком длинный, и скрывать ее в противном случае. К сожалению, это единственная функция, которую я просто не смог сделать с помощью CSS, потому что для этого требуется селектор :truncated, чтобы мы могли сделать что-то вроде этого:
.read-more {display:none;} p:truncated + .read-more {display:block;} |
Оказывается, у других была та же идея, но обсуждение 2014 года никуда не привело. Бу! Если вам действительно нужна эта функция, рассмотрите возможность использования JS до тех пор, пока не появится поддержка браузерами, например:
constps=document.querySelectorAll(‘p’); constobserver=newResizeObserver(entries=>{ for(let entry of entries){ entry.target.classList[entry.target.scrollHeight>entry.contentRect.height?’add’:’remove’](‘truncated’); } }); ps.forEach(p=>{ observer.observe(p); }); |
А вот расширенная демонстрация с JS хелпером и изменением размера блока (откройте в Codepen и измените размер окна браузера, чтобы увидеть это поведение):