flexbox 항목이 열 모드로 줄 바꿈 될 때 컨테이너의 너비가 커지지 않습니다


167

중첩 된 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 은 지금까지 내가 가지고있는 것을 보여줍니다.

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

내가 원하는 출력

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

내 현재 출력

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

내 오래된 출력

최신 정보

약간의 조사가 끝나면 더 큰 문제처럼 보이기 시작합니다. 모든 주요 브라우저는 동일한 방식으로 작동하며 내 flexbox 디자인과 중첩되지 않습니다. 더 간단한 flexbox 열 레이아웃조차도 항목을 줄 바꿈 할 때 목록의 너비를 늘리지 않습니다.

다른 JSFiddle 은 문제를 분명히 보여줍니다. 현재 버전의 Chrome, Firefox 및 IE11에서는 모든 항목이 올바르게 줄 바꿈됩니다. 목록의 높이는 row모드에서 증가 하지만 너비는 column모드 에서 증가하지 않습니다 . 또한 column모드 의 높이를 변경할 때 요소가 즉시 리플 로우되지 않지만 row모드가 있습니다.

그러나 공식 사양 (특히 예 5 참조) 은 내가하고 싶은 일이 가능해야 함을 나타내는 것으로 보입니다.

누군가이 문제에 대한 해결 방법을 제안 할 수 있습니까?

업데이트 2

크기 조정 이벤트 중에 다양한 요소의 높이와 너비를 업데이트하기 위해 JavaScript를 사용하여 많은 실험을 한 후에는 너무 복잡하고 그렇게 해결하기가 너무 어렵다는 결론에 도달했습니다. 또한 JavaScript를 추가하면 flexbox 모델이 깨져서 최대한 깨끗하게 유지해야합니다.

지금 은 내부 컨테이너가 필요할 때 세로로 스크롤되도록 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

답변:


170

문제

이것은 플렉스 레이아웃의 근본적인 결함처럼 보입니다.

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

이 질문은 CSS에서 명확한 대답없이 여러 번 요청되었습니다 (아래 목록 참조).

이 문제는 모든 주요 브라우저에서 발생하기 때문에 버그로 고정하기가 어렵습니다. 그러나 그것은 질문을 제기합니다 :

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

당신은 그들 중 적어도 하나가 그것을 올바르게 얻을 것이라고 생각할 것입니다. 나는 그 이유에 대해서만 추측 할 수 있습니다. 기술적으로 어려운 구현 일 수도 있고이 반복을 위해 보류 된 것일 수도 있습니다.

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


문제의 예

OP는 문제를 보여주는 유용한 데모를 만들었습니다. 여기에 복사하고 있습니다 : http://jsfiddle.net/nwccdwLw/1/


해결 방법 옵션

Stack Overflow 커뮤니티의 해키 솔루션 :


추가 분석


같은 문제를 설명하는 다른 게시물


2
그들은 그들의 새로운 레이아웃 엔진 해제 될 때까지 버그 리포트의 의견에 따르면,이 문제가 해결되지 않습니다 LayoutNG
Ben.12

5
귀하가 제공하고 분류 한 링크의 수는 정말 좋습니다. 대부분의 사람들이 이런 식으로 답을 쓰길 바랍니다. 좋은 대답입니다.
Vignesh

4
다음은 몇 가지 Flexbox 버그와 이에 대한 해결 방법을 나열한 유용한 저장소입니다. 이 버그는 # 14
Ben.12

CSS 그리드를 사용하여이 문제를 해결할 수 있습니까?
Ismail Farooq

또 다른 해결 방법은 다음과 같습니다. codepen.io/_mc2/pen/PoPmJRP 일부 측면에서 쓰기 모드 접근 방식이 더 좋습니다
michalczerwinski

37

파티에 늦었지만 나중에이 문제가 계속 발생했습니다. 그리드를 사용하여 솔루션을 찾았습니다. 컨테이너에서 사용할 수 있습니다

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

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


1
내가 본 적이 있다면 그것은 우아한 해결책입니다! 나는 방금 그리드에 들어가고 있으며 솔루션을 좋아합니다. 감사합니다.
Albert

에 딱 맞다! 내 문제를 해결했습니다.
Celestin Bochis

Chrome에서이 문제가 계속 발생합니다. 그리드 해결 방법을 사용하지 않기를 바랐습니다. 다른 사람들이이 방법을 사용하고 있다는 것을 알게되어 기쁩니다!
trukvl

생명의 은인. grid-row-end: span X;더 많은 행을 차지하기 위해 일부 항목이 필요한 경우 에도 사용할 수 있습니다 .
Meirion Hughes

0

많은 주요 브라우저가 수년 후에이 버그로 고통받는 것은 유감입니다. 자바 스크립트 해결 방법을 고려하십시오. 브라우저 창의 크기가 조정되거나 컨텐츠가 요소에 추가 될 때마다이 코드를 실행하여 적절한 너비로 크기를 조정하십시오. 프레임 워크에서 지시문을 정의하여이를 수행 할 수 있습니다.

    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에서 스타일을 조정해야했습니다 (솔루션에 필요하지 않은 많은 정렬 스타일을 제거하십시오).

참고 : 의견에 따르면 Firefox가 아닌 Chromium 기반 브라우저에서만 작동합니다. Chrome에서만 개인적으로 테스트했습니다. 다른 브라우저에서 작동하도록 수정하거나 다른 브라우저에서 작동하도록하는 방법이있을 수 있습니다.

이 의견에 대한 큰 소리 : flexbox 항목이 열 모드로 줄 바꿈되면 컨테이너의 너비가 커지지 않습니다 . 이 문제 스레드 를 파헤쳐 서 https://bugs.chromium.org/p/chromium/issues/detail?id=507397#c39로 연결되어이 JSFiddle로 연결되었습니다.


-1

해결책이나 적절한 해결 방법이 아직 제안되지 않았으므로 약간 다른 접근 방식으로 요청 된 동작을 얻을 수있었습니다. 레이아웃을 3 개의 다른 div로 분리하는 대신 모든 항목을 1 div에 추가하고 사이에 더 많은 div가있는 분리를 만듭니다.

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

  1. flex를 사용하여 항목을 감싸는 하나의 컨테이너 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

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.