CSS 전용 벽돌 레이아웃


134

상당히 낡은 벽돌 레이아웃을 구현해야합니다. 그러나 여러 가지 이유로 JavaScript를 사용하여 원하지 않습니다.

높이가 변하는 사각형의 여러 열 그리드입니다.

매개 변수 :

  • 모든 요소의 너비가 동일합니다
  • 요소는 서버 측에서 계산할 수없는 높이를 갖습니다 (이미지와 다양한 양의 텍스트)
  • 필요한 경우 고정 된 수의 열로 살 수 있습니다

현대적인 브라우저에서 작동이에 대한 사소한 해결책이 속성.column-count

해당 솔루션의 문제점은 요소가 열로 정렬된다는 것입니다.

맨 왼쪽 상자부터 시작하여 1부터 4까지 번호가 매겨지고 다음 열의 맨 위 상자는 5입니다.

요소를 적어도 행 단위로 주문해야하지만 적어도 대략 다음과 같습니다.

맨 왼쪽 상자부터 시작하여 1에서 6까지 번호가 매겨 지지만 상자 5는 가장 짧은 상자이므로 맨 왼쪽의 다음 상자보다 높은 행에있는 것처럼 보입니다.

내가 시도한 접근법이 작동하지 않습니다.

지금은 내가 좋아하는 것, 그래서 오류가 발생하기 쉬운 (브라우저 열로 항목 목록을 분할하기로 결정 방법에 따라), 서버 측 렌더링 및 열 수에 의해 항목의 수를 나누어 재주문 항목을 변경할 수 있지만, 그 복잡 가능하면 피하십시오.

이것을 가능하게하는 새로운 신형 flexbox 마술이 있습니까?


7
사전 정의 된 높이에 의존하지 않는 방법을 생각할 수 없습니다. JS를 다시 생각하면 stackoverflow.com/questions/13518653 / ...을 살펴보십시오. 여기서 매우 간단한 솔루션을 구현합니다.
Gabriele Petrioli

1
@Gaby는 지금 솔루션을 구현하고 있습니다. 감사합니다!
Pekka

4
나는 당신이 CSS 전용이라고 말한 것을 알고 있습니다. Masonry는 더 이상 jQuery가 필요하지 않습니다. 축소 라이브러리는 8kb 미만 이며 html만으로 초기화 할 수 있습니다. 그냥 참조 jsfiddle.net/wp7kuk1t
나는

1
선 높이, 글꼴 크기 (특정 글꼴을 제공하고 영리한 계산을 수행해야 함), 이미지 높이, verticle margin 및 padding을 알고 요소의 높이를 미리 결정할 수 있다면 이 작업을 수행. 그렇지 않으면 CSS 만 사용하여이 작업을 수행 할 수 없습니다. PhantomJS와 같은 것을 사용하여 각 요소를 사전 렌더링하고 해당 요소의 높이를 얻을 수 있지만 상당한 오버 헤드 / 대기 시간이 추가됩니다.
Timothy Zorn

답변:


157

플렉스 박스

최소한 깨끗하고 효율적인 방식으로 flexbox를 사용하면 동적 석조 레이아웃을 사용할 수 없습니다.

Flexbox는 1 차원 레이아웃 시스템입니다. 즉, 가로 또는 세로 선을 따라 항목을 정렬 할 수 있습니다. 플렉스 항목은 해당 행 또는 열로 제한됩니다.

진정한 그리드 시스템은 2 차원이므로 가로 및 세로 선을 따라 항목을 정렬 할 수 있습니다. 내용 항목은 행과 열에 동시에 걸쳐있을 수 있지만, 플렉스 항목은 할 수 없습니다.

이것이 flexbox의 그리드 구축 용량이 제한된 이유입니다. W3C가 또 다른 CSS3 기술인 Grid Layout을 개발 한 이유이기도합니다 .


row wrap

가있는 플렉스 컨테이너 flex-flow: row wrap에서 플렉스 항목은 새 행으로 줄 바꿈되어야합니다 .

, 플렉스 항목은 같은 행의 다른 항목으로 줄 바꿈 할 수 없습니다 .

div # 3이 div # 1 아래로 어떻게 래핑되어 새 행을 만드는지 살펴보십시오 . div # 2 아래를 감쌀 수 없습니다 .

결과적으로, 항목이 행에서 가장 키가 크지 않으면 공백이 남아있어보기 흉한 간격을 만듭니다.


column wrap

로 전환 flex-flow: column wrap하면 그리드와 유사한 레이아웃을 얻을 수 있습니다. 그러나 열 방향 컨테이너에는 바로 다음과 같은 네 가지 잠재적 문제가 있습니다.

  1. 플렉스 아이템은 수평이 아닌 수직으로 흐릅니다 (이 경우 필요에 따라).
  2. 컨테이너는 수직이 아닌 수평으로 확장됩니다 (Gateway 레이아웃과 같이).
  3. 컨테이너의 높이가 고정되어 있어야 항목을 감쌀 위치를 알 수 있습니다.
  4. 이 글을 쓰는 시점 에서 컨테이너가 추가 열을 수용하도록 확장되지 않는 모든 주요 브라우저에는 결함이 있습니다 .

결과적으로 열 방향 컨테이너는이 경우와 다른 많은 경우에 옵션이 아닙니다.


항목 크기가 정의되지 않은 CSS 그리드

다양한 높이의 컨텐트 항목을 미리 결정할 수있는 경우 그리드 레이아웃은 문제에 대한 완벽한 솔루션 입니다. 다른 모든 요구 사항은 Grid의 용량 내에 있습니다.

주변 항목과의 간격을 메우려면 격자 항목의 너비와 높이를 알아야합니다.

따라서 가로로 흐르는 벽돌 레이아웃을 구축하기 위해 CSS에서 제공해야하는 최고의 CSS 인 Grid는이 경우 부족합니다.

사실, CSS 기술이 자동으로 틈을 메울 수있을 때까지 CSS는 일반적으로 해결책이 없습니다. 이와 같은 것은 아마도 문서를 리플 로우해야 할 것이므로 얼마나 유용하고 효율적인지 잘 모르겠습니다.

스크립트가 필요합니다.

JavaScript 솔루션은 절대 위치 지정을 사용하는 경향이 있으며, 이는 문서 흐름에서 컨텐츠 항목을 제거하여 간격없이 다시 정렬합니다. 다음은 두 가지 예입니다.


항목 크기가 정의 된 CSS 그리드

컨텐트 항목의 너비와 높이가 알려진 레이아웃의 경우 순수 CSS의 가로로 흐르는 벽돌 레이아웃이 있습니다.

grid-container {
  display: grid;                                                /* 1 */
  grid-auto-rows: 50px;                                         /* 2 */
  grid-gap: 10px;                                               /* 3 */
  grid-template-columns: repeat(auto-fill, minmax(30%, 1fr));   /* 4 */
}

[short] {
  grid-row: span 1;                                             /* 5 */
  background-color: green;
}

[tall] {
  grid-row: span 2;
  background-color: crimson;
}

[taller] {
  grid-row: span 3;
  background-color: blue;
}

[tallest] {
  grid-row: span 4;
  background-color: gray;
}

grid-item {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.3em;
  font-weight: bold;
  color: white;
}
<grid-container>
  <grid-item short>01</grid-item>
  <grid-item short>02</grid-item>
  <grid-item tall>03</grid-item>
  <grid-item tall>04</grid-item>
  <grid-item short>05</grid-item>
  <grid-item taller>06</grid-item>
  <grid-item short>07</grid-item>
  <grid-item tallest>08</grid-item>
  <grid-item tall>09</grid-item>
  <grid-item short>10</grid-item>
  <grid-item tallest>etc.</grid-item>
  <grid-item tall></grid-item>
  <grid-item taller></grid-item>
  <grid-item short></grid-item>
  <grid-item short></grid-item>
  <grid-item short></grid-item>
  <grid-item short></grid-item>
  <grid-item tall></grid-item>
  <grid-item short></grid-item>
  <grid-item taller></grid-item>
  <grid-item short></grid-item>
  <grid-item tall></grid-item>
  <grid-item short></grid-item>
  <grid-item tall></grid-item>
  <grid-item short></grid-item>
  <grid-item short></grid-item>
  <grid-item tallest></grid-item>
  <grid-item taller></grid-item>
  <grid-item short></grid-item>
  <grid-item tallest></grid-item>
  <grid-item tall></grid-item>
  <grid-item short></grid-item>
</grid-container>

jsFiddle 데모


작동 원리

  1. 블록 레벨 그리드 컨테이너를 설정하십시오. ( inline-grid다른 옵션이 될 것입니다)
  2. grid-auto-rows속성은 자동으로 생성 된 행의 높이를 설정합니다. 이 격자에서 각 행의 키는 50px입니다.
  3. grid-gap속성은 grid-column-gap및 의 약어입니다 grid-row-gap. 이 규칙 모눈 항목 사이에 10px 간격을 설정 합니다. (항목과 컨테이너 사이의 영역에는 적용되지 않습니다.)
  4. grid-template-columns속성은 명시 적으로 정의 된 열의 너비를 설정합니다.

    repeat표기 반복 열 (또는 행)의 패턴을 정의한다.

    auto-fill함수는 컨테이너에 오버플로없이 가능한 한 많은 열 (또는 행)을 정렬하도록 그리드에 지시합니다. (이것은 레이아웃을 조정하는 것과 비슷한 동작을 만들 수 있습니다 flex-wrap: wrap.)

    minmax()함수는 각 열 (또는 행)의 최소 및 최대 크기 범위를 설정합니다. 위의 코드에서 각 열의 너비는 컨테이너의 최소 30 %이며 사용 가능한 여유 공간이 최대가됩니다.

    fr부는 그리드 용기 내의 빈 공간의 일부를 나타낸다. flexbox의 flex-grow속성 과 비슷 합니다.

  5. grid-row그리고 span우리는 그들이에 걸쳐해야 얼마나 많은 행 그리드 항목을 말하는 것입니다.


CSS 그리드에 대한 브라우저 지원

  • Chrome-2017 년 3 월 8 일 (버전 57)부터 완전 지원
  • Firefox-2017 년 3 월 6 일 (버전 52) 전체 지원
  • Safari-2017 년 3 월 26 일 (버전 10.1)부터 완벽 지원
  • Edge-2017 년 10 월 16 일 (버전 16) 기준 완벽 지원
  • IE11-현재 사양을 지원하지 않습니다. 더 이상 사용되지 않는 버전 지원

완전한 그림은 다음과 같습니다. http://caniuse.com/#search=grid


Firefox의 멋진 그리드 오버레이 기능

Firefox 개발자 도구에서 그리드 컨테이너를 검사 할 때 CSS 선언에 작은 그리드 아이콘이 있습니다. 클릭하면 페이지에 그리드의 개요가 표시됩니다.

자세한 내용은 https://developer.mozilla.org/en-US/docs/Tools/Page_Inspector/How_to/Examine_grid_layouts


5
환상적인 답변! "항목 치수가 정의 된 CSS 그리드"솔루션을 사용하여 셀 높이를 셀 너비의 백분율로 표현할 수 있습니까? 이것은 종횡비가 알려진 이미지를 표시하는 데 유용합니다. 항상 종횡비를 유지하고 싶습니다.
Oliver Joseph Ash

감사. 이미지의 가로 세로 비율 문제, "셀 너비 백분율"방법 (패딩 비율 백분율)에 대해서는 Grid 또는 Flexbox에서 그 문제에 대해 신뢰할 수 없습니다. 여기여기를 참조 하십시오 . @OliverJosephAsh
Michael Benjamin

예, 백분율 패딩 트릭을 말합니다. 벽돌 레이아웃 솔루션과 함께 해결 방법을 사용할 수 있습니까? 문맥 상, unsplash.com 의 이미지에 CSS 전용 석조 레이아웃을 구현 하려고 합니다.
Oliver Joseph Ash

1
불행히도 JS를 사용하는 것은 옵션이 아닙니다. 성능 및 SEO 이유로 서버 측 렌더링을 사용하려고합니다. 즉, 클라이언트 측 JavaScript가 다운로드, 파싱 및 실행되기 전에 레이아웃을 렌더링해야합니다. 이것이 불가능한 것처럼 보이면, 우리는 어딘가에서 거래를해야 할 것 같습니다! 도와 주셔서 감사합니다 :-)
Oliver Joseph Ash

1
사양 업데이트 : flexbox에서 컨테이너의 인라인 크기를 다시 확인하도록 백분율 여백 및 패딩이 설정되었습니다. drafts.csswg.org/css-flexbox/#item-margins @OliverJosephAsh
Michael Benjamin

13

이는 최근 기술 관련 인 flexbox을 발견 : https://tobiasahlin.com/blog/masonry-with-css/ .

이 기사는 나에게 의미가 있지만, 그것을 사용하려고 시도하지 않았으므로 Michael의 대답에 언급 된 것 외에 다른주의 사항이 있는지 알 수 없습니다.

다음은와 order속성 을 사용하여 기사의 샘플 입니다 :nth-child.

스택 스 니펫

.container {
  display: flex;
  flex-flow: column wrap;
  align-content: space-between;
  /* Your container needs a fixed height, and it 
   * needs to be taller than your tallest column. */
  height: 960px;
  
  /* Optional */
  background-color: #f7f7f7;
  border-radius: 3px;
  padding: 20px;
  width: 60%;
  margin: 40px auto;
  counter-reset: items;
}

.item {
  width: 24%;
  /* Optional */
  position: relative;
  margin-bottom: 2%;
  border-radius: 3px;
  background-color: #a1cbfa;
  border: 1px solid #4290e2;
  box-shadow: 0 2px 2px rgba(0,90,250,0.05),
    0 4px 4px rgba(0,90,250,0.05),
    0 8px 8px rgba(0,90,250,0.05),
    0 16px 16px rgba(0,90,250,0.05);
  color: #fff;
  padding: 15px;
  box-sizing: border-box;
}

 /* Just to print out numbers */
div.item::before {
  counter-increment: items;
  content: counter(items);
}

/* Re-order items into 3 rows */
.item:nth-of-type(4n+1) { order: 1; }
.item:nth-of-type(4n+2) { order: 2; }
.item:nth-of-type(4n+3) { order: 3; }
.item:nth-of-type(4n)   { order: 4; }

/* Force new columns */
.break {
  flex-basis: 100%;
  width: 0;
  border: 1px solid #ddd;
  margin: 0;
  content: "";
  padding: 0;
}

body { font-family: sans-serif; }
h3 { text-align: center; }
<div class="container">
  <div class="item" style="height: 140px"></div>
  <div class="item" style="height: 190px"></div>
  <div class="item" style="height: 170px"></div>
  <div class="item" style="height: 120px"></div>
  <div class="item" style="height: 160px"></div>
  <div class="item" style="height: 180px"></div>
  <div class="item" style="height: 140px"></div>
  <div class="item" style="height: 150px"></div>
  <div class="item" style="height: 170px"></div>
  <div class="item" style="height: 170px"></div>
  <div class="item" style="height: 140px"></div>
  <div class="item" style="height: 190px"></div>
  <div class="item" style="height: 170px"></div>
  <div class="item" style="height: 120px"></div>
  <div class="item" style="height: 160px"></div>
  <div class="item" style="height: 180px"></div>
  <div class="item" style="height: 140px"></div>
  <div class="item" style="height: 150px"></div>
  <div class="item" style="height: 170px"></div>
  <div class="item" style="height: 170px"></div>
  
  <span class="item break"></span>
  <span class="item break"></span>
  <span class="item break"></span>
</div>


첫째, 링크 만 답변은 링크가 죽을 때와 같이 나쁜 답변입니다. 둘째, 주어진 답변을 더 자세히 읽으면 링크에 언급 된 내용이 포함되어 있음을 알 수 있습니다. 간단히 말해서 위에서 언급 한 내용이 문제가되지 않는 한 Flexbox 만 사용하는 데 너무 많은 제한이 있습니다.
Ason

3
승인 된 답변을 매우 자세히 읽었으며 그 아래에 추가 한 의견도 볼 수 있습니다. 내가 연결 한 flexbox 접근 방식은 독특하며 그 대답으로 다루지 않습니다. 나는 기사가 매우 복잡하기 때문에 기사를 반복하고 싶지 않으며 기사는 그것을 다루는 데 큰 도움이됩니다.
Oliver Joseph Ash

링크 된 것과 다른 점은 order속성 을 사용하는 것입니다. 항목이 왼쪽에서 오른쪽으로 흐르는 것처럼 보입니다. 여전히 주요 트릭은 flex-flow: column wrap위의 답변에서 언급됩니다. 또한 실제 벽돌과 같은 방식으로 항목을 흐르게 할 수 없습니다. 예를 들어 3, 4 번째 항목이 3 번째 열에 맞으면 연결된 항목은 그렇지 않습니다. 그러나 내가 말했듯이, 그것은 모두 요구 사항이 무엇인지에 달려 있으며,이 경우 (이 질문), 요청 한대로 작동하지 않습니다.
Ason

또한, "기사를 반복하고 싶지 않다" 는 것이 아닙니다 . 답은 코드의 필수 부분을 포함해야하므로 링크 된 리소스가 죽을 때도 여전히 유효합니다.
Ason

3
나는 그것을 업데이트하고 기사 + upvote의 샘플을 추가했습니다.
Ason
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.