web-dev-qa-db-ja.com

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... */
}

私の問題は、ウィンドウの高さが小さくなりすぎると、内部リストが折り返されないことです。 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にフォールバックしているため、必要に応じて内部コンテナーが垂直にスクロールします。見た目はきれいではありませんが、少なくとも使いやすさを損なうことはありません。

126
Anders Tornblad

問題

これは、フレックスレイアウトの根本的な欠陥のようです。

列方向のフレックスコンテナは、追加の列を収容するために拡張されません。 (これはflex-direction: rowの問題ではありません。)

この質問は何度も聞かれていますが(下のリストを参照)、CSSには明確な答えはありません。

この問題はすべての主要なブラウザーで発生するため、これをバグとして特定するのは困難です。しかし、それは疑問を提起します:

すべての主要なブラウザがフレックスコンテナを取得して、列方向ではなく行方向にラップして展開することはどのように可能ですか?

そのうちの少なくとも1つが正しいと思うでしょう。その理由だけを推測できます。技術的に困難な実装であり、この反復のために棚上げされた可能性があります。

UPDATE:この問題はEdge v16で解決されたようです。


問題の実例

OPは問題を説明する便利なデモを作成しました。ここにコピーしています: http://jsfiddle.net/nwccdwLw/1/


回避策のオプション

Stack Overflowコミュニティのハッキングソリューション:


さらなる分析


同じ問題を説明している他の投稿

137
Michael_B

パーティーに遅れたが、まだこの問題にYEARS後に実行されていました。グリッドを使用してソリューションを見つけることになりました。コンテナ上で使用できます

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

flexboxの問題とグリッドの修正を切り替えるCodePenの例があります。 https://codepen.io/MandeeD/pen/JVLdLd

6
MandeeD

解決策または適切な回避策がまだ提案されていないため、要求された動作を少し異なるアプローチで取得できました。レイアウトを3つの異なるdivに分割する代わりに、すべてのアイテムを1つのdivに追加し、さらにいくつかのdivを挟んで分割を作成します。

提案されたソリューションは、3つのセクションがあると仮定してハードコーディングされていますが、一般的なものに拡張することができます。主なアイデアは、このレイアウトを実現する方法を説明することです。

  1. Flexを使用してアイテムをラップする1つのコンテナdivにすべてのアイテムを追加します
  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