it-swarm.com.ru

Когда элементы flexbox переносятся в режиме столбца, контейнер не увеличивается в ширину

Я работаю над вложенным макетом flexbox, который должен работать следующим образом:

Самый внешний уровень (ul#main) представляет собой горизонтальный список, который должен расширяться вправо, когда в него добавляется больше элементов. Если он становится слишком большим, должна быть горизонтальная полоса прокрутки.

#main {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    overflow-x: auto;
    /* ...and more... */
}

Каждый элемент этого списка (ul#main > li) имеет заголовок (ul#main > li > h2) и внутренний список (ul#main > li > ul.tasks). Этот внутренний список является вертикальным и должен при необходимости переноситься в столбцы. При обтекании большего количества столбцов его ширина должна увеличиваться, чтобы освободить место для большего количества элементов. Это увеличение ширины должно применяться также к содержащемуся элементу внешнего списка.

.tasks {
    flex-direction: column;
    flex-wrap: wrap;
    /* ...and more... */
}

Моя проблема в том, что внутренние списки не переносятся, когда высота окна становится слишком маленькой. Я много пытался подделать все свойства flex, пытаясь следовать указаниям в CSS-Tricks тщательно, но безуспешно.

Это JSFiddle показывает, что я до сих пор.

Ожидаемый результат _ ​​(что я хочу):

My desired output

Фактический результат _ ​​(что я получу):

My current output

Более старый результат _ ​​(что я получил в 2015 году):

My older output

Обновление

После некоторого расследования это начинает выглядеть как большая проблема. Все основные браузеры ведут себя одинаково, и это никак не связано с тем, что мой дизайн flexbox является вложенным. Еще более простые макеты столбцов flexbox отказываются увеличивать ширину списка при переносе элементов.

Этот другой JSFiddle ясно демонстрирует проблему. В текущих версиях Chrome, Firefox и IE11 все элементы переносятся правильно; высота списка увеличивается в режиме row, но ширина не увеличивается в режиме column. Кроме того, при изменении высоты режима column немедленного перекомпоновки элементов не происходит, но это происходит в режиме row.

Тем не менее, официальные спецификации (посмотрите конкретно на пример 5) , похоже, указывают на то, что то, что я хочу сделать, должно быть возможным.

Может кто-нибудь придумать обходной путь к этой проблеме?

ОБНОВЛЕНИЕ 2

После многих экспериментов с использованием JavaScript для обновления высоты и ширины различных элементов во время событий изменения размера, я пришел к выводу, что это слишком сложно и слишком много проблем, чтобы попытаться решить эту проблему таким образом. Кроме того, добавление JavaScript определенно нарушает модель flexbox, которая должна быть максимально чистой.

Сейчас я возвращаюсь к overflow-y: auto вместо flex-wrap: wrap, чтобы внутренний контейнер прокручивался вертикально, когда это необходимо. Это не красиво, но это один из способов продвижения вперед, который, по крайней мере, не сильно нарушает удобство использования.

111
Anders Tornblad

Эта проблема

Это похоже на фундаментальный недостаток гибкого макета.

Гибкий контейнер в направлении столбцов не будет расширяться для размещения дополнительных столбцов. (Это не проблема в flex-direction: row.)

Этот вопрос задавался много раз (см. Список ниже), без четких ответов в CSS.

Трудно связать это с ошибкой, потому что проблема возникает во всех основных браузерах. Но это поднимает вопрос:

Как это возможно, что все основные браузеры получили гибкий контейнер для развернуть обтекание в направлении строки, но не в направлении столбца?

Можно подумать, что хотя бы один из них понял это правильно. Я могу только догадываться о причине. Возможно, это была технически сложная реализация, и она была отложена для этой итерации.

UPDATE: Проблема, похоже, решена в Edge v16.


Иллюстрация проблемы

ОП создал полезную демонстрацию, иллюстрирующую проблему. Я копирую это здесь: http://jsfiddle.net/nwccdwLw/1/


Варианты обхода

Хакерские решения от сообщества Stack Overflow:


Больше анализа


Другие сообщения, описывающие ту же проблему

119
Michael_B

Опоздал на вечеринку, но все еще сталкивался с этой проблемой ГОДАМИ позже. Закончилось поиском решения с использованием сетки. На контейнере вы можете использовать

display: grid;
grid-auto-flow: column;
grid-template-rows: repeat(6, auto);

У меня есть пример на CodePen, который переключается между проблемой flexbox и исправлением сетки: https://codepen.io/MandeeD/pen/JVLdLd

2
MandeeD

Поскольку решения или правильного обходного пути пока не предлагалось, мне удалось получить требуемое поведение с немного другим подходом. Вместо того, чтобы разделять макет на 3 разных элемента, я добавляю все элементы в 1 блок и создаю разделение с несколькими дополнительными элементами.

Предлагаемое решение жестко запрограммировано, предполагая, что у нас есть 3 раздела, но может быть расширено до общего. Основная идея состоит в том, чтобы объяснить, как мы можем достичь этого макета. 

  1. Добавление всех элементов в 1 контейнерный блок, который использует flex для упаковки элементов
  2. Первый элемент каждого «внутреннего контейнера» (я назову его разделом) будет иметь класс, который помогает нам выполнять некоторые манипуляции, которые создают разделение и стилизацию каждого раздела.
  3. Используя :before для каждого первого элемента, мы можем найти заголовок каждого раздела.
  4. Использование space создает разрыв между разделами
  5. Так как space не покрывает всю высоту раздела, я также добавляю :after к разделам, чтобы расположить его с абсолютной позицией и белым фоном.
  6. Чтобы стилизовать цвет фона каждого раздела, я добавляю еще один div внутри первого элемента каждого раздела. Я также буду с абсолютным положением и буду иметь z-index: -1.
  7. Чтобы получить правильную ширину каждого фона, я использую JS, устанавливаю правильную ширину, а также добавляю слушателя для изменения размера.

function calcWidth() {
  var size = $(document).width();
  var end = $(".end").offset().left;

  var todoWidth = $(".doing-first").offset().left;
  $(".bg-todo").css("width", todoWidth);

  var doingWidth = $(".done-first").offset().left - todoWidth;
  $(".bg-doing").css("width", doingWidth);

  var doneWidth = $(".end").offset().left - $(".done-first").offset().left;
  $(".bg-done").css("width", doneWidth + 20);

}

calcWidth();

$(window).resize(function() {
  calcWidth();
});
.container {
  display: flex;
  flex-wrap: wrap;
  flex-direction: column;
  height: 120px;
  align-content: flex-start;
  padding-top: 30px;
  overflow-x: auto;
  overflow-y: hidden;
}

.item {
  width: 200px;
  background-color: #e5e5e5;
  border-radius: 5px;
  height: 20px;
  margin: 5px;
  position: relative;
  box-shadow: 1px 1px 5px 0px rgba(0, 0, 0, 0.75);
  padding: 5px;
}

.space {
  height: 150px;
  width: 10px;
  background-color: #fff;
  margin: 10px;
}

.todo-first:before {
  position: absolute;
  top: -30px;
  height: 30px;
  content: "To Do (2)";
  font-weight: bold;
}

.doing-first:before {
  position: absolute;
  top: -30px;
  height: 30px;
  content: "Doing (5)";
  font-weight: bold;
}

.doing-first:after,
.done-first:after {
  position: absolute;
  top: -35px;
  left: -25px;
  width: 10px;
  height: 180px;
  z-index: 10;
  background-color: #fff;
  content: "";
}

.done-first:before {
  position: absolute;
  top: -30px;
  height: 30px;
  content: "Done (3)";
  font-weight: bold;
}

.bg-todo {
  position: absolute;
  background-color: #FFEFD3;
  width: 100vw;
  height: 150px;
  top: -30px;
  left: -10px;
  z-index: -1;
}

.bg-doing {
  position: absolute;
  background-color: #EFDCFF;
  width: 100vw;
  height: 150px;
  top: -30px;
  left: -15px;
  z-index: -1;
}

.bg-done {
  position: absolute;
  background-color: #DCFFEE;
  width: 10vw;
  height: 150px;
  top: -30px;
  left: -15px;
  z-index: -1;
}

.end {
  height: 150px;
  width: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">

  <div class="item todo-first">
    <div class="bg-todo"></div>
    Drink coffee
  </div>
  <div class="item">Go to work</div>

  <div class="space"></div>

  <div class="item doing-first">
    <div class="bg-doing"></div>
    1
  </div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>

  <div class="space"></div>

  <div class="item done-first">
    <div class="bg-done"></div>
    1
  </div>
  <div class="item">2</div>
  <div class="item">3</div>

  <div class="end"></div>

</div>

0
Itay Gal

Возможное решение JS ..

var ul = $("ul.ul-to-fix");

if(ul.find("li").length>{max_possible_rows)){
    if(!ul.hasClass("width-calculated")){
        ul.width(ul.find("li").eq(0).width()*ul.css("columns"));
        ul.addClass("width-calculated");
     }
}
0
user2323336