Автор: Ян Вэньбинь
Исходное заявление: Эта статья подготовлена членами команды интерфейса чтения YFE, пожалуйста, уважайте оригинальность, пожалуйста, свяжитесь с общедоступной учетной записью (id: yuewen_YFE) для авторизации и укажите автора, источник и ссылку.
Многострочный текст Развернуть Свернуть — очень распространенное взаимодействие, как показано на следующем рисунке.
Основные трудности в реализации такого типа компоновки и взаимодействия заключаются в следующем:
- Кнопка «Развернуть и свернуть» в правом нижнем углу многострочного текста
- Переключение между состояниями «развернуть» и «свернуть»
- Когда текст не превышает заданного количества строк, кнопка "Развернуть свернуть" не отображается
Честно говоря, в одиночку смотреть на этот макет раньше было непросто, даже с JavaScript (нужно вычислять ширину текста, чтобы динамически перехватывать текст,vue-clampВот как это делается), не говоря уже о следующей логике взаимодействия и суждения, но после некоторых размышлений, на самом деле, чистый CSS также может быть отлично реализован, давайте шаг за шагом, чтобы увидеть, как этого добиться~
1. Кнопка "Развернуть свернуть" в правом нижнем углу
Многим студентам-дизайнерам нравится этот дизайн, они помещают кнопку в нижний правый угол, а текстсмешиваниеВместе, а не в одну линию, это может быть более визуально и эстетически приятно. Давайте сначала рассмотрим усечение многострочного текста, это относительно просто
1. Обрезка многострочного текста
Допустим есть такая html структура
<div class="text">
浮动元素是如何定位的
正如我们前面提到的那样,当一个元素浮动之后,它会被移出正常的文档流,然后向左或者向右平移,一直平移直到碰到了所处的容器的边框,或者碰到另外一个浮动的元素。
</div>
Многострочный текст нельзя пропустить, с этим должен быть знаком каждый, в основном он используется дляline-clamp, ключевые стили следующие
.text {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
2. Эффект объемного звучания в правом нижнем углу
упомянулэффект переноса текста, о чем вообще можно думатьпоплавок поплавок, Да, не думайте, что флоатинг ушел в прошлое, а конкретные сценарии все еще очень полезны. Например, поставьте внизу кнопку, а затем установите плавающую
<div class="text">
<button class="btn">展开</button>
浮动元素是如何定位的
正如我们前面提到的那样,当一个元素浮动之后,它会被移出正常的文档流,然后向左或者向右平移,一直平移直到碰到了所处的容器的边框,或者碰到另外一个浮动的元素。
</div>
.btn {
float: left;
/*其他装饰样式*/
}
Если установлено правое плавание
.btn {
float: right;
/*其他装饰样式*/
}
Существует ужеокружатьЭффект только в правом верхнем углу, как переместить кнопку в правый нижний угол? попробуй сначалаmargin
.btn {
float: right;
margin-top: 50px;
/*其他装饰样式*/
}
Видно, что хотя кнопка находится в правом нижнем углу, текст не имеет пробела над кнопкой.
несмотря на то чтоmarginНе решает проблему, но плавающая кнопка по-прежнему влияет на весь текст, что, если плавающих элементов несколько? Здесь используются псевдоэлементы::beforeзаменять
.text::before{
content: '';
float: right;
width: 10px;
height: 50px;/*先随便设置一个高度*/
background: red
}
Теперь, когда кнопка находится слева от псевдоэлемента, как мне переместить ее вниз? Очень просто, очистить поплавокclear: both;просто хорошо
.btn {
float: right;
clear: both;
/*其他装饰样式*/
}
Видно, что текст теперь полностью обернут вокруг двух плавающих элементов справа, пока ширина псевдоэлемента с красным фоном установлена на 0 (или ширина не установлена, по умолчанию 0) , достигается эффект заворачивания в правом нижнем углу.
.text::before{
content: '';
float: right;
width: 0; /*设置为0,或者不设置宽度*/
height: 50px;/*先随便设置一个高度*/
}
3. Динамическая высота
Хотя нижний правый и объемный вверху доделаны, высота фиксированная.Как выставить ее динамически? можно использовать здесьcalcДля расчета вычтите высоту кнопки из высоты всего контейнера, как показано ниже.
.text::before{
content: '';
float: right;
width: 0;
height: calc(100% - 24px);
}
Жалко, похоже, это не имеет никакого эффекта, открыл консоль, чтобы посмотреть, и обнаружил, чтоcalc(100% - 24px)Вычислить высоту как 0
Причину легко представить, т.Высота 100% отказВ сети есть много разборов подобного рода задач.Обычное решение - указать высоту для родителя, но здесь высота меняется динамически, и есть развернутое состояние. Высота еще более непредсказуема, поэтому установка высоты невозможна Выбрать.
Кроме того, на самом деле есть еще один способ, который заключается в использованиигибкий макет. Наверное, такгибкий макетВ подпунктах высота изменения может быть рассчитана в процентах Подробнее см. в информации на w3.orgcss-flexboxописание
If the flex item hasalign-self: stretch, redo layout for its contents, treating this used size as its definite cross size so that percentage-sized children can be resolved.
Поэтому необходимо дать.textоберните один слой, затем установитеdisplay: flex
<div class="wrap">
<div class="text">
<button class="btn">展开</button>
浮动元素是如何定位的
正如我们前面提到的那样,当一个元素浮动之后,它会被移出正常的文档流,然后向左或者向右平移,一直平移直到碰到了所处的容器的边框,或者碰到另外一个浮动的元素。
</div>
</div>
.wrap{
display: flex;
}
На практике display:grid и display:-webkit-box одинаково эффективны, принцип аналогичен
Таким образом, расчетная высота только сейчас вступает в силу, и изменяется количество строк текста, которое также находится в правом нижнем углу~
Кроме того, динамическая высота также может быть реализована с отрицательным запасом (производительность будет немного лучше, чем у calc).
.text::before{
content: '';
float: right;
width: 0;
/*height: calc(100% - 24px);*/
height: 100%;
margin-bottom: -24px;
}
На этом эффект обтекания правого нижнего угла в основном завершен, и многоточие тоже перед кнопкой развернуть.Полный код можно посмотретьЭффект переноса многострочного расширения в правом нижнем углу codepen
4. Совместимость с другими браузерами
Приведенная выше реализация является наиболее совершенным способом справиться с этим. Я изначально думал, что совместимость не большая проблема, ведь использовались только усечение текста и плавание.-webkit-line-clampХотя это является-webkit-префикс, ноfirefoxОн тоже поддерживает.Когда я открыл его, я был ошарашен.safariа такжеfirefoxВсе запутано!
Это немного неудобно, неужели все предыдущие усилия были напрасными? Эти два нельзя игнорировать, иначе это будет только демо и не может быть использовано в производственной среде.
Быстро откройте консоль, чтобы увидеть, в чем причина. После недолгих поисков оказалось, чтоdisplay: -webkit-box! После установки этого свойства исходный текст как бы становится целым блоком, а плавающий элемент не может производить эффект обтекания, после его удаления плавание нормальное.
Итак, возникает вопрос:Как добиться многострочного усечения без отображения: -webkit-box?
На самом деле вышеперечисленными усилиями достигнут эффект обтекания в правом нижнем углу.Если установить максимальную высоту, когда известно количество строк, будет ли выполняться еще и многострочное усечение? Для облегчения установки высоты можно добавитьвысота линии, если его нужно установить в 3 строки, то высота устанавливается вline-height * 3
.text {
/*
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
*/
line-height: 1.5;
max-height: 4.5em;
overflow: hidden;
}
Чтобы облегчить лучший контроль над количеством строк, обычно используемое количество строк может быть разделено с помощью селектора атрибутов (обычно не слишком много), как показано ниже.
[line-clamp="1"] {
max-height: 1.5em;
}
[line-clamp="2"] {
max-height: 3em;
}
[line-clamp="3"] {
max-height: 4.5em;
}
...
<!--3行-->
<div class="text" line-clamp="3">
...
</div>
<!--5行-->
<div class="text" line-clamp="5">
...
</div>
Видно, что это в принципе нормально, за исключением того, что многоточия нет, теперь добавьте многоточие, прямо перед кнопкой расширения, это можно реализовать с помощью псевдоэлементов
.btn::before{
content: '...';
position: absolute;
left: -10px;
color: #333;
transform: translateX(-100%)
}
так,Safariа такжеFirefoxСовместимый макет в основном завершен, и полный код можно просмотретьЭффект переноса многострочного расширения в правом нижнем углу codepen (полная совместимость)
Два, "расширенные" и "свернутые" два состояния
Когда дело доходит до переключения состояния CSS, об этом может подумать каждый.input type="checkbox"Бар. Здесь нам также нужно использовать эту функцию, сначала добавьтеinput, затем поместите предыдущийbuttonзаменитьlabel, и черезforассоциация атрибутов
<div class="wrap">
<input type="checkbox" id="exp">
<div class="text">
<label class="btn" for="exp">展开</label>
浮动元素是如何定位的
正如我们前面提到的那样,当一个元素浮动之后,它会被移出正常的文档流,然后向左或者向右平移,一直平移直到碰到了所处的容器的边框,或者碰到另外一个浮动的元素。
</div>
</div>
Таким образом, при нажатииlabel, на самом деле щелкнулinputЭлемент, теперь давайте добавим два состояния, которые должны отображать только 3 строки и не ограничивать количество строк
.exp:checked+.text{
-webkit-line-clamp: 999; /*设置一个足够大的行数就可以了*/
}
Совместимые версии могут напрямую устанавливать максимальную высотуmax-heightявляется большим значением или напрямую устанавливается наnone
.exp:checked+.text{
max-height: none;
}
Здесь тоже есть небольшая проблема.Кнопка "Развернуть" после нажатия должна становиться "Свернуть".Как это изменить?
Есть хитрость: вы можете использовать псевдоклассы всякий раз, когда вам нужно динамически изменять содержимое.contentТехнология генерации, конкретный метод заключается в удалении или скрытии текста в кнопке и использовании псевдоэлементов для генерации
<label class="btn" for="exp"></label><!--去除按钮文字-->
.btn::after{
content:'展开' /*采用content生成*/
}
Добавить к:checkedусловие
.exp:checked+.text .btn::after{
content:'收起'
}
Совместимые версии Из-за предыдущего пропущенного номера он не может быть автоматически скрыт, поэтому необходимо выполнить дополнительную обработку.
.exp:checked+.text .btn::before {
visibility: hidden; /*在展开状态下隐藏省略号*/
}
Эффект в принципе такой же, как и в начале этой статьи, полный код можно посмотретьcodepen, многострочное расширение, сворачивающееся взаимодействие, совместимую версию можно посмотретьCodepen многострочное развертывание и свертывание взаимодействия (полная совместимость)
Еще одна вещь, если даноmax-heightУстановите соответствующее значение, обратите внимание, чтоявляется подходящим значением, конкретный принцип может относиться кCSS-трюки: динамическая анимация перехода высоты, а также добавить анимацию перехода
.text{
transition: .3s max-height;
}
.exp:checked+.text{
max-height: 200px; /*超出最大行高度就可以了*/
}
В-третьих, оценка количества строк текста
Вышеупомянутое взаимодействие в основном удовлетворило требованиям, но проблемы все равно будут. НапримерКогда текст маленький, усечения в это время нет, то есть многоточия нет, но кнопка "Развернуть" все равно в правом нижнем углу, как ее скрыть?
Обычно решение js простое, сравните элементscrollHeightа такжеclientHeightВы можете, а затем добавить соответствующее имя класса. Ниже псевдокод
if (el.scrollHeight > el.clientHeight) {
// 文本超出了
el.classList.add('trunk')
}
Итак, как CSS реализует такого рода суждения?
Безусловно, в CSS нет такого логического суждения, и большинству из нас нужно использовать его с других точек зрения.«Завязка»реализовать. Например, в этом сценарии, когда усечение не происходит, это означает, что текст полностью виден.конец текстаДобавьте элемент (маленький красный квадрат), чтобы не влиять на исходный макет, здесь задается абсолютное позиционирование
.text::after {
content: '';
width: 10px;
height: 10px;
position: absolute;
background: red;
}
Как видите, за красным квадратом здесь полностью следует многоточие. Когда появится многоточие, маленький красный квадрат должен исчезнуть,Потому что он был сжатздесь поставь родителейoverflow: hiddenТо, что вы можете видеть, временно скрывает принцип
Затем вы можете установить маленький красный квадрат прямо сейчас надостаточно большой размер,Например100% * 100%
.text::after {
content: '';
width: 100%;
height: 100%;
position: absolute;
background: red;
}
Как видите, красные блоки закрывают нижний правый угол, а теперь меняют фон на белый (тот же цвет фона, что и у родителя), родительoverflow: hiddenдобавить обратно
.text::after {
content: '';
width: 100%;
height: 100%;
position: absolute;
background: #fff;
}
Теперь взгляните на эффект нажатия, чтобы развернуть
Теперь, после его расширения, обнаруживается, что кнопка отсутствует (сейчас покрыта псевдоэлементом и не может быть нажата), что, если вы хотите, чтобы она все еще была видна после нажатия? добавить это:checkedсостояние, скрывать оверлей при раскрытии
.exp:checked+.text::after{
visibility: hidden;
}
Таким образом реализована функция скрытия кнопки расширения, когда текста меньше
Окончательный полный код можно посмотретьcodepen многострочное расширение свернуть автоматически скрыть, совместимую версию можно посмотретьcodepen многострочное развертывание и свертывание автоматически скрывают (полная совместимость)
Следует отметить, что совместимые версии могут поддерживатьсяIE 10+(Это уж слишком, он по-прежнему поддерживает IE), но поскольку IE не поддерживает codepen, тестовый IE можно скопировать и протестировать локально.
4. Резюме и объяснение
В общем, основное внимание уделяетсямакет, взаимодействие на самом деле относительно простое, общая стоимость реализации на самом деле очень низкая, и нет относительно необычных атрибутов, за исключением макета.-webkit-boxКажется, немного глючит (в конце концов-Webkit-kernelFirefox просто позаимствовал у него, неизбежны некоторые проблемы), к счастью, можно добиться эффекта обрезания многострочного текста, совместимость неплохая, в принципе полностью совместима (IE10+), вот ключевые моменты реализации
- Эффекты переноса текста рассматриваются в первую очередьпоплавок поплавок
- гибкий макетДочерние элементы могут вычислять высоту в процентах
- Многострочное усечение текста также можно использовать в сочетании с эффектами переноса текста.max-heightРеализация моделирования
- Переключение состояний может быть выполнено с помощьюcheckbox
- CSS для изменения текста можно использоватьпсевдоэлементгенерировать
- Больше использования окклюзии CSS«Завязывание глаз»
Можно сказать, что эффект расширения и свертывания многострочного текста является первым в отрасли.Большая проблемаЕсть много js-решений, но ни одно из них не кажется идеальным. Я надеюсь, что эта новая идея решения CSS может вдохновить вас по-разному. Спасибо за чтение, добро пожаловать в избранное и вперед~