Коли елементи flexbox загортаються в режимі стовпців, контейнер не збільшує свою ширину


167

Я працюю над вкладеним макетом флексокса, який повинен працювати наступним чином:

Зовнішній рівень ( 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 показує, що я маю досі.

Очікуваний результат (що я хочу) :

Мій бажаний вихід

Фактичний результат (що я отримую) :

Мій поточний вихід

Старіший результат (що я отримав у 2015 році) :

Мій старший вихід

ОНОВЛЕННЯ

Після деякого розслідування це починає виглядати як більша проблема. Усі основні браузери поводяться однаково , і це не має нічого спільного з тим, щоб мій гніздовий дизайн вкладений. Навіть простіші розкладки стовпців у флексі відмовляються збільшувати ширину списку при загортанні елементів.

Цей інший JSFiddle наочно демонструє проблему. У поточних версіях Chrome, Firefox та IE11 всі елементи завершуються правильно; висота списку збільшується в rowрежимі, але його ширина в columnрежимі не збільшується . Крім того, немає жодного негайного перезарядження елементів при зміні висоти columnрежиму, але він є в rowрежимі.

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

Чи може хтось вирішити цю проблему?

ОНОВЛЕННЯ 2

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

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


2
Просто сторонне позначення, але в Chrome є помилка, яка викликає контейнер з потоком, який column wrapне розширює його ширину при обгортанні. Для отримання додаткової інформації див. Code.google.com/p/chromium/isissue/detail?id=247963
— Герріт Бертьє

Я також не можу змусити його працювати в IE11. Там загортають найпотаємніші предмети, але внутрішній список та його контейнер (зовнішній предмет) не збільшують їх ширину. В даний час я повертаюсь до того, що внутрішні списки прокручуються, але це не гарне довгострокове рішення, і я дуже хотів би уникати додавання JavaScript для цього.
— Андерс Торнблад

Відповіді:


170

Проблема

Це виглядає як принциповий недолік у гнучкому розташуванні.

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

Це запитання задавали багато разів (див. Список нижче), без чітких відповідей у ​​CSS.

Важко зафіксувати це як помилку, оскільки проблема виникає у всіх основних браузерах. Але це викликає питання:

Як можливо, що всі основні браузери отримали гнучкий контейнер для розгортання на обгортці в напрямку рядка, але не в напрямку стовпця?

Ви б могли подумати, що принаймні один із них виправиться правильно. Я можу лише міркувати про причину. Можливо, це було технічно складною реалізацією і було прихованим для цієї ітерації.

ОНОВЛЕННЯ: Здається, проблема вирішена в Edge v16.


Ілюстрація проблеми

ОП створила корисну демонстрацію проблеми. Я копіюю його тут: http://jsfiddle.net/nwccdwLw/1/


Параметри обходу

Хейкі рішення із спільноти Stack Overflow:


Більше аналізу


Інші пости, що описують ту саму проблему


2
Згідно з коментарями звітів про помилки, ця проблема не буде виправлена, доки вони не випустять свою нову версію
— Ben.12,

5
Кількість посилань, які ви надали та класифікували, дійсно велика. Я хочу, щоб більшість людей писали відповіді таким чином. Чудова відповідь.
— Виньєш

4
Ось корисний репо з переліком декількох помилок Flexbox та їх вирішення: Ця помилка занесена до №14
— Ben.12

чи можна виправити цю проблему за допомогою сітки CSS?
— Ісмаїл Фарук

ще один варіант вирішення: codepen.io/_mc2/pen/PoPmJRP Для певного аспекту я вважаю, що підхід у режимі запису
— michalczerwinski

37

Запізнився на вечірку, але все ще стикався з цим питанням РОКІВ пізніше. Закінчили пошук рішення за допомогою сітки. На контейнері можна використовувати

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

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


1
Це елегантне вирішення, якщо я його коли-небудь бачив! Я просто потрапляю в сітку і люблю ваше рішення, дякую за це.
— Альберт

Пляма на! Вирішили мою проблему.
— Селестін Бохіс

Проблема все ще працює в Chrome. Я сподівався уникати використання сіткового вирішення. Добре знати, що інші використовують цей підхід!
— trukvl

рятівник життя. Ви також можете використовувати, grid-row-end: span X;якщо вам потрібні деякі елементи, щоб зайняти більше рядків.
— Meirion Hughes

0

Прикро, що так багато основних браузерів страждають від цієї помилки через багато років. Розгляньте спосіб вирішення Javascript. Щоразу, коли вікно веб-переглядача змінює розмір або додається вміст до елемента, виконайте цей код, щоб отримати його розмір до потрібної ширини. Ви можете визначити директиву у своїх рамках, щоб зробити це за вас.

    element.style.flexBasis = "auto";
    element.style.flexBasis = `${element.scrollWidth}px`;

0

Я щойно знайшов тут надзвичайно чудовий спосіб PURE CSS.

https://jsfiddle.net/gcob492x/3/

Хитрість: встановіть writing-mode: vertical-lrу списку div та writing-mode: horizontal-tbв пункті списку. Мені довелося налаштувати стилі в JSFiddle (видалити багато стилів вирівнювання, які не потрібні для рішення).

Примітка. У коментарі йдеться, що він працює лише у веб-переглядачах Chromium, а не у Firefox. Я лише особисто перевіряв у Chrome. Можливо, або є спосіб змінити це, щоб він працював в інших браузерах, або були оновлені згадані браузери, які змушують цю роботу.

Великий вигук на цей коментар: Коли елементи flexbox загортаються в режимі стовпців, контейнер не збільшує своєї ширини . Копаючи цю тему, я перейшов до https://bugs.chromium.org/p/chromium/isissue/detail?id=507397#c39, який привів мене до цього JSFiddle.


-1

Оскільки не було запропоновано жодного рішення чи належного вирішення, мені вдалося отримати запитувану поведінку трохи іншим підходом. Замість того, щоб розділяти макет на 3 різних діви, я додаю всі елементи в 1 div і створюю розділення ще кількома дівами між ними.

Запропоноване рішення важко закодовано, якщо припустити, що у нас є 3 розділи, але їх можна поширити на загальний. Основна ідея - пояснити, як ми можемо досягти цього планування.

  1. Додавання всіх елементів до 1 контейнера, який використовує flex для обгортання елементів
  2. Перший елемент кожного "внутрішнього контейнера" ​​(я називаю це секцією) матиме клас, який допомагає нам робити деякі маніпуляції, що створюють розділення та стилізацію кожного розділу.
  3. Використовуючи :beforeкожен перший елемент, ми можемо знайти заголовок кожного розділу.
  4. Використання spaceстворює зазор між секціями
  5. Оскільки spaceне буде охоплювати повну висоту розділу, я також додаю :afterдо секцій, таким чином розміщуючи його з абсолютним положенням та білим тлом.
  6. Для стилю кольору тла кожного розділу я додаю ще один роздільник всередині першого пункту кожного розділу. Я буду позицією і з абсолютною, і матиму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>


-2

Можливе рішення 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");
     }
}

На жаль, це не допоможе, оскільки висота окремих елементів може змінюватись. Тож кількість елементів не цікава ... Але використання columnsвластивості стилю може стати відправною точкою для робочого рішення. Можливо, регулюючи кількість стовпців та ширину вул.
— Андерс Торнблад

1
Я також вирішив вирішити цю проблему JS для програми React, над якою працюю. Він призначений для роботи з елементами будь-якої і різної величини. Приклад тут: djskinner.github.io/react-column-wrap . Вихідний код тут: github.com/djskinner/react-column-wrap
— djskinner
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.