Многострочный усеченный текст с кнопкой «Показать больше» на чистом CSS

Я написал скрипт на CSS для размещения многострочного усеченного текста с кнопкой «Читать далее».

Я задался вопросом, позволяет ли CSS правильно оформить усеченный текст так, чтобы разместить в нем несколько строк?  А также по нажатию кнопки «Показать больше» отобразить текст полностью.

Свойство text-overflow: ellipsis не поддерживает многострочность. Но я вспомнил о свойстве line-clamp, которое позволяет обрезать многострочный текст.

Подробнее о кнопке «Показать больше»

Для создания кнопки «Показать больше» я не мог использовать тег <button> или <a>. Для этого требуется label и чекбокс. Вот что получилось:

<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't appreciate being put into a box.</p>
  <!-- Примечание: я не нашел способа поместить дополнительную кнопку/метку в строку внутри абзаца после или перед усечением. -->
  <label for="expanded" role="button">read more</label>
</div>

Я разместил чекбокс прямо перед абзацем, поэтому можно использовать псевдокласс :checked для активации усечения текста:

input:checked + p {
  -webkit-line-clamp: unset;
}

Нажмите кнопку, и в абзаце отобразится обрезанная версия текста.

Но как насчет доступности?

Хак с чекбоксом не только семантически неправильный, но и ограничивает возможности доступа к функционалу для людей с плохим зрением. При этом присваивается для чекбокса свойство display: none. Из-за этого нарушается навигация с помощью клавиатуры. Нельзя использовать скрытый чек-бокс, а использование метки не помогает. Событие нажатия клавиши пробела/ввода не перенаправляют событие в чекбокс.

Чтобы решить эту проблему,  я сделал чекбокс фокусируемым, хоть и все еще невидимым.

input {
  opacity: 0;
  position: absolute;
  pointer-events: none;
}

Теперь чекбокс можно выделить, но без скринридера нельзя узнать, установлен он или нет, так как невидим. Чтобы решить эту проблему, я заставил label наследовать стиль фокуса браузера по умолчанию, когда чекбокс выделен:

input:focus ~ label {
  outline: -webkit-focus-ring-color auto 5px;
}

Ниже приведена комбинированная демо-версия. Попробуйте нажать на кнопку с помощью мышки, а затем используя клавишу пробела.

Как отображать кнопку динамически?

Но как динамически отображать кнопку, когда текст в абзаце слишком длинный, чтобы поместиться в контейнер. Это единственная функция, которую я не смог реализовать с помощью CSS. Потому что она требует применения селектора :truncated:

.read-more { display: none; }
p:truncated + .read-more { display: block; }

Поэтому реализовать это можно только с помощью JavaScript. Например:

const ps = document.querySelectorAll('p');
const observer = new ResizeObserver(entries => {
  for (let entry of entries) {
    entry.target.classList[entry.target.scrollHeight > entry.contentRect.height ? 'add' : 'remove']('truncated');
  }
});

ps.forEach(p => {
  observer.observe(p);
});

А вот расширенная демо-версия: