Khi các mục flexbox bao bọc trong chế độ cột, container không tăng chiều rộng của nó


166

Tôi đang làm việc trên một bố trí flexbox lồng nhau nên hoạt động như sau:

Cấp độ ngoài cùng ( ul#main) là một danh sách ngang phải mở rộng sang bên phải khi thêm nhiều mục vào nó. Nếu nó phát triển quá lớn, cần có một thanh cuộn ngang.

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

Mỗi mục của danh sách này ( ul#main > li) có một tiêu đề ( ul#main > li > h2) và một danh sách bên trong ( ul#main > li > ul.tasks). Danh sách bên trong này là dọc và nên bọc thành các cột khi cần thiết. Khi gói vào nhiều cột hơn, chiều rộng của nó sẽ tăng lên để nhường chỗ cho nhiều vật phẩm hơn. Việc tăng chiều rộng này cũng nên áp dụng cho mục chứa của danh sách bên ngoài.

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

Vấn đề của tôi là danh sách bên trong không bao bọc khi chiều cao của cửa sổ quá nhỏ. Tôi đã thử làm xáo trộn tất cả các thuộc tính flex, cố gắng làm theo các hướng dẫn tại CSS-Tricks cách tỉ mỉ, nhưng không gặp may.

JSFiddle này cho thấy những gì tôi có cho đến nay.

Kết quả mong đợi (những gì tôi muốn) :

Đầu ra mong muốn của tôi

Kết quả thực tế (những gì tôi nhận được) :

Sản lượng hiện tại của tôi

Kết quả cũ hơn (những gì tôi nhận được trong năm 2015) :

Sản phẩm cũ của tôi

CẬP NHẬT

Sau một số điều tra, điều này đang bắt đầu giống như một vấn đề lớn hơn. Tất cả các trình duyệt chính hoạt động theo cùng một cách và nó không liên quan gì đến thiết kế flexbox của tôi được lồng vào nhau. Ngay cả bố trí cột flexbox đơn giản hơn cũng từ chối tăng chiều rộng của danh sách khi các mục được bọc.

Điều này JSFiddle khác thể hiện rõ ràng vấn đề. Trong các phiên bản hiện tại của Chrome, Firefox và IE11, tất cả các mục đều được bọc chính xác; chiều cao của danh sách tăng trong rowchế độ, nhưng chiều rộng của nó không tăng trong columnchế độ. Ngoài ra, không có sự phản xạ tức thời của các yếu tố khi thay đổi độ cao của columnchế độ, nhưng có trongrow chế độ.

Tuy nhiên, thông số kỹ thuật chính thức (xem cụ thể ở ví dụ 5) dường như chỉ ra rằng những gì tôi muốn làm nên có thể.

Ai đó có thể đưa ra một cách giải quyết cho vấn đề này?

CẬP NHẬT 2

Sau rất nhiều thử nghiệm sử dụng JavaScript để cập nhật chiều cao và chiều rộng của các yếu tố khác nhau trong quá trình thay đổi kích thước, tôi đã đi đến kết luận rằng nó quá phức tạp và quá nhiều rắc rối để cố gắng giải quyết theo cách đó. Ngoài ra, việc thêm JavaScript chắc chắn phá vỡ mô hình flexbox, cần được giữ sạch nhất có thể.

Hiện tại, tôi đang quay trở lại overflow-y: autothay vì flex-wrap: wrapđể container bên trong cuộn theo chiều dọc khi cần. Nó không đẹp, nhưng đó là một cách để ít nhất không phá vỡ khả năng sử dụng quá nhiều.


2
Chỉ là một sidenote, nhưng có một lỗi trong Chrome khiến cho một thùng chứa với dòng chảy được đặt thành column wrapkhông mở rộng chiều rộng của nó khi gói. Xem code.google.com/p/chromium/issues/detail?id=247963 để biết thêm thông tin.
Gerrit Bertier

Tôi cũng không thể làm cho nó hoạt động trong IE11. Ở đó, các mục trong cùng bao bọc, nhưng danh sách bên trong và thùng chứa của nó (mục bên ngoài) không tăng chiều rộng của chúng. Hiện tại tôi đang quay trở lại để cuộn danh sách bên trong, nhưng nó không phải là một giải pháp lâu dài tốt và tôi thực sự muốn tránh thêm JavaScript cho việc này.
Anders Tornblad

Câu trả lời:


170

Vấn đề

Điều này trông giống như một thiếu sót cơ bản trong bố trí flex.

Một thùng chứa flex theo hướng cột sẽ không mở rộng để chứa các cột bổ sung. (Đây không phải là vấn đề trong flex-direction: row.)

Câu hỏi này đã được hỏi nhiều lần (xem danh sách bên dưới), không có câu trả lời rõ ràng trong CSS.

Thật khó để xác định đây là một lỗi vì sự cố xảy ra trên tất cả các trình duyệt chính. Nhưng nó đặt ra câu hỏi:

Làm thế nào có thể tất cả các trình duyệt chính có bộ chứa flex để mở rộng theo hướng hàng nhưng không theo hướng cột?

Bạn sẽ nghĩ ít nhất một trong số họ sẽ làm cho đúng. Tôi chỉ có thể suy đoán về lý do. Có lẽ đó là một thực hiện khó khăn về mặt kỹ thuật và đã được gác lại cho lần lặp này.

CẬP NHẬT: Vấn đề dường như được giải quyết trong Edge v16.


Minh họa của vấn đề

OP đã tạo ra một bản demo hữu ích minh họa vấn đề. Tôi đang sao chép nó ở đây: http://jsfiddle.net/nwccdwLw/1/


Tùy chọn giải pháp thay thế

Các giải pháp mạnh mẽ từ cộng đồng Stack Overflow:


Phân tích thêm


Các bài viết khác mô tả cùng một vấn đề


2
Theo các ý kiến báo cáo lỗi, vấn đề này sẽ không được cố định cho đến khi họ phát hành công cụ layout mới của họ LayoutNG
Ben.12

5
Số lượng liên kết bạn cung cấp và phân loại chúng là thực sự tuyệt vời. Tôi muốn hầu hết mọi người viết câu trả lời theo cách này. Câu trả lời chính xác.
Vignesh

4
Đây là một repo hữu ích liệt kê ra một số lỗi Flexbox và cách giải quyết cho chúng: Lỗi này được liệt kê ở # 14
Ben.12

chúng ta có thể khắc phục vấn đề này bằng cách sử dụng lưới CSS không?
Ismail Farooq

thêm một tùy chọn giải pháp khác: codepen.io/_mc2/pen/PoPmJRP Đối với một số khía cạnh tôi thấy tốt hơn là cách tiếp cận chế độ viết
michalczerwinski

37

Đến bữa tiệc muộn, nhưng vẫn gặp phải vấn đề này NĂM sau. Đã kết thúc việc tìm một giải pháp bằng cách sử dụng lưới. Trên container bạn có thể sử dụng

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

Tôi có một ví dụ về CodePen để giải quyết vấn đề flexbox và sửa lỗi lưới: https://codepen.io/MandeeD/pen/JVLdLd


1
Đó là một cách giải quyết tao nhã nếu tôi từng thấy! Tôi chỉ đang vào lưới và tôi yêu giải pháp của bạn, cảm ơn bạn vì điều này.
Albert

Tại chỗ trên! Giải quyết vấn đề của tôi.
Celestin Bochis

Vẫn đang gặp vấn đề này trong Chrome. Tôi đã hy vọng tránh sử dụng một cách giải quyết lưới. Thật tốt khi biết những người khác đang sử dụng phương pháp này!
trukvl

cứu người. Bạn cũng có thể sử dụng grid-row-end: span X;nếu bạn cần một số mặt hàng để chiếm nhiều hàng hơn.
Meirion Hughes

0

Thật không may là rất nhiều trình duyệt lớn bị lỗi này sau nhiều năm. Hãy xem xét một cách giải quyết Javascript. Bất cứ khi nào cửa sổ trình duyệt thay đổi kích thước hoặc nội dung được thêm vào phần tử, hãy thực thi mã này để làm cho nó thay đổi kích thước theo chiều rộng phù hợp. Bạn có thể xác định một lệnh trong khung của bạn để làm điều đó cho bạn.

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

-1

Vì chưa có giải pháp hoặc giải pháp phù hợp nào được đề xuất, tôi đã quản lý để có được hành vi được yêu cầu với một cách tiếp cận khác. Thay vì tách bố cục thành 3 div khác nhau, tôi thêm tất cả các mục vào 1 div và tạo sự tách biệt với một số div khác ở giữa.

Giải pháp đề xuất được mã hóa cứng, giả sử chúng ta có 3 phần, nhưng có thể được mở rộng thành một phần chung. Ý tưởng chính là giải thích làm thế nào chúng ta có thể đạt được bố cục này.

  1. Thêm tất cả các mục vào 1 div container sử dụng flex để bọc các mục
  2. Mục đầu tiên của mỗi "thùng chứa bên trong" (tôi sẽ gọi nó là một phần) sẽ có một lớp, giúp chúng ta thực hiện một số thao tác tạo sự tách biệt và kiểu dáng của từng phần.
  3. Sử dụng :before trên mỗi mục đầu tiên, chúng tôi có thể định vị tiêu đề của từng phần.
  4. Sử dụng space tạo khoảng cách giữa các phần
  5. spacesẽ không bao gồm toàn bộ chiều cao của phần tôi cũng đang thêm:after vào các phần để định vị nó với vị trí tuyệt đối và nền trắng.
  6. Để tạo kiểu màu nền cho mỗi phần, tôi thêm một div khác vào trong mục đầu tiên của mỗi phần. Tôi sẽ được vị trí tuyệt đối là tốt và sẽ có z-index: -1.
  7. Để có được độ rộng chính xác của mỗi nền, tôi đang sử dụng JS, đặt độ rộng chính xác và thêm người nghe để thay đổi kích thước.

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

Giải pháp JS khả thi ..

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");
     }
}

Thật không may, điều đó không giúp ích gì, vì độ cao của các yếu tố riêng lẻ có thể thay đổi. Vì vậy, số lượng phần tử không thú vị ... Nhưng sử dụng thuộc tính columnskiểu có thể là điểm khởi đầu cho giải pháp làm việc. Có thể điều chỉnh số lượng cột chiều rộng của ul.
Anders Tornblad

1
Tôi cũng đã kết thúc với một giải pháp JS cho vấn đề này cho một ứng dụng React mà tôi đang làm việc. Nó được thiết kế để làm việc với các yếu tố có kích thước bất kỳ và khác nhau. Ví dụ ở đây: djskinner.github.io/react-column-wrap . Mã nguồn tại đây: github.com/djskinner/react-column-wrap
djskinner
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.