我正在處理一個嵌套的flexbox布局,它應該如下工作:
最外層(ul#main)是一個水平列表,當向其中添加更多項目時,它必須向右擴展。如果它變得太大,應該有一個水平滾動條。
#main {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
overflow-x: auto;
/* ...and more... */
}
此列表中的每一項(ul # main & gtli)有一個標題(ul # main & gt李& gth2)和內(nèi)部列表(ul # main & gt李& gtul.tasks)。這個內(nèi)部列表是垂直的,需要時應該換行。當包裝成更多的列時,它的寬度應該增加,以便為更多的項目騰出空間。這種寬度的增加也應該適用于外部列表的包含項目。
.tasks {
flex-direction: column;
flex-wrap: wrap;
/* ...and more... */
}
我的問題是,當窗口的高度變得太小時,內(nèi)部列表不會換行。我嘗試了很多篡改所有flex屬性的方法,試圖一絲不茍地遵循CSS-Tricks的指導方針,但是沒有成功。
這個JSFiddle顯示了我到目前為止所擁有的。
預期結果(我想要的):
實際結果(我得到的):
舊結果(2015年我得到的):
更新 經(jīng)過一些調(diào)查,這開始看起來像一個更大的問題。所有主流瀏覽器的行為都一樣,和我的flexbox設計被嵌套沒有關系。更簡單的flexbox列布局拒絕在項目換行時增加列表的寬度。
另一個JSFiddle清楚地說明了這個問題。在當前版本的Chrome、Firefox和IE11中,所有項目都能正確換行;在行模式下,列表的高度會增加,但在列模式下,其寬度不會增加。此外,當改變列模式的高度時,元素根本不會立即重排,但在行模式下會。
然而,官方的規(guī)范(具體看例子5)似乎表明我想做的應該是可能的。
有人能想出解決這個問題的方法嗎?
更新2 在使用JavaScript在resize事件期間更新各種元素的高度和寬度的大量實驗之后,我得出的結論是,試圖用這種方式解決它太復雜、太麻煩了。此外,添加JavaScript肯定會破壞flexbox模型,應該盡可能保持干凈。
現(xiàn)在,我回退到overflow-y: auto,而不是flex-wrap: wrap,以便內(nèi)部容器在需要時垂直滾動。它并不漂亮,但它是一種前進的方式,至少不會太多地破壞可用性。
這似乎是flex布局的一個基本缺陷。
列方向的flex容器不會擴展以容納更多的列。(這在flex-direction: row中不是問題。)
這個問題被問了很多次(見下面的列表),在CSS中沒有清晰的答案。
很難確定這是一個錯誤,因為這個問題在所有主流瀏覽器中都存在。但這確實提出了一個問題:
怎么可能所有主流瀏覽器都讓flex容器 在行方向但不在列方向擴展換行?
你會認為他們中至少有一個人會答對。我只能推測原因。也許這是一個技術上困難的實現(xiàn),并被擱置在這次迭代中。
更新:該問題似乎在Edge v16中得到解決。
問題的說明 OP制作了一個有用的演示來說明這個問題。我在這里復制:http://jsfiddle.net/nwccdwLw/1/
變通方法選項 來自堆棧溢出社區(qū)的Hacky解決方案:
"似乎這個問題不能只通過CSS來解決,所以我向你推薦一個JQuery解決方案。"
"奇怪的是,大多數(shù)瀏覽器都沒有正確實現(xiàn)column flex容器,但對編寫模式的支持相當不錯。因此,您可以使用具有垂直書寫模式的row flex容器。"
更多分析 Chromium錯誤報告
馬克·埃默里的回答
描述相同問題的其他帖子 柔性盒容器寬度不& # 39;不要成長 如何讓display:flex容器隨著其包裝的內(nèi)容水平擴展? 伸縮流:列換行。如何設置容器& # 39;s寬度等于內(nèi)容? Flexbox flex-flow列在chrome中出現(xiàn)錯誤? 如何使用& quot伸縮流:列換行& quot? Flex容器不& # 39;當內(nèi)容在列中換行時,不要展開 flex-flow:列換行,在flex框中導致父容器溢出 Html flexbox容器不會在包裝的子項上展開 Flexbox容器和溢出的flex子? 我如何制作一個伸縮自如的flexbox容器來包裝物品? 當有多列時,計算一列的Flex容器 用flex制作全寬容器 Flexbox容器可以調(diào)整大小嗎? Flex-Grow內(nèi)部的Flex-Wrap Flexbox擴展到包含 將flexbox元素展開到其內(nèi)容? flexbox列拉伸以適合內(nèi)容 https://stackoverflow.com/q/48406237/3597276 flex-flow:列換行不& # 39;t拉伸父元素& # 39;s寬度 為什么& # 39;t my & ltul & gt擴展寬度以覆蓋所有& lt李& gt? https://stackoverflow.com/q/55709208/3597276 Flexbox wrap不增加父級的寬度? 絕對伸縮容器未更改為具有定義的最大高度的正確寬度 父內(nèi)嵌塊div比帶flex-wrap的子div窄 參加派對很晚,但幾年后仍然遇到這個問題。最終使用網(wǎng)格找到了解決方案。在你可以使用的容器上
display: grid;
grid-auto-flow: column;
grid-template-rows: repeat(6, auto);
我在CodePen上有一個在flexbox問題和網(wǎng)格修復之間切換的例子:https://codepen.io/MandeeD/pen/JVLdLd
在這個問題被提出近6年后,這個flexbox bug仍然存在,所以這里有一個專門針對CSS的flex-direction: column解決方案,供其他人使用:
body {
background-color: grey;
}
button {
background-color: white;
border: none;
border-radius: 4px;
width: 80px;
height: 40px;
margin: 4px;
}
/* WORKAROUND FOR flex-direction: column WITH WRAP IS BELOW */
.wrapped-columns {
flex-direction: row;
flex-wrap: wrap;
writing-mode: vertical-lr;
text-orientation: upright;
}
/* Ensures content is rendered correctly in Firefox */
.wrapped-columns * {
writing-mode: horizontal-tb;
}
<div class="wrapped-columns">
<button>Button 1</button>
<button>Button 2</button>
<button>Button 3</button>
<button>Button 4</button>
<button>Button 5</button>
<button>Button 6</button>
<button>Button 7</button>
<button>Button 8</button>
<button>Button 9</button>
<button>Button 10</button>
<button>Button 11</button>
<button>Button 12</button>
<button>Button 13</button>
<button>Button 14</button>
</div>
我剛剛在這里發(fā)現(xiàn)了一個非常棒的純CSS解決方案。
https://jsfiddle.net/gcob492x/3/
棘手之處:在列表div中設置writing-mode: vertical-lr,然后在列表項中設置writing-mode: horizontal-tb。我必須調(diào)整JSFiddle中的樣式(刪除許多對齊樣式,這對于解決方案來說是不必要的)。
注意:評論說它只能在基于Chromium的瀏覽器上運行,不能在Firefox上運行。我只在Chrome中親自測試過。有可能有一種方法可以修改它,使其在其他瀏覽器中工作,或者有更新的瀏覽器使其工作。
對這個評論大聲喊出來:當flexbox項目以列模式包裝時,容器不會增加它的寬度。通過挖掘這個問題線索,我找到了https://bugs.chromium.org/p/chromium/issues/detail? id = 507397 # c39,這讓我找到了這個JSFiddle。
很不幸,這么多主流瀏覽器在多年后都遭受這個bug的困擾。考慮一種Javascript變通方法。每當瀏覽器窗口調(diào)整大小,或者向元素添加內(nèi)容時,執(zhí)行這段代碼,使其調(diào)整到適當?shù)膶挾取D憧梢栽谀愕目蚣苤卸x一個指令來為你做這件事。
element.style.flexBasis = "auto";
element.style.flexBasis = `${element.scrollWidth}px`;
由于還沒有提出解決方案或適當?shù)淖兺ǚ椒ǎ以O法用一種稍微不同的方法獲得了所請求的行為。我沒有將布局分成3個不同的div,而是將所有的項目添加到1個div中,并在中間添加更多的div。
建議的解決方案是硬編碼的,假設我們有3個部分,但可以擴展到一個通用的部分。主要的想法是解釋我們?nèi)绾螌崿F(xiàn)這種布局。
將所有項目添加到一個使用flex包裝項目的容器div中 每個“內(nèi)部容器”(我稱之為section)的第一項將有一個類,它幫助我們進行一些操作,創(chuàng)建每個部分的分離和樣式。 使用:在每個第一項之前,我們可以找到每個部分的標題。 使用空間會在各部分之間產(chǎn)生間隙 由于空間不會覆蓋部分的整個高度,我還添加了:在部分之后,所以用絕對位置和白色背景來定位它。 為了設計每個部分的背景顏色,我在每個部分的第一個項目中添加了另一個div。我也將絕對持倉,z指數(shù)為:-1。 為了獲得每個背景的正確寬度,我使用JS,設置正確的寬度,并添加一個監(jiān)聽器來調(diào)整大小。
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>
我以這種方式解決了我的問題,我希望它能幫助其他遇到這個問題的人:
_ensureWidth(parentElement) {
let totalRealWidth = 0;
let parentElementBoundingRect = parentElement.getBoundingClientRect()
let lowestLeft = parentElementBoundingRect.x;
let highestRight = parentElementBoundingRect.width;
for (let i = 0; i < parentElement.children.length; i++) {
let { x, width } = parentElement.children[i].getBoundingClientRect();
if (x < lowestLeft) {
lowestLeft = x;
}
if (x + width > highestRight) {
highestRight = x + width;
}
}
totalRealWidth = highestRight - lowestLeft;
parentElement.style.width = `${totalRealWidth}px`;
}
解決方法:
使用javascript,在元素加載到屏幕上之后,手動設置包裝器的寬度并不難。寬度總是最后一個子元素的右邊點。
在react中,我讓它根據(jù)添加到flex包裝器中的任何子元素來更新布局,但這可以在您向包裝器添加或移除子元素的任何時候調(diào)用。
let r = refWrapper.current.lastElementChild.getBoundingClientRect()
refWrapper.current.style.width = (r.x+r.width )+'px'
`
其中refWrapper是您的flex元素
可能的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");
}
}