css: div с текстом накладываются один на другой, вместо того, чтобы располагаться один под другим
Приветствую подскажите в чём может быть проблема: есть вот такой html код (https://jsfiddle.net/vtfdm2yh/):
.line < position: relative; width: 500px; min-height: 27px; margin: 5px 0px 0px 0px; padding: 0px; font-size: 18px; background: orange; border: 1px solid black; >.line>div:first-child:not(:only-child) < position: absolute; left: 0px; width: 150px; background: red; >.line>div:last-child
очень длинный текст который займёт несколько строк text #2 text #3 text #4
Ожидал, что будет выглядеть так:
текст1-текст2 текст3-текст4
Но почему-то происходит наложение одной строки текста (нижней) на другую (верхнюю), хотя должна быть сначала одна строка (верхняя), потом 5px пробел, потом вторая строка (нижняя). В чем проблема, почему так не выводится?
Отслеживать
14.5k 6 6 золотых знаков 33 33 серебряных знака 71 71 бронзовый знак
задан 22 ноя 2017 в 21:18
37.2k 4 4 золотых знака 27 27 серебряных знаков 70 70 бронзовых знаков
6 ответов 6
Сортировка: Сброс на вариант по умолчанию
Это реализовано на FLEX-х
.line < display:flex; flex-direction:row; width: 500px; min-height: 27px; height: auto; margin: 5px 0px 0px 0px; font-size: 18px; background: orange; border: 1px solid black; /*padding чтобы ты видел что родитель растягивается*/ padding:5px; >.line>div:first-child < width: 150px; background: red; >.line>div:last-child
очень длинный текст который займёт несколько строк text #2 text #3 text #4
Отслеживать
ответ дан 22 ноя 2017 в 22:03
14.5k 6 6 золотых знаков 33 33 серебряных знака 71 71 бронзовый знак
Да, мой косяк, я не совсем точно описал. 1) высота родительского блока МИНИМУМ 27px (min-height), т.е. если внутри будут дочерние блоки меньшей высоты, родительский блок все равно должен быть 27px 2) может оказаться, что дочерний блок больше 27px и тогда родительский блок должен быть такой же высоты как и дочерний блок максимальной высоты 3) если в дочернем блоке есть текст, он должен переноситься на следующую строку (т.е. многострочный текст) 4) между последовательными соседними родительскими блоками должен быть промежуток 5px (делалось через margin)
23 ноя 2017 в 9:00
5) ВАЖНО. (пока вообще не знаю как сделать, так что надеюсь люди подскажут) — если высота дочерних блоков меньше 27px, то выравнивать по вертикали (middle) в родительском блоке, который 27px
23 ноя 2017 в 9:08
Вот так ты хотел реализовать? посмотри ответ
23 ноя 2017 в 9:08
И еще, у тебя столько вопросов, а ты даже ни один ответ не принял.. Не красиво оставлять людей без внимания, тебе же помогают. Поверь, я не ради своего ответа пекусь. А вообще.. Если тебя ответ удовлетворяет, рядом с ответом есть галочка серая, которую нажав ты примешь ответ и она станет зеленой.
23 ноя 2017 в 9:16
Air, да я толком еще форумом пользоваться не умею. Спасибо за совет
23 ноя 2017 в 12:22
.line < width: 500px; margin: 5px 0px 0px 0px; padding: 0px; font-size: 18px; background: orange; border: 1px solid black; clear:both; >.line>div:first-child:not(:only-child) < width: 150px; background: red; float: left; margin-bottom: 5px; >.line>div:last-child
очень длинный текст который займёт несколько строк text #2 text #3 text #4
Отслеживать
ответ дан 22 ноя 2017 в 21:56
Дмитрий Полянин Дмитрий Полянин
13.6k 1 1 золотой знак 20 20 серебряных знаков 51 51 бронзовый знак
Дмитрий, действительно ‘clear’ частично решил проблему (у меня раньше был float, но без clear), потом заменил на position, left, right чтобы избавиться от некоторых проблем. Но даже твой способ до конца не решил проблему — хотя наложения не происходит, но и пробел в 5px между линиями не появился (задается через margin)
23 ноя 2017 в 5:58
обновил решение, margin-bottom надо установить у дочерних div -ов
23 ноя 2017 в 7:29
Дмитрий! Выглядит почти как задумывалось. Спасибо. НО! есть 1 маленькая ошибка — внутренний div оказывается (когда много текста) по высоте больше, чем родительский div . т.е. если делать задний фон и границы не прозрачными, то это будет видно сразу, т.е. все таки хотелось бы, чтоб внутренние divы были целиком во внешнем
23 ноя 2017 в 8:48
Проблема решается, но потребуется 15-20 строк кода. Я бы порекомендовал бы использовать лучше таблицу
Это лишь пример и нуждается в доработке.
Отслеживать
ответ дан 22 ноя 2017 в 21:29
Antonio112009 Antonio112009
2,641 1 1 золотой знак 19 19 серебряных знаков 44 44 бронзовых знака
Нет, вопрос именно про изменение только стилей. С изменением структуры html все понятно — тут вопросов бы не возникло. А так непонятно, почему происходит наложение и что с этим делать.
23 ноя 2017 в 5:53
.line < position: relative; width: 500px; min-height: 27px; margin: 5px 0px 0px 0px; padding: 0px; font-size: 0; background: orange; border: 1px solid black; >.line>div:first-child:not(:only-child) < position: relative; left: 0px; width: 150px; background: red; display:inline-block; font-size:18px; vertical-align:top; >.line>div:last-child
очень длинный текст который займёт несколько строк text #2 text #3 text #4
Отслеживать
ответ дан 23 ноя 2017 в 7:37
2,290 2 2 золотых знака 15 15 серебряных знаков 30 30 бронзовых знаков
все заработало НО! перестал работать :not(:only-child) (jsfiddle.net/4gv351q0) А ведь хочу, что если только один дочерний , то он позиционируется справа (тут помогло бы position: absolute, но тогда твое решение перестает работать)
23 ноя 2017 в 8:37
А если несколько дочерних элементов, тогда что?
23 ноя 2017 в 9:46
предполагается, что их будет только 2 (1 или 2)
23 ноя 2017 в 12:15
По результатам ответов выделил решения, которые работают
1) метод, предложенный Air
.line < display:flex; flex-direction:row; width: 500px; min-height: 27px; height: auto; margin: 5px 0px 0px 0px; font-size: 18px; background: orange; border: 1px solid black; /*padding чтобы ты видел что родитель растягивается*/ padding:5px; >.line>div:first-child < width: 150px; background: red; >.line>div:last-child
- дочерние элементы занимают 100% высоты от родительского элемента
- свойство flex не полностью поддерживается браузером IE (только 11 версией и то не до конца)
2) метод, предложенный DaemonHK:
использование в дочерних div свойства font-size, position, vertical-align, использование в родительском свойства font-size: 0px: https://jsfiddle.net/o88pfdqr/
.line < position: relative; width: 500px; min-height: 27px; margin: 5px 0px 0px 0px; padding: 0px; font-size: 0; background: orange; border: 1px solid black; >.line>div:first-child:not(:only-child) < position: relative; left: 0px; width: 150px; background: red; display:inline-block; font-size:18px; vertical-align:top; >.line>div:last-child
- перестало работать выравнивание справа для одного элемента (https://jsfiddle.net/o88pfdqr/1/)
- использование font-size для дочерних элементов и обнуление его для родительского элемента
3) метод, предложенный Дмитрием Поляниным:
использование в дочерних элементах flex, а в родительском clear: https://jsfiddle.net/o88pfdqr/4/
.line < width: 500px; margin: 5px 0px 0px 0px; padding: 0px; font-size: 18px; background: orange; border: 1px solid black; clear:both; >.line>div:first-child:not(:only-child) < width: 150px; background: red; float: left; margin-bottom: 5px; >.line>div:last-child
- теряется высота родительского элемента, т.е. дочерний элемент может стать больше родительского по высоте
Общий вывод:
Наилучший способ, как мне кажется, у AIR, но меня пугает flex своей несовместимостью (надо протестировать), при том, что я реально взаимодействую с людьми у которых чуть ли не IE6 стоит 🙂 (утрирую немного)
Есть еще одна проблема-вопрос
Дополнительно я хотел бы обеспечить следующий функционал (тоже только листами стилей без привлечения дополнительных тегов):
если высота дочерних блоков меньше 27px, то выполняется выравнивать дочерних элементов по вертикали (middle) в родительском блоке, который 27px, а если хотя бы 1 дочерний элемент больше по высоте 27px, то выравнивание выполняется по top
расположение div один под другим
У меня есть два внутренних div, которые вложены внутри div оболочки. Я хочу, чтобы два внутренних div были расположены один под другим. Но сейчас они устраиваются по одной линии.
#wrapper < margin-left:auto; margin-right:auto; height:auto; width:auto; >#inner1 < float:left; >#inner2
user544079 15 апр. 2011, в 04:21
Поделиться
Почему вы отпустили их влево, если хотите, чтобы они были один под другим? Просто удалите свойства float и все в порядке.
enguerranws 21 фев. 2014, в 18:15
Поделиться:
4 ответа
Лучший ответ
Попробуйте очистить: слева на # inner2. Поскольку оба они установлены на float, это должно привести к возврату строки.
#inner1 < float:left; >#inner2
Kyle Rogers 15 апр. 2011, в 03:27
Поделиться
Если вы хотите, чтобы два div отображались один над другим, самым простым ответом является удаление float: left; из объявления css, поскольку это приводит к их сглаживанию до размера их содержимого (или css определенный размер), и, будьте осторожны друг с другом.
В качестве альтернативы вы можете просто добавить clear:both; в div s, что заставит плавающий контент очистить предыдущие поплавки.
David Thomas 15 апр. 2011, в 01:52
Поделиться
Поведение по умолчанию для divs — это получение полной ширины в родительском контейнере. Это то же самое, что если бы вы дали внутренним divs ширину 100%.
Поляв divs, они игнорируют их значение по умолчанию и определяют их ширину, чтобы они соответствовали содержимому. Все, что находится за ним (в HTML), помещается под div (на отображаемой странице).
Именно по этой причине они выстраиваются рядом друг с другом.
Свойство float CSS указывает, что элемент должен быть взят из нормальный поток и помещенный вдоль левой или правой стороны его контейнер, где текст и встроенные элементы будут обтекать его. плавающий элемент — это тот, где вычисленное значение float не равно.
Избавьтесь от float, и divs будут выровнены друг под другом.
Если этого не произойдет, у вас будет еще один css для div или дочерних оболочек, определяющих плавающее поведение или встроенный дисплей.
Если вы хотите сохранить float, по какой-то причине вы можете использовать clear для второго div для reset плавающие свойства элементов перед этим элементом.
clear имеет 5 действительных значений: none | left | right | both | inherit . Очистка без поплавков (используется для переопределения унаследованных свойств), поплавки влево или вправо или оба поплавка. Inherit означает, что он наследует поведение родительского элемента
Кроме того, из-за поведения по умолчанию вам не нужно устанавливать ширину и высоту на авто.
Вам нужно только это, вы хотите установить жестко заданную высоту/ширину. Например. 80%/800px/500em/.
#wrapper < margin-left:auto; margin-right:auto; height:auto; // this is not needed, as parent container, this div will size automaticly width:auto; // this is not needed, as parent container, this div will size automaticly >/* You can get rid of the inner divs in the css, unless you want to style them. If you want to style them identicly, you can use concatenation */ #inner1, #inner2
Как один элемент разместить под другим css
Позиционированием называется положение элемента в системе координат. Различают четыре типа позиционирования: нормальное, абсолютное, фиксированное и относительное. В зависимости от типа, который устанавливается через свойство position , изменяется и система координат.
Благодаря комбинации свойств position , left , top , right и bottom элемент можно накладывать один на другой, выводить в точке с определёнными координатами, фиксировать в указанном месте, определить положение одного элемента относительно другого и др. Подобно другим свойствам CSS управление позиционированием доступно через скрипты. Таким образом, можно динамически изменять положение элементов без перезагрузки страницы, создавая анимацию и различные эффекты.
Нормальное позиционирование
Если для элемента свойство position не задано или его значение static , элемент выводится в потоке документа как обычно. Иными словами, элементы отображаются на странице в том порядке, как они идут в исходном коде HTML.
Свойства left , top , right , bottom если определены, игнорируются.
Абсолютное позиционирование
При абсолютном позиционировании элемент не существует в потоке документа и его положение задаётся относительно краёв браузера. Задать этот тип можно через значение absolute свойства position . Координаты указываются относительно краёв окна браузера, называемого «видимой областью» (рис. 3.42).
Рис. 3.42. Значения свойств left, right, top и bottom при абсолютном позиционировании
Для режима характерны следующие особенности.
- Ширина слоя, если она не задана явно, равна ширине контента плюс значения полей, границ и отступов.
- Слой не меняет своё исходное положение, если у него нет свойств right , left , top и bottom .
- Свойства left и top имеют более высокий приоритет по сравнению с right и bottom . Если left и right противоречат друг другу, то значение right игнорируется. То же самое касается и bottom .
- Если left задать отрицательное значение, то слой уйдёт за левый край браузера, полосы прокрутки при этом не возникнет. Это один из способов спрятать элемент от просмотра. То же относится и к свойству top , только слой уйдёт за верхний край.
- Если left задать значение больше ширины видимой области или указать right с отрицательным значением, появится горизонтальная полоса прокрутки. Подобное правило работает и с top , только речь пойдёт о вертикальной полосе прокрутки.
- Одновременно указанные свойства left и right формируют ширину слоя, но только если width не указано. Стоит добавить свойство width и значение right будет проигнорировано. Аналогично произойдёт и с высотой слоя, только уже участвуют свойства top , bottom и height .
- Элемент с абсолютным позиционированием перемещается вместе с документом при его прокрутке.
Свойство position со значением absolute можно использовать для создания эффекта фреймов. Кроме абсолютного позиционирования для элементов необходимо назначить свойство overflow со значением auto . Тогда при превышении контентом высоты видимой области появится полоса прокрутки. Высота и ширина «фреймов» формируется автоматически путём одновременного использования свойств left , right для ширины и top , bottom для высоты (пример 3.31).
Пример 3.31. Создание аналога фреймов
XHTML 1.0 CSS 2.1 IE Cr Op Sa Fx
Результат данного примера показан на рис. 3.43. Слой header выводится в потоке как обычно, а для слоёв sidebar и content установлено абсолютное позиционирование.

Рис. 3.43. Применение абсолютного позиционирования
В браузере IE6 для абсолютно позиционированных элементов нельзя одновременно задать свойства left , right и top , bottom .
Абсолютное позиционирование также применяется для создания различных эффектов, например, всплывающей подсказки к фотографиям. В отличие от атрибута title тега который также выводит текст подсказки, через стили можно управлять видом текста выводимого с помощью скрипта.
Для начала создадим пустой слой с идентификатором floatTip и определим его стиль. Обязательными должны быть три стилевых свойства — position со значением absolute , display со значением none скрывает слой и width задаёт ширину слоя с подсказкой. Остальные свойства используются по желанию разработчика и предназначены для изменения оформления слоя (пример 3.32).
Пример 3.32. Стиль для всплывающей подсказки
Сам скрипт состоит из двух функций — moveTip() отслеживает движение мыши и в соответствии с координатами курсора меняет положение слоя, и toolTip() управляет видимостью слоя и выводит в нём желаемый текст (пример 3.33).
Пример 3.33. Скрипт для вывода слоя
Для удобства и универсальности скрипт следует вынести в отдельный файл и подключать его через атрибут src тега . Окончательный код показан в примере 3.34.
Пример 3.34. Создание всплывающей подсказки
XHTML 1.0 CSS 2.1 CSS 3 IE 7+ IE 9+ Cr Op Sa Fx
Результат данного примера показан на рис. 3.44. Обратите внимание, что переносы текста при вызове функции toolTip() сделаны для удобства восприятия и имеют синтаксис JavaScript. В Safari скрипт иногда не работает при переносе текста, в этом случае текст следует записать в одну строку. К стилям добавлено свойство CSS3 opacity , которое добавляет для слоя небольшую прозрачность. В IE до версии 9.0 это свойство не поддерживается.

Рис. 3.44. Всплывающая подсказка, выводимая с помощью JavaScript
Фиксированное положение
Фиксированное положение слоя задаётся значением fixed свойства position и по своему действию похоже на абсолютное позиционирование. Но в отличие от него привязывается к указанной свойствами left , top , right и bottom точке на экране и не меняет своего положения при прокрутке веб-страницы. Ещё одна разница от absolute заключается в том, что при выходе фиксированного слоя за пределы видимой области справа или снизу от неё, не возникает полос прокрутки.
Применяется такой тип позиционирования для создания меню, вкладок, заголовков, в общем, любых элементов, которые должны быть закреплены на странице и всегда видны посетителю. В примере 3.35 показано добавление подвала, который остаётся на одном месте независимо от объёма информации на сайте.
Пример 3.35. Фиксированный подвал
XHTML 1.0 CSS 2.1 IE Cr Op Sa Fx
Результат примера показан на рис. 3.45. Поскольку фиксированный подвал накладывается на текст и скрывает его, добавлен отступ снизу для селектора BODY . Браузер IE6 не поддерживает значение fixed , поэтому в нём данный пример будет работать некорректно.

Рис. 3.45. Подвал внизу страницы
Относительное позиционирование
Если задать значение relative свойства position , то положение элемента устанавливается относительно его исходного места. Добавление свойств left , top , right и bottom изменяет позицию элемента и сдвигает его в ту или иную сторону от первоначального расположения. Положительное значение left определяет сдвиг вправо от левой границы элемента, отрицательное — сдвиг влево. Положительное значение top задаёт сдвиг элемента вниз (рис. 3.46), отрицательное — сдвиг вверх.

Рис. 3.46. Значения свойств left и top при относительном позиционировании
Свойства bottom и right производят обратный эффект. При положительном значении right сдвигает элемент влево от его правого края, при отрицательном — сдвигает вправо (рис. 3.47). При положительном значении bottom элемент поднимается вверх, при отрицательном опускается вниз.

Рис. 3.47. Значения свойств right и bottom при относительном позиционировании
Для относительного позиционирования характерны следующие особенности.
- Этот тип позиционирования не применим к элементам таблицы вроде ячеек, строк, колонок и др.
- При смещении элемента относительно исходного положения, место, которое занимал элемент, остаётся пустым и не заполняется ниже или вышележащими элементами.
В примере 3.36 показан сдвиг текста заголовка вниз для придания ему особого стиля написания.
Пример 3.36. Заголовок текста
XHTML 1.0 CSS 2.1 IE Cr Op Sa Fx
Результат данного примера показан на рис. 3.48.

Рис. 3.48. Сдвиг текста относительно исходного положения
Вложенные слои
Обычно относительное позиционирование само по себе применяется не часто, поскольку есть ряд свойств выполняющих фактически ту же роль, к примеру, тот же margin . Но сочетание разных типов позиционирования для вложенных слоёв является одним из удобных и практичных приёмов вёрстки. Если для родительского элемента задать relative , а для дочернего absolute , то произойдёт смена системы координат и положение дочернего элемента при этом указывается относительно его родителя (рис. 3.49).

Рис. 3.49. Значения свойств left, right, top и bottom во вложенных слоях
Отсчёт координат ведётся от внутреннего края границы, значения полей не учитываются. В следующем примере текст располагается в правом нижнем углу слоя возле границы, игнорируя свойство padding .
Благодаря использованию четырёх свойств left , right , top , bottom для управления положением внутреннего слоя, размеры родительского слоя знать не обязательно. Это расширяет сферу применения позиционирования, поэтому position довольно активно применяется при вёрстке различных элементов. В качестве примера возьмём наложение на фотографию разной информации: количество комментариев к ней, ссылки «Добавить комментарий», «Информация об авторе» и «Добавить в избранное». В целом, результат должен быть примерно таким, как на рис. 3.50.

Рис. 3.50. Фотография с наложенными элементами
Сам код приведён в примере 3.37. Для слоя photo установлено относительное позиционирование, а для внутренних слоёв img (вывод фотографии), comment (число комментариев) и tool (ссылки внизу фотографии) задано абсолютное позиционирование.
Один элемент под другим без Position: absolute?
Привет, подскажите как сверстать один элемент под другим, что-бы родительский блок сохранил высоту?
P.S. сделал маской прозрачного изображения, мб есть ещё какие варианты?
вот так можно сделать, через float, не уверен насчет какие браузеры это поддерживают.
z-index ввел просто чтобы в условие попасть (как я понял вторая должна быть под первой)
Всё ещё ищете ответ? Посмотрите другие вопросы с метками html css или задайте свой вопрос.
Site design / logo © 2022 Stack Exchange Inc; user contributions licensed under cc by-sa. rev 2022.4.14.41981
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
Выстроить блоки один под другим
Здравствуйте. Для закрепления теории решил сделать простенькое меню, которое бы перекидывало с помощью кнопок на нужные поисковые системы(скрин).
1) Как сделать эти элементы один под другим, а не в ряд?
2) Дайте рекомендации по оптимизации кода.
Почему блоки на одном уровне, должны быть один под другим
Подскажите, пожалуйста, у меня блок класса menuDiv должен быть под классом headerDiv. Сейчас они на.

Расположить блоки разной высоты один под другим, в несколько столбцов
Добрый день. Есть блоки разной высоты. Нужно расположить их один под другим в несколько.

Как из ДИВ-блоков верстают сайты с двумя и более колонками, ведь по умолчанию ДИВ-блоки располагаются один под другим?
Большинство сайтов имеют боковые колонки (так называемые сайтбары), как их делают с помощью блочной.
Как сделать один фон под другим
Скрин макета — Мне нужно что бы один фон был под другим выше ссылка на скрин макета <!DOCTYPE.
CSS позиционирование блоков
Позиционирование блоков css один из важнейших этапов верстки, потому что именно это влияет на адаптивность сайта или на возможность её реализации в дальнейшем (если на данный момент не требуется), а так же оказывает значительное влияние на дальнейшее масштабирование сайта. Не редки случаи когда «горе-верстальщики» делают такую верстку, что в итоге её проще выкинуть чем что то изменить, но при это она может выглядеть полностью в соответствии с макетом. Данная ситуация возникает из за не понимания где и когда использовать тот или иной тип позиционирования. Сегодня мы попробуем разобраться в данном вопросе. И так, в css существует свойство position. Данное свойство может принимать 5 значений, но мы рассмотрим 4 основных:
Абсолютное позиционирование блоков (absolute)
Первый, в нашем списке, способ позиционирование — это абсолютное. При назначении данного свойства, блок становится самостоятельно единицей и остальные элементы страницы не влияют на его расположение, а так же и он не влияет на другие элементы. Размер блока определяется свойствами width и height, а расположение на странице — свойствами top. left, right и bottom эти параметры задают отступы от верхнего, левого, правого и нижнего края. Если у блока нет родительского элемента, а так же если позиционирование родительского элемента отлично от static, то top, left, bottom, right свойства задают отступы от начала страницы, в противном случае от краев родительского элемента.
Чаще всего данный вид позиционирования используется, когда блок нужно прижать к правому или нижнем краю. Рассмотрим такой макет.

Для удобства блоки были выделены разноцветно рамкой. Разметка будет выглядеть следующим образом:
Похожие публикации:
- Как сделать калькулятор в visual basic
- Как сделать картинку фоном css
- Как сделать кнопку круглой css
- Как сделать круг css
Плиточная раскладка на CSS Flexbox с помощью order и :nth-child()
Эта статья показывает то, как сделать плиточную раскладку на CSS Flexbox, имея под рукой только стандартные возможности CSS и ничего более. Она хороша тем, что показывает подводные камни работы с флексами и даёт понять суть их работы с другого ракурса.
Мой Твиттер — там много из мира фронтенда, да и вообще поговорим. Подписывайтесь, будет интересно: ) ✈️
С первого взгляда это кажется довольно простым, взять и создать плиточную раскладку на флексах. Всё, что нужно, это всего лишь выставить flex-flow на column wrap и вуаля, у вас то что нужно. Ну типа того. Проблема с таким подходом в том, что он создает сетку с на вид перетасованным и неясным порядком. Элементы будут отрендерены сверху вниз и люди, смотрящие на сетку слева направо будут читать боксы в примерно таком, довольно произвольном виде, к примеру 1, 3, 6, 2, 4, 7, 8, 5 и так далее и т.п .
У флексов нет простого способа отрендерить элементы в виде колоночной раскладки, используя строчную расстановку элементов, но мы всё же можем сделать плиточную раскладку только на CSS — без JavaScript — используя свойства :nth-child() и order . По сути, это трюк с созданием строчной расстановки элементов, используя flex-direction: column , учитывая то, что мы рендерим 3 колонки:
/* Рендерим элементы как колонки */
.container display: flex;
flex-flow: column wrap;
>
/* Меняем порядок элементов, делая как бы строчную расстановку */
.item:nth-child(3n+1) < order: 1; >
.item:nth-child(3n+2) < order: 2; >
.item:nth-child(3n) < order: 3; >
/* Новые колонки разделители */
.container::before,
.container::after content: "";
flex-basis: 100%;
width: 0;
order: 2;
>
Это создаст плиточную раскладку с элементами, отрендереными как колонки, но расставленными в порядке, как было бы в строчном порядке. Серые вертикальные линии это псевдоэлементы, которые делают переносы строк.
Давайте разберем проблему (ну или перейдите к её решению в конце статьи или к codepen).
Выбирайте каким будет косяк: смешанным порядком или странными промежутками
Flexbox по факту не создан для построения плиточных раскладок — если вы выставите фиксированную высотку на флекс-контейнере и flex-flow на column wrap , то у вас получится что-то типа такого:
Тут элементы отрендерены по колонкам сверху вниз, создавая произвольный порядок во время чтения слева направо. Конечно же, это ожидаемый итог и желаемый во многих случаях, но не тогда, когда мы пытаемся создать именно плиточную раскладку. Вы только представьте насколько это дезориентирует читателя, когда страница станет больше в высоту.
Если же мы сменим flex-direction на row , имея элементы с различными высотами, то мы получим правильный порядок, но уже со стрёмными и неожиданными разрывами по все нашей сетке:
Так, что, кажется невозможным воспользоваться преимуществами обоих подходов: получить элементы отрендеренные как колонки, но имеющие строчный порядок. Вы могли прибегнуть к flex-direction: column и просто переставить элементы в HTML, достигнув правильного визуального порядка, но это может быть очень громоздко, к тому же это излишне сложно и создаст неразбериху в логическом порядке при переходах по клавише табуляции (Просто кликая по табу).
Меняем порядок элементов с помощью order и nth-child()
Свойство order влияет на порядок элементов в CSS Flexbox или гриде, и мы можем смело использовать его для смены порядка элементов в нашей плиточной раскладке, которая вот вот уже будет сделана как мы хотим. Свойство order довольно простое в использовании: если у вас два элемента и у одного стоит order: 1 , а у другого order: 2 , то элемент с order: 1 будет орендерен перед другим элементом, вне зависимости от их порядка в HTML исходнике.
В нашем случае, решение зависит от тонкостей спецификации order : что случится, если два или более элементов будут с одинаковым order ? Какой из них будет первым? В этом случае, flexbox опирается на исходный код: тот элемент, который идет первым в исходном HTML коде, будет отрендерен перед другим элементом с таким же значением order . Это даёт нам возможность легко перегруппировать элементы в сетке таким образом, что мы сможем сменить порядок расстановки элементов с колоночного на строчный, всё ещё рендеря эти строки, как колонки, используя nth-child() .
Посмотрите на табличку ниже. Чтобы получить рациональный порядок с использованием flex-direction: row , нам просто надо отрендерить элементы в стандартном порядке: 1, 2, 3, 4, 5, 6, и т.д .
Но если нам надо получить тот же порядок с использованием flex-direction: column , то тогда уже нам понадобится поменять сам порядок элементов, таким образом, чтобы он соответствовал порядку каждой колонки в таблице (а не каждой строки):
То есть первыми элементами в нашей флексбокс раскладке должны 1, 4, 7, 10 . Эти элементы заполнят первую колонку, далее 2, 5, 8, 11 для второй колонки и 3, 6, 9, 12 для третьей и последней колонки. Тут нам на помощь приходит селектор nth-child() . Мы можем его использовать для того, чтобы выделить каждый третий элемент (3n) , начиная с первого элемента (3n + 1) и выставить всем этим элементам одинаковое значение order :
.item:nth-child(3n+1)
Этот селектор выставит order: 1 для элементов 1, 4, 7, 10 , то есть всем первым колонкам. Другими словами, мы используем комбинацию nth-child() и order , чтобы изменить порядок элементов на их изначальном положении. Чтобы создать 2 и 3 колонки, мы изменим порядок у других элементов:
.item:nth-child(3n+1) < order: 1; >
.item:nth-child(3n+2) < order: 2; >
.item:nth-child(3n) < order: 3; >
Тут мы делаем три группы элементов: 1, 4, 7, 10 (3n+1) c order: 1 , далее 2, 5, 8, 11 (3n+2) с order: 2 и 3, 6, 9, 12 (3) . Всё вместе выдаёт нам такой порядок элементов 1, 4, 7, 10, 2, 5, 8, 11, 3, 6, 9, 12 .
Такой подход создаст иллюзию того, что элементы вернулись к своему изначальному порядку, как если бы вы рассматривали их в порядке слева направо. Если бы мы визуально оценивали эту сетку по строкам, то первая строка включала бы по первому элементу с каждой группы (1, 2, 3) , вторая строка содержала бы каждый второй элемент из каждой группы (4, 5, 6) и так далее и т.п. Используя эту технику мы можем создать плиточную раскладку с элементами, отрендеренными как колонки, но имеющими порядок как было бы в строчном варианте.
А как это влияет на переходы с использованием табов? Да никак. Свойство order меняет только визуальное представление объектов, а не порядок переходов по клавише TAB, так что в этом плане всё будет работать, как и предполагается.
Предотвращаем слияние колонок
Если у вас довольно много элементов в раскладке, то этот подход 100% приведёт к тому, что что-то пойдет не так. Мы делаем расчёт на то, что каждая “группа”, которую мы создали, будет отрендерена ровно как одна колонка в контейнере, но в реальности у элементов могут быть разные высоты и колонки с лихвой могут сливаться друг с другом. Первая колонка может быть длиннее, чем другие две, для примера, что привело бы к тому, что третья колонка начиналась бы в конце второй:
Подсвеченный элемент (3) должен быть отрендерен в начале третьей колонки или же алгоритм расстановки попросту полетит в тартарары, и если есть место для ещё одного элемента в конце второй колонки, то он само собой будет отрендерен там.
Мы можем пофиксить эту проблему, заставив колонки рестартиться в указанные моменты. Вообще, с флексбоксами нет простого способа для указания “этот элемент должен перейти на новую строку”, но мы можем достигнуть этого эффекта, добавив невидимые элементы, которые возьмут 100% высоты контейнера. Так как они требуют 100% высоты родителя, то они не поместятся в колонку вместе с любым другим элементом, создавая тем самым, переходы на новые строки.
Нам нужно вставить такие переходы в сетку и массив элементов, таким образом, чтобы у нас получилась такая последовательность: 1, 4, 7, 10,, 2, 5, 8, 11,, 3, 6, 9, 12 . Мы можем использовать псевдоэлементы на контейнере, чтобы добавить такие переходы и мы можем выставить order на 2 обоим. Добавление псевдоэлемента :before, сделает его первым потомком контейнера, а добавление псевдоэлемента :after сделает его последним потомком того же контейнера, так что если мы выставим order: 2 каждому из них, то они станут первым и последним элементом “группы” с order: 2 (так как они находятся до и после других элементов): :before, 2, 5, 8, 11, :after .
/* Новые колонки разделители */
.container::before,
.container::after content: "";
flex-basis: 100%;
width: 0;
order: 2;
>
Я подсветил псевдоэлементы ниже, чтобы показать их эффект. Обратите внимание, что элемент 3 мог бы попасть во вторую колонку, но он отображается как первый элемент в последней:
Решение
И в конце вам надо убедиться в том, что ваш флекс-контейнер имеет высоту выше, чем ваша самая высокая колонка (чтобы все колонки поместились). Теперь всё это совместите и так вы сможете сделать настоящую трехколоночную плиточную раскладку (вот codepen).
.container display: flex;
flex-flow: column wrap;
align-content: space-between;
/* Вашему контейнеру нужна фиксированная высота
* и он должен быть выше, чем самая высокая колонка. */
height: 600px;
>
.item width: 32%;
margin-bottom: 2%; /* Optional */
>
/* Перегруппировываем элементы в 3 ряда */
.item:nth-child(3n+1) < order: 1; >
.item:nth-child(3n+2) < order: 2; >
.item:nth-child(3n) < order: 3; >
/* Новые колонки разделители */
.container::before,
.container::after content: "";
flex-basis: 100%;
width: 0;
order: 2;
>
Ваш html должен выглядеть примерно так, где div это каждый элемент в сетке:
Работаем с более, чем тремя колонками
Чтобы создать плиточную раскладку с более, чем тремя колонками, нам надо сделать несколько вещей: адаптировать наш алгоритм сортировки, обновить ширину элементов и вставить переходы на новые строки вручную (вместо использования псевдоэлементов). Для быстрого доступа к конечным результатам я собрал список codepen’ов показывающих плиточную раскладку на флексах для 3, 4, 5 и 6 колонок.
До этого мы были ограничены созданием только двух псевдоэлементов с :before и :after , теперь нам нужно прибегнуть к ручному добавлению переходов на новые строки внутри контейнера (вам требуется на один элемент-разделитель меньше, чем количество колонок в вашей раскладке). Вы можете просто вставить их в конец контейнера и они будут отсортированы по соответствующим колонкам:
Мы вставляем разделители колонок как span, для того, чтобы отсортировать их в независимости от элементов контента. Нам нужен способ сбросить счет после того, как мы достигнем элемент разделитель или неравномерное число элементов сделает старт первого разделителя после 3 колонки, к примеру. Селектор :nth-of-type выбирает элементы вне зависимости от их типа, так что мы можем разделить порядок элементов и разделители таким образом:
.item:nth-of-type(4n+1) < order: 1; >
.item:nth-of-type(4n+2) < order: 2; >
.item:nth-of-type(4n+3) < order: 3; >
.item:nth-of-type(4n) < order: 4; >
Разделители же, как и в предыдущем примере, возьмут всю высоту контейнера:
/* Переход к новой колонке */
.break flex-basis: 100%;
width: 0;
margin: 0;
>
В общем, это создаст плиточную колонку с 4-мя колонками (вот codepen):
Вот полное решение для CSS такой плиточной раскладки с 4-мя колонками:
.container display: flex;
flex-flow: column wrap;
align-content: space-between;
height: 600px;
>
.item width:24%;
margin-bottom: 2%; /* опционально */
>
.item:nth-of-type(4n+1) < order: 1; >
.item:nth-of-type(4n+2) < order: 2; >
.item:nth-of-type(4n+3) < order: 3; >
.item:nth-of-type(4n) < order: 4; >
.break flex-basis: 100%;
width: 0;
margin: 0;
>
Этот способ создания плиточной раскладки только средствами CSS, точно не является самым надежным, гибким или защищенным от внезапных косяков со стороны разработчика, в отличие от такого же исполнения на JavaScript (например Masonry), но если вы не хотите полагаться на сторонние библиотеки только для того, чтобы создать раскладку, то я надеюсь, что эти советы будут вам полезны.
