フレックスボックスアイテムが列モードで折り返されると、コンテナの幅が拡大しません


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を追加すると、フレックスボックスモデルが確実に機能しなくなります。これは可能な限りクリーンに保つ必要があります。

とりあえず、overflow-y: auto代わりにフォールバックしflex-wrap: wrapて、必要なときに内部コンテナーが垂直にスクロールするようにします。きれいではありませんが、少なくとも使いやすさを大幅に損なうことはありません。


2
余談ですが、Chromeには、フローが設定されたコンテナがcolumn wrap折り返し時に幅を拡張しないようにするバグがあります。詳細については、code.google.com / p / chromium / issues / detail?id = 247963をご覧ください。
Gerrit Bertier

IE11でも動作しません。そこでは、最も内側のアイテムが折り返されますが、内側のリストとそのコンテナ(外側のアイテム)は幅を広げません。現在、内部リストをスクロールさせることにフォールバックしていますが、これは長期的な解決策としては適切ではないため、JavaScriptを追加しないようにしたいと思います。
Anders Tornblad、2015年

回答:


170

問題

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

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

この質問は何度も尋ねられ(下のリストを参照)、CSSで明確な答えはありません。

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

すべての主要なブラウザーが、フレックスコンテナーを行方向の折り返しで展開し、列方向では展開しないのはなぜですか?

あなたはそれらのうちの少なくとも1つがそれを正しく理解すると思うでしょう。私はその理由を推測することしかできません。多分それは技術的に難しい実装であり、この反復のために棚上げされました。

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


問題の説明

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


回避策のオプション

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


さらなる分析


同じ問題を説明する他の投稿


2
バグレポートのコメントによると、この問題は、新しいレイアウトエンジンLayoutNG
Ben.12、

5
あなたが提供し、それらを分類したリンクの数は本当に素晴らしいです。ほとんどの人がこのように答えを書いてくれるといいのですが。すばらしい答えです。
Vignesh

4
Flexboxのいくつかのバグとそれらの回避策をリストした便利なリポジトリを次に示します。このバグは、#14
Ben.12

CSSグリッドを使用してこの問題を修正できますか?
Ismail Farooq 2019

もう1つの回避策オプション:codepen.io/_mc2/pen/PoPmJRPある側面では、書き込みモードのアプローチよりも優れていることがわかりました
michalczerwinski

37

パーティーには遅れましたが、この問題はYEARS後でまだ発生していました。グリッドを使用して解決策を見つけることになりました。使用できるコンテナ

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

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


1
私がこれまでに見たことがなければ、それはエレガントな回避策です!私はグリッドに入り始めて、あなたのソリューションが大好きです。ありがとうございます。
アルバート

スポット!私の問題を解決しました。
Celestin Bochis、

Chromeでまだこの問題が発生しています。グリッドの回避策を使用しないことを望んでいました。他の人がこのアプローチを使用していることを知っておくと便利です。
trukvl

命の恩人。grid-row-end: span X;より多くの行を取得するためにいくつかの項目が必要な場合にも使用できます。
メイリオン・ヒューズ

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でテストしただけです。これを変更して他のブラウザーで機能するようにする方法があるか、またはこのブラウザーを更新してこの機能を実現している可能性があります。

このコメントへの大きな一言:フレックスボックスアイテムが列モードで折り返されると、コンテナの幅が大きくなりません。この問題のスレッドを掘り下げた結果、https: //bugs.chromium.org/p/chromium/issues/detail?id = 507397#c39が表示され、このJSFiddleが表示されました。


-1

解決策や適切な回避策はまだ提案されていなかったので、少し異なるアプローチで要求された動作を取得することができました。レイアウトを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>


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

残念ながら、個々の要素の高さは変わる可能性があるため、これは役に立ちません。要素の数は興味深いものではありません...しかし、columnsstyleプロパティを使用することは、実用的なソリューションの出発点になる可能性があります。たぶん、列数調整 ULの幅を。
Anders Tornblad 2017

1
私はまた、私が取り組んでいるReactアプリケーションのこの問題のJSソリューションを使用することになりました。さまざまなサイズの要素を操作できるように設計されています。ここの例:djskinner.github.io/react-column-wrap。ソースコードはこちら:github.com/djskinner/react-column-wrap
djskinner
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.