Saat item flexbox terbungkus dalam mode kolom, kontainer tidak tumbuh lebarnya

167

Saya sedang mengerjakan tata letak flexbox bersarang yang seharusnya berfungsi sebagai berikut:

Level terluar ( ul#main) adalah daftar horizontal yang harus diperluas ke kanan ketika lebih banyak item ditambahkan ke dalamnya. Jika terlalu besar, harus ada bilah gulir horizontal.

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

Setiap item dari daftar ini ( ul#main > li) memiliki header ( ul#main > li > h2) dan daftar dalam ( ul#main > li > ul.tasks). Daftar dalam ini adalah vertikal dan harus membungkus ke dalam kolom saat diperlukan. Ketika membungkus lebih banyak kolom, lebarnya harus bertambah untuk memberi ruang bagi lebih banyak item. Peningkatan lebar ini harus berlaku juga untuk item yang berisi daftar luar.

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

Masalah saya adalah bahwa daftar bagian dalam tidak membungkus ketika ketinggian jendela terlalu kecil. Saya telah mencoba banyak gangguan dengan semua properti fleksibel, mencoba mengikuti panduan di CSS-Trik dengan cermat, tetapi tidak berhasil.

JSFiddle ini menunjukkan apa yang saya miliki sejauh ini.

Hasil yang diharapkan (apa yang saya inginkan) :

Output yang saya inginkan

Hasil aktual (apa yang saya dapatkan) :

Output saya saat ini

Hasil yang lebih lama (apa yang saya dapatkan di 2015) :

Output saya yang lebih tua

MEMPERBARUI

Setelah beberapa penyelidikan, ini mulai terlihat seperti masalah yang lebih besar. Semua browser utama berperilaku dengan cara yang sama , dan tidak ada hubungannya dengan desain flexbox saya yang bersarang. Layout kolom flexbox yang lebih sederhana menolak untuk menambah lebar daftar saat item dibungkus.

JSFiddle lainnya ini dengan jelas menunjukkan masalahnya. Dalam versi Chrome, Firefox dan IE11 saat ini, semua item terbungkus dengan benar; tinggi daftar bertambah dalam rowmode, tetapi lebarnya tidak bertambah dalam columnmode. Juga, tidak ada reflow langsung elemen sama sekali ketika mengubah ketinggian columnmode, tetapi ada dalam rowmode.

Namun, spesifikasi resmi (lihat contoh 5) tampaknya mengindikasikan bahwa apa yang ingin saya lakukan harus dimungkinkan.

Bisakah seseorang menemukan solusi untuk masalah ini?

PEMBARUAN 2

Setelah banyak bereksperimen menggunakan JavaScript untuk memperbarui tinggi dan lebar berbagai elemen selama acara pengubahan ukuran, saya sampai pada kesimpulan bahwa itu terlalu rumit dan terlalu banyak kesulitan untuk mencoba menyelesaikannya dengan cara itu. Juga, menambahkan JavaScript pasti merusak model flexbox, yang harus dijaga sebersih mungkin.

Untuk saat ini, saya jatuh kembali ke overflow-y: autobukan flex-wrap: wrapsehingga wadah bagian dalam bergulir secara vertikal saat diperlukan. Ini tidak cantik, tetapi ini adalah salah satu cara maju yang setidaknya tidak terlalu merusak kegunaan.

Anders Tornblad
sumber
2
Hanya sidenote, tetapi ada bug di Chrome yang menyebabkan sebuah wadah dengan alirannya diatur untuk column wraptidak memperluas lebarnya saat membungkus. Lihat code.google.com/p/chromium/issues/detail?id=247963 untuk informasi lebih lanjut.
Gerrit Bertier
Saya juga tidak bisa menggunakannya di IE11. Di sana, item terdalam dibungkus, tetapi daftar bagian dalam dan wadahnya (item luar) tidak menambah lebarnya. Saat ini saya kembali ke gulir daftar bagian dalam, tetapi ini bukan solusi jangka panjang yang baik, dan saya benar-benar ingin menghindari menambahkan JavaScript untuk ini.
Anders Tornblad

Jawaban:

170

Masalah

Ini terlihat seperti kekurangan mendasar dalam tata letak fleksibel.

Wadah fleksibel dengan arah kolom tidak akan memuai untuk mengakomodasi kolom tambahan. (Ini bukan masalah di flex-direction: row.)

Pertanyaan ini telah ditanyakan berkali-kali (lihat daftar di bawah), tanpa jawaban bersih di CSS.

Sulit untuk menyematkan ini sebagai bug karena masalah terjadi di semua browser utama. Tapi itu menimbulkan pertanyaan:

Bagaimana mungkin semua browser utama mendapatkan wadah fleksibel untuk diperluas dengan membungkus dalam arah baris tetapi tidak dalam arah kolom?

Anda akan berpikir setidaknya salah satu dari mereka akan melakukannya dengan benar. Saya hanya bisa berspekulasi tentang alasannya. Mungkin itu implementasi yang sulit secara teknis dan dibatalkan untuk iterasi ini.

UPDATE: Masalah ini tampaknya diselesaikan di Edge v16.


Ilustrasi Masalah

OP menciptakan demo bermanfaat yang menggambarkan masalah. Saya menyalinnya di sini: http://jsfiddle.net/nwccdwLw/1/


Opsi Penanganan Masalah

Solusi peretasan dari komunitas Stack Overflow:


Analisis Lebih Lanjut


Posting Lain Menggambarkan Masalah yang Sama

Michael Benjamin
sumber
2
Menurut komentar laporan bug, masalah ini tidak akan diperbaiki sampai mereka merilis LayoutNG
Ben.12
5
Jumlah tautan yang Anda berikan dan kategorikan sangat bagus. Saya berharap kebanyakan orang menulis jawaban dengan cara ini. Jawaban yang bagus
Vignesh
4
Berikut ini adalah repo yang berguna yang mencantumkan beberapa bug dan penyelesaian masalah Flexbox untuk mereka: Bug ini terdaftar di # 14
Ben.12
dapatkah kami memperbaiki masalah ini dengan menggunakan kisi CSS?
Ismail Farooq
satu lagi solusi pemecahan masalah: codepen.io/_mc2/pen/PoPmJRP Untuk beberapa aspek saya merasa lebih baik bahwa pendekatan mode tulis
michalczerwinski
37

Terlambat ke pesta, tetapi masih mengalami masalah ini TAHUN kemudian. Akhirnya menemukan solusi menggunakan kisi. Pada wadah yang bisa Anda gunakan

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

Saya punya contoh pada CodePen yang beralih antara masalah flexbox dan perbaikan grid: https://codepen.io/MandeeD/pen/JVLdLd

MandeeD
sumber
1
Itu solusi yang elegan jika saya pernah melihatnya! Saya baru saja masuk ke grid dan saya suka solusi Anda, terima kasih untuk ini.
Albert
Temukan! Memecahkan masalah saya.
Celestin Bochis
Masih mengalami masalah ini di Chrome. Saya berharap untuk menghindari menggunakan solusi grid. Senang mengetahui orang lain menggunakan pendekatan ini!
trukvl
penyelamat hidup. Anda juga dapat menggunakan grid-row-end: span X;jika Anda membutuhkan beberapa item untuk mengambil lebih banyak baris.
Meirion Hughes
0

Sangat disayangkan bahwa begitu banyak browser utama menderita bug ini setelah bertahun-tahun. Pertimbangkan solusi Javascript. Setiap kali jendela browser mengubah ukuran, atau konten ditambahkan ke elemen, jalankan kode ini untuk membuatnya untuk mengubah ukuran ke lebar yang tepat. Anda dapat menentukan arahan dalam kerangka kerja Anda untuk melakukannya untuk Anda.

    element.style.flexBasis = "auto";
    element.style.flexBasis = `${element.scrollWidth}px`;
Steve Hanov
sumber
0

Saya baru saja menemukan solusi PURE CSS yang benar-benar mengagumkan di sini.

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

Caranya: atur writing-mode: vertical-lrdi daftar div lalu writing-mode: horizontal-tbdi daftar item. Saya harus mengubah style di JSFiddle (menghapus banyak style alignment, yang tidak diperlukan untuk solusinya).

Catatan: komentar mengatakan itu hanya berfungsi di browser berbasis Chromium, dan bukan Firefox. Saya hanya diuji secara pribadi di Chrome. Mungkin saja ada cara untuk memodifikasi ini agar berfungsi di browser lain atau ada pembaruan untuk browser yang membuat ini berfungsi.

Teriakan besar untuk komentar ini: Saat item flexbox terbungkus dalam mode kolom, kontainer tidak tumbuh lebarnya . Menggali utas masalah itu mengarahkan saya ke https://bugs.chromium.org/p/chromium/issues/detail?id=507397#c39 yang membawa saya ke JSFiddle ini.

Dustin Kane
sumber
-1

Karena tidak ada solusi atau solusi yang tepat yang disarankan, saya berhasil mendapatkan perilaku yang diminta dengan pendekatan yang sedikit berbeda. Alih-alih memisahkan tata letak menjadi 3 div yang berbeda, saya menambahkan semua item menjadi 1 div dan membuat pemisahan dengan beberapa div di antaranya.

Solusi yang diusulkan adalah kode keras, dengan asumsi kita memiliki 3 bagian, tetapi dapat diperluas ke yang umum. Ide utamanya adalah menjelaskan bagaimana kita bisa mencapai tata letak ini.

  1. Menambahkan semua item ke dalam 1 kontainer div yang menggunakan flex untuk membungkus item
  2. Item pertama dari setiap "wadah dalam" (saya akan menyebutnya bagian) akan memiliki kelas, yang membantu kita untuk melakukan beberapa manipulasi yang menciptakan pemisahan dan gaya setiap bagian.
  3. Menggunakan :beforepada setiap item pertama, kami dapat menemukan judul setiap bagian.
  4. Menggunakan spacemenciptakan kesenjangan antara bagian-bagian
  5. Karena spacetidak akan menutupi ketinggian penuh bagian saya juga menambahkan :afterke bagian sehingga memposisikannya dengan posisi absolut dan latar belakang putih.
  6. Untuk gaya warna latar belakang setiap bagian saya menambahkan div lain di dalam item pertama dari setiap bagian. Saya akan posisi dengan absolut juga dan akan memiliki z-index: -1.
  7. Untuk mendapatkan lebar yang benar dari setiap latar belakang, saya menggunakan JS, mengatur lebar yang benar, dan juga menambahkan pendengar untuk mengubah ukuran.

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>

Itay Gal
sumber
-2

Kemungkinan solusi 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");
     }
}
pengguna2323336
sumber
Sayangnya, itu tidak membantu, karena ketinggian elemen individu dapat bervariasi. Jadi jumlah elemen tidak menarik ... Tetapi menggunakan columnsproperti style bisa menjadi titik awal untuk solusi yang bekerja. Mungkin menyesuaikan jumlah kolom dan lebar ul.
Anders Tornblad
1
Saya juga akhirnya menggunakan solusi JS untuk masalah ini untuk aplikasi Bereaksi yang telah saya kerjakan. Ini dirancang untuk bekerja dengan elemen ukuran apa pun dan beragam. Contoh di sini: djskinner.github.io/react-column-wrap . Kode sumber di sini: github.com/djskinner/react-column-wrap
djskinner