bestsource

열 모드에서 flexbox 항목을 랩할 때 컨테이너의 너비가 증가하지 않습니다.

bestsource 2023. 9. 11. 21:55
반응형

열 모드에서 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의 지침을 꼼꼼하게 따르려고 노력하면서 모든 플렉스 속성을 조작하려고 많이 시도했지만, 운이 없었습니다.

JS Fiddle은 제가 지금까지 가지고 있는 것을 보여줍니다.

예상 결과(내가 원하는 것):

My desired output

실제 결과(내가 얻는 것):

My current output

이전 결과(2015년에 얻은 결과):

My older output

갱신하다

어느 정도 조사를 해보니, 이 문제는 더 큰 문제로 보이기 시작했습니다.주요 브라우저는 모두 동일하게 동작하며, 제 플렉스박스 디자인이 중첩되는 것과는 무관합니다.더 간단한 플렉스박스 열 레이아웃은 항목 랩 시 목록의 너비를 늘리지 않습니다.

다른 JSFiddle은 문제를 명확하게 보여줍니다.현재 버전의 Chrome, Firefox 및 IE11에서는 모든 항목이 올바르게 랩핑됩니다. 목록의 높이가 증가합니다.row에서는 그 하지 않습니다,그은서다지나다지e나서s,,그은eecolumnmode. 모드의 할 때 가 전혀 . 또한 a의 높이를 변경할 때 요소의 즉각적인 리플로우가 전혀 없습니다.column는 있습니다.rowmode.mode

하지만 공식 스펙(구체적으로 예 5 참조)을 보면 제가 하고 싶은 일이 가능해야 한다는 것을 알 수 있는 것 같습니다.

누군가 이 문제에 대한 해결책을 생각해 줄 수 있습니까?

업데이트 2

이벤트 크기를 조정하는 동안 다양한 요소의 높이와 폭을 업데이트하기 위해 자바스크립트를 사용하여 많은 실험을 한 결과, 그런 방식으로 해결하기에는 너무 복잡하고 번거롭다는 결론에 도달했습니다.또한 자바스크립트를 추가하는 것은 플렉스박스 모델을 분명히 깨뜨리며, 이 모델은 가능한 한 깨끗하게 유지되어야 합니다.

은, 으로 .overflow-y: auto에 대신에flex-wrap: wrap필요할 때 내부 용기가 수직으로 스크롤되도록 합니다.예쁘지는 않지만, 적어도 사용성이 너무 깨지지 않는 것이 한 가지 방법입니다.

더 프로블럼

플렉스 레이아웃의 근본적인 결함으로 보입니다.

열 방향의 플렉스 컨테이너는 추가 열을 수용하기 위해 확장되지 않습니다.(이는 문제가 되지 않습니다.flex-direction: row.)

이 질문은 CSS에서 명확한 답변이 없는 상태에서 여러 번 질문을 받았습니다(아래 목록 참조).

모든 주요 브라우저에서 문제가 발생하기 때문에 버그로 고정하기는 어렵습니다.하지만 이는 의문을 제기합니다.

어떻게 모든 주요 브라우저가 열 방향이 아닌 행 방향으로 랩 상에서 확장할 수 있는 플렉스 컨테이너를 얻을 수 있습니까?

적어도 한 명은 맞힐 거라고 생각하실 겁니다.나는 그 이유를 추측할 수 밖에 없습니다.아마도 기술적으로 어려운 구현이었고 이 반복을 위해 보류되었을 수도 있습니다.

업데이트: Edge v16에서 이 문제가 해결된 것으로 보입니다.


문제 설명

OP는 문제를 설명하는 유용한 데모를 만들었습니다.여기 복사합니다. http://jsfiddle.net/nwccdwLw/1/


해결 방법 옵션

스택 오버플로 커뮤니티의 해킹 솔루션:


추가 분석


동일한 문제를 설명하는 다른 게시물

파티에 늦었지만, 몇 년이 지난 후에도 여전히 이 문제에 부딪치고 있었습니다.그리드를 이용한 해결책을 찾게 되었습니다.사용할 수 있는 컨테이너에

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

codePen에서 flexbox 문제와 그리드 수정 사이를 전환하는 예제가 있습니다. https://codepen.io/MandeeD/pen/JVLdLd

CSS 전용 해결 방법

이 질문을 받은 지 거의 6년이 지났는데도 이 플렉스박스 버그는 여전히 존재합니다. 그래서 여기 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>

방법은 Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δflex-direction: column둘 다 같이 일하죠flex-wrap: wrap그리고.wrap-reverse.

방금 여기서 정말 멋진 퓨어 CSS 작업을 찾았습니다.

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

: set : setwriting-mode: vertical-lr그록서는서록ne는그nv .writing-mode: horizontal-tb∙ ∙하지 않은).JSFiddle의 스타일을 조정해야 했습니다(솔루션에 필요하지 않은 정렬 스타일을 많이 제거).

참고: 댓글에는 파이어폭스가 아닌 크롬 기반 브라우저에서만 작동한다고 나와 있습니다.저는 개인적으로 크롬 테스트만 해봤습니다.이것을 다른 브라우저에서 작동하도록 수정하는 방법이 있거나 이것을 작동시키는 브라우저에 대한 업데이트가 있을 수 있습니다.

이 댓글에 큰 함성을 지릅니다.플렉스박스 항목이 열 모드로 랩핑되면 컨테이너의 너비가 증가하지 않습니다.해당 이슈 스레드를 통해 https://bugs.chromium.org/p/chromium/issues/detail?id=507397#c39 로 이동하게 되었고, 이를 통해 이 JSFiddle로 이동하게 되었습니다.

많은 주요 브라우저들이 수년이 지난 후 이 버그로 인해 어려움을 겪고 있는 것은 유감스러운 일입니다.자바스크립트 해결 방법을 생각해보세요.브라우저 창의 크기가 조정되거나 내용이 요소에 추가될 때마다 이 코드를 실행하여 적절한 너비로 크기를 조정합니다.프레임워크에서 지시를 정의하여 대신 수행할 수 있습니다.

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

아직 해결책이나 적절한 해결책이 제시되지 않았기 때문에, 저는 조금 다른 접근법으로 요청된 행동을 얻을 수 있었습니다.레이아웃을 3개의 다른 디브로 분리하는 대신 모든 아이템을 1디브로 추가하고 그 사이에 디브를 몇 개 더 추가하여 분리를 만들고 있습니다.

제안된 해결책은 3개의 섹션이 있다고 가정할 때 하드 코딩되지만 일반적인 것으로 확장될 수 있습니다.주요 아이디어는 이 레이아웃을 어떻게 달성할 수 있는지 설명하는 것입니다.

  1. 플렉스를 사용하여 물품을 포장하는 컨테이너 디브 1개에 모든 물품 추가
  2. 각 '내부 용기'의 첫 번째 항목(섹션이라고 하겠습니다)에는 클래스가 있어 각 섹션의 분리와 스타일링을 만드는 조작을 할 수 있습니다.
  3. 을 해서.:before각 첫번째 항목에서 각 섹션의 제목을 찾을 수 있습니다.
  4. 을 해서.space을다면 사이의 .
  5. 로부터 space제가 추가하는 섹션의 전체 높이를 커버하지 못할 것입니다.:after절대적인 위치와 흰색 배경으로 섹션을 배치합니다.
  6. 각 섹션의 배경색을 스타일링하기 위해 각 섹션의 첫 번째 항목 안에 디브를 하나 더 추가합니다.나는 절대적인 위치에 있을 것이고 또한 가질 것입니다.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>

저는 이런 식으로 제 문제를 해결했습니다. 저는 그것이 다른 누군가에게 도움이 되기를 바랍니다.

  _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를 사용하면 화면에 요소가 로드된 후 수동으로 포장지의 너비를 설정하는 것이 어렵지 않습니다.너비는 항상 마지막 하위 요소의 오른쪽 점입니다.

반응으로 flex wrapper에 추가되는 어떤 children에 기반하여 레이아웃 변경에 업데이트를 시켰습니다. 그러나 이것은 당신이 wrapper에 children을 추가하거나 제거하는 어떤 지점에서도 호출될 수 있습니다.

let r = refWrapper.current.lastElementChild.getBoundingClientRect()
refWrapper.current.style.width = (r.x+r.width )+'px'

`

여기서 refWrapper는 당신의 플렉스 요소입니다.

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

언급URL : https://stackoverflow.com/questions/33891709/when-flexbox-items-wrap-in-column-mode-container-does-not-grow-its-width

반응형