Задача. Необходимо сделать такой функционал для блока с контентом, который будет по умолчанию скрывать часть его контента, а при нажатии на текст «Развернуть» контент блока должен раскрываться полностью, а текст сам «Развернуть» должен измениться на «Свернуть». И обратно – при клике на «Свернуть» контент должен частично скрыться. Например, это может быть применено в каталоге с товарами, где отображаются в несколько строк какие-то метки для фильтрации товаров. Или нужно просто скрыть часть текста в статье или на главной.
Решение 1. Чтобы убрать контент под кат можно использовать лишь HTML + CSS. Для этого нужно будет сам контент обернуть в div и назначить свой класс. Добавить тег input типа чекбокс перед обернутым контентом. В конец контента добавить пустой див с еще одним своим классом. После обернутого контента добавить label. Вот HTML и CSS Код №1 для примера:
1 2 3 4 5 6 7 8 |
<input type="checkbox" class="read-more-checker" id="read-more-checker" /> <div class="limiter"> <!-- Здесь сам контент который должен будет скрываться / раскрываться --> <div class="bottom"></div> </div> <label for="read-more-checker" class="read-more-button"></label> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
/* Стили для текстового поля с кнопкой "Далее" */ .limiter { max-height: 200px; overflow: hidden; position: relative; } .limiter .bottom { position: absolute; /* Если прыгает - можно попробовать sticky */ bottom: 0; background: linear-gradient( to bottom, rgb(255 217 29 / 0%), rgb(255 217 29)90%); width: 100%; height: 60px; opacity: 1; transition: 0.3s; } .read-more-checker { opacity: 0; position: absolute; } .read-more-checker:checked ~ .limiter { max-height: none; } .read-more-checker:checked ~ .limiter .bottom { opacity: 0; transition: 0.3s; } .read-more-checker ~ .read-more-button:before { content: "Развернуть »"; } .read-more-checker:checked ~ .read-more-button:before { content: "Свернуть «"; } .read-more-button { cursor: pointer; display: inline-block; color: #777; text-decoration: underline; } |
- Тег input должен обязательно стоять перед обрабатываемым контентом. Через него происходит переключение, с помощью тега
label class="read-more-button"
и ссылаемся на чекбокс input черезfor="read-more-checker"
. - В теге div с
class="limiter"
размещается сам контент. В его стилях мы и устанавливаем необходимую высоту видимого контента. - Тег div с
class="bottom"
– это блок с градиентным фоном, который показывает, что под контент не полный и внизу есть что-то ещё. Его нужно настроить под свой контент. - Тег label с
class="read-more-button"
– тот элемент через который будет осуществляться скрытие и отображение всего контента. Также благодаря псевдоэлементам :after и :before мы можем сделать чтобы текст в условной кнопке для разворачивания изменялся в зависимости от состояния (Развернуть/Свернуть).
Источник: Aida Drogan
Решение 2. Дополнение к Решению 1, когда блоков где текст скрывается под кат несколько. Если блоков несколько, то и class, id, for со значением ‘read-more-checker’ должны различаться у всех блоков, а в стилях нужно продублировать правила где есть класс read-more-checker
для новых блоков.
Можно немного уменьшить код за счет использования пользовательских атрибутов data-
, а class="read-more-checker"
убрать — Код №2.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
<style> .block {margin: 3rem;} /* Стили для текстового поля с кнопкой "Развернуть" */ .limiter { max-height: 100px; overflow: hidden; position: relative; } .limiter .bottom { position: absolute; bottom: 0; background: linear-gradient( to bottom, rgb(255 217 29 / 0%), rgb(255 255 255)85%); width: 100%; height: 60px; opacity: 1; transition: 0.3s; } [data-more-checker^="read-more"] { opacity: 0; position: absolute; } [data-more-checker^="read-more"]:checked ~ .limiter { max-height: none; } [data-more-checker^="read-more"]:checked ~ .limiter .bottom { opacity: 0; transition: 0.3s; } [data-more-checker^="read-more"] ~ .read-more-button:before { content: "Развернуть »"; } [data-more-checker^="read-more"]:checked ~ .read-more-button:before { content: "Свернуть «"; } .read-more-button { cursor: pointer; display: inline-block; color: #777; text-decoration: underline; } </style> <div class="block"> <input type="checkbox" id="read-more-checker" data-more-checker="read-more" /> <div class="limiter"> <!-- Здесь сам контент который должен будет скрываться / раскрываться --> <div class="bottom"></div> </div> <label for="read-more-checker" class="read-more-button"></label> </div> <div class="block"> <input type="checkbox" id="read-more-checker-2" data-more-checker="read-more-2" /> <div class="limiter"> <!-- Здесь сам контент который должен будет скрываться / раскрываться --> <div class="bottom"></div> </div> <label for="read-more-checker-2" class="read-more-button"></label> </div> <div class="block"> <input type="checkbox" id="read-more-checker-3" data-more-checker="read-more-3" /> <div class="limiter"> <!-- Здесь сам контент который должен будет скрываться / раскрываться --> <div class="bottom"></div> </div> <label for="read-more-checker-3" class="read-more-button"></label> </div> |
[data-more-checker^="read-more"]
— говорит о том, что правило в стилях применяется ко всем элементам у которых атрибут ‘data-more-checker’ имеет значение, начинающееся как ‘read-more’. Т.е. применяется к всем атрибутам ‘data-more-checker’ со значениями ‘read-more’, ‘read-more-2’, ‘read-more-3’ и т.п.
Всю голову сломал, как же сделать, чтобы после нажатия на кнопку Развернуть форма не прыгала вниз по экрану. Это происходит лишь тогда когда желтая форма находится в верхней части экрана.
Имеете в виду если раскрывающийся блок находится в самом верху, то при клике на Раскрыть страница прокручивается так что этот желтый блок становится по середине?
Интересно, конечно.
Если придумаете, то пишите 🙂
Решил вопрос, заменив у .limiter .bottom absolute на sticky
Все удачи все))
Спасибо, всё супер, но возникла проблема. Если на странице несколько разворачивающихся блоков, то когда разворачиваешь верхний, то разворачиваются и те, что ниже. Как этого избежать?
Если есть несколько таких блоков, то у них должны быть разные class, id и for ‘read-more-checker’. Например, для первого блока используем class, id, for — «read-more-checker«. Для второго — ‘read-more-checker-2′, третьего — ‘read-more-checker-3′ и т.д. А в стилях нужно продублировать все правила где есть класс ‘read-more-checker’ через запятую.
Например, у нас было с одним блоком такое правило:
.read-more-checker:checked ~ .limiter {..
с двумя это будет так:
.read-more-checker:checked ~ .limiter,
.read-more-checker-2:checked ~ .limiter {..
Если не получится разобраться, то напишите — я тогда в статью этот случай добавлю.
Обновил статью — добавил решение для нескольких блоков через пользовательские атрибуты data-.
Спасибо за быстрый и подробный ответ, всё работает!
Ага и спойлер под ним не работает из-за позиции absolute у .limiter .bottom
Пришлось убрать синею шторку жаль((
Что за спойлер? Вроде же все работает.
А как сделать, чтобы это работало в ленте Ajax Load More?
При установке Вашего кода открывается как надо только самая верхняя новость в ленте, а все последующие перебрасывают опять к ней. Как бы сделать, чтобы каждый свое открывал.
Была такая мысль, чтобы read-more-2, read-more-3 и т.д. работали не на одной, а каждый на своей странице, но как это сделать — не знаю.
На сколько понял, вы делаете по Решению 1, но у вас несколько элементов где скрываете текст.
Нужно делать по Решению 2.
И по решению 1 делал и по решению 2 — не работает, как надо. И по решению 2 — все номера собираются на одной странице-записи. А у меня бесконечная прокрутка записей, каждая со своим урл. И как сделать, чтобы каждый последующий номер ( read-more-2 и далее) открывался на своей странице (записи) — отдельно.
Возможно и это не решение. Но стоит попробовать.
Еще раз — хочется, чтобы все работало, как по решению 1, но каждый на своей странице. И может быть поможет решение 2. Но как его раскинуть по ленте?
Спасибо за статью, очень помогла, только один вопрос, под кнопкой спрятан очень большой текст, и при нажатии «Развернуть» мы перемещаемся в конец текста, как бы убрать это перемещение?)
решение с заметной свойства position к сожалению не спасает
В этой статье, в примере стоит
.limiter .bottom {position: absolute; }
и у меня при развертывании не прыгает (текст я черз консоль браузера в html добавил много), а прыгает при свертывании вверх.У вас в этой статье прыгает вниз или только на вашем проекте? Вот выше человек пробовал
position: sticky;
. Но этот параметр ‘sticky’ работает как-то с нюансами. Честно говоря, уже не вспомню… Помню, делал как-то прилипающий блок на сайте сposition: sticky;
и там как-то оно то работало, то — нет, в зависимости от свойств родительских элементов.