Masonry Grid Layout System
목적
Masonry Grid Layout System은 다양한 높이의 비균일 콘텐츠 카드(예: 사진 포트폴리오, 사용자 생성 콘텐츠 피드, 혼합 미디어 카드, 편집 비주얼 디스커버리 보드)를 표시하기 위한 표준화된 반응형 디자인 프레임워크를 제공합니다. 표준 CSS 그리드 레이아웃은 행 높이를 강제로 정렬하므로 항목의 종횡비나 텍스트 길이가 다양한 경우 어색한 수직 공백이 발생합니다.
효과적인 벽돌형 그리드를 설계하려면 항목을 동적으로 병렬 수직 열로 패킹하고, 미디어 자산이 로드될 때 CLS(Cumulative Layout Shift)를 방지하고, 모바일에서 우아하게 열을 축소하며, 결정적으로 시각적 레이아웃이 논리적 DOM 읽기 순서 및 키보드 포커스 탐색 순서(WCAG 2.1 SC 1.3.2 및 SC 2.1.1)를 깨뜨리지 않도록 해야 하는 공간적 과제를 해결해야 합니다.
사용 사례
- 사진 및 시각 미디어 포트폴리오: 다양한 기본 종횡비(세로, 가로, 정사각형, 파노라마)의 이미지 갤러리를 빈틈없는 그리드로 표시합니다.
- 소셜 및 UGC 활동 피드: 짧은 텍스트 업데이트, 전문 기사, 포함된 이미지, 비디오 티저가 섞인 소셜 카드를 구성합니다.
- 전자상거래 UGC 및 리뷰 월: 고객 리뷰 사진, 태그된 Instagram 게시물, 제품 하이라이트 스니펫을 동적 디스커버리 쇼케이스로 제공합니다.
- 편집 디스커버리 및 핀보드: 다양한 수직 공간을 차지하는 다양한 콘텐츠 요소가 포함된 카드로 무드보드, 북마크 관리자, 영감 피드를 구축합니다.
사용하지 말아야 할 경우
- 균일 종횡비 그리드: 모든 항목이 동일한 종횡비(예: 표준 16:9 비디오 카드 또는 1:1 제품 카탈로그)를 공유하는 경우
responsive-grid-system또는card-ui-system을 사용하세요. - 구조화된 2D 비대칭 하이라이트: 명시적인 2D 직사각형 스패닝 규칙(예: 1x1 통계 블록 옆 2x2 주요 기능)이 있는 큐레이팅된 히어로 섹션의 경우
bento-grid-layout-system을 사용하세요. - 엄격한 표 형식 또는 정렬된 데이터: 사용자가 가로 행(예: 가격표 또는 재무 지표)에서 값을 비교해야 하는 경우
data-table-ui-system또는comparison-matrix-system을 사용하세요. - 순차적 스토리텔링 및 기사: 읽기 순서가 단일 수직 흐름을 엄격히 따라야 하는 선형 내러티브의 경우
article-layout-system또는section-composition-system을 사용하세요.
입력
- 콘텐츠 인벤토리 및 종횡비: 미디어 및 텍스트 콘텐츠 유형(이미지, 비디오, 텍스트 스니펫, 액션 카드) 및 해당 종횡비 스펙트럼(3:4 세로에서 16:9 가로까지).
- 열 아키텍처 요구 사항: 화면 크기별 대상 열 개수(예: 와이드스크린 데스크톱 4열, 데스크톱 3열, 태블릿 2열, 모바일 1열).
- 상호작용 및 포커스 요구 사항: 키보드 접근성이 필요한 카드 내부의 대화형 요소(버튼, 라이트박스, 인라인 토글, 링크).
- 공간 및 테마 토큰: 유동 열 거터 및 행 간격(
gap: clamp(12px, 2vw, 24px)), 카드 배경 채우기, 테두리 반경 및 포커스 링 토큰(fluid-spacing-system및focus-indicator-design-system에서).
출력
- 벽돌형 레이아웃 아키텍처 명세: 순수 CSS 다중 열 흐름, CSS Grid 행 스패닝(
grid-auto-rows), JavaScript 최단 열 패킹 간의 전략적 선택 및 기술 청사진. - 반응형 열 배율 매트릭스: 부드러운 열 개수 전환 및 간격 배율을 위한 중단점 정의.
- DOM 읽기 순서 및 키보드 포커스 맵: 키보드 탐색(
Tab/Shift+Tab)이 혼란스러운 열 점프 없이 자연스러운 시각적 읽기 순서를 따르도록 보장하는 아키텍처. - 레이아웃 안정성 및 종횡비 보존 규칙: 이미지 및 미디어 로딩 중 CLS(Cumulative Layout Shift)를 방지하는 CSS 아키텍처.
워크플로우
1. 아키텍처 전략 선택
상호작용 및 읽기 순서 요구 사항에 따라 적절한 레이아웃 기술을 선택합니다.
- 옵션 A: 순수 CSS 다중 열 레이아웃(
column-count)- 최적 대상: 정적 갤러리, 이미지가 많은 피드, 또는 흐름 순서가 열 1 아래로, 그다음 열 2 등으로 실행될 수 있는 비대화형 카드.
- 구현:
column-count: 4; column-gap: var(--space-m);. 자식 카드에break-inside: avoid; margin-bottom: var(--space-m);설정. - 트레이드오프: 수직 소스 순서(열 내에서 위에서 아래로)는 카드에 대화형 컨트롤이 포함된 경우 키보드 사용자를 혼란스럽게 할 수 있습니다.
- 옵션 B: 행 스팬이 있는 CSS Grid (
grid-auto-rows및grid-row: span X)- 최적 대상: 카드 높이를 고정 행 트랙 단위(예:
10px기본 트랙)로 양자화할 수 있는 반정적 그리드. - 구현:
display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); grid-auto-rows: 10px; gap: 16px;. JavaScript가 콘텐츠 높이를 계산하고grid-row: span Math.ceil(height / trackHeight)를 적용합니다. - 트레이드오프: 기본 가로 DOM 순서가 유지되지만 약간의 JS 높이 계산이나 컨테이너 쿼리가 필요합니다.
- 최적 대상: 카드 높이를 고정 행 트랙 단위(예:
- 옵션 C: JavaScript 최단 열 컨테이너 분배
- 최적 대상: 왼쪽에서 오른쪽으로 읽는 순서가 가장 중요하고 카드에 링크, 버튼 및 양식 컨트롤이 포함된 상호작용성이 높은 혼합 미디어 피드.
- 구현: $N$개의 flex 열 컨테이너 생성(
display: flex; flex-direction: column; gap: var(--space-m);). 들어오는 카드를 현재 총 렌더링 높이가 가장 짧은 열에 추가합니다. - 트레이드오프: 클라이언트 측 DOM 컨테이너 관리가 필요하지만 완벽한 왼쪽에서 오른쪽 DOM 포커스 흐름과 제로 시각적 수직 간격을 보장합니다.
2. 공간 리듬 및 열 거터 정의
모든 열 및 카드 내부 패딩에 걸쳐 일관된 간격 토큰을 설정합니다.
- 열 거터: 유동 간격 사용(예:
gap: clamp(16px, 2.5vw, 28px)). 쌓인 카드 사이의 수직 간격이 균일한 공간 밀도를 유지하도록 가로 열 간격과 동일한지 확인합니다. - 카드 패딩 및 내부 정렬: 유동 토큰을 사용하여 내부 카드 패딩을 표준화합니다(
padding: var(--space-m)). 미디어 전용 카드(예: 라이트박스 트리거)의 경우 이미지가 가장자리에서 가장자리로 번질 수 있도록 합니다(padding: 0; overflow: hidden;). - 모서리 반경 동기화: 외부 카드 컨테이너에 일관된 border-radius를 적용합니다(예:
12px~16px). 내부 요소(예: 상단 이미지)가 동심 모서리 반경을 상속하는지 확인합니다(border-top-left-radius: calc(var(--card-radius) - 1px)).
3. 레이아웃 변경(CLS) 및 이미지 왜곡 방지
벽돌형 그리드는 이미지 로딩 중 CLS(Cumulative Layout Shift)에 매우 취약합니다.
- 종횡비 상자: 이미지 컨테이너에
aspect-ratio를 명시적으로 선언(aspect-ratio: 4 / 5; object-fit: cover; width: 100%; display: block;)하거나 미디어가 확인되기 전에 인라인 패딩 비율을 계산합니다. - 스켈레톤 플레이스홀더: 원격 자산이 로드되는 동안 예상 카드 종횡비와 일치하는 스타일링된 스켈레톤 배경 펄스를 렌더링합니다(
background: var(--surface-subtle); animation: pulse 1.5s infinite;). - 이미지 로드 리스너: JS 높이 계산을 사용하는 경우
ResizeObserver또는 이미지load이벤트 리스너를 바인딩하여 이미지 렌더링이 완료되면 열 높이 할당을 다시 계산합니다.
4. DOM 읽기 순서 및 포커스 관리 조정
WCAG 1.3.2(의미 있는 순서) 및 2.1.1(키보드)을 준수해야 합니다.
- 시각적-DOM 연결 해제 방지: CSS 열을 사용하여 시각적 레이아웃이 수직으로 열 아래로 흐르는 경우 키보드 포커스 표시기가 명확하고 논리적인지 확인합니다. 카드에 대화형 컨트롤이 포함된 경우 자연스러운 왼쪽에서 오른쪽, 위에서 아래로의 탭 순서(
Tab키 순서)를 유지하기 위해 JavaScript 최단 열 분배 또는 CSS Grid 행 스패닝을 선호합니다. - 포커스 표시기 가시성: 고대비, 클리핑되지 않은 포커스 표시기 표준화(
outline: 3px solid var(--focus-ring-color); outline-offset: 3px;). 클립 경계 내에 충분한 포커스 표시기 패딩을 추가하지 않고 카드에overflow: hidden을 사용하지 마십시오. - 라이트박스/모달용 키보드 단축키: 벽돌형 카드를 클릭하여 모달 오버레이나 라이트박스를 여는 경우 오버레이 내에 키보드 포커스를 트랩(
focus-trap)하고 해제 시(Escape키) 원래 카드 트리거로 포커스를 되돌립니다.
5. 반응형 열 배율 구현
콘텐츠 균형을 깨뜨리지 않고 열 개수를 우아하게 조정하는 중단점을 설계합니다.
- 와이드스크린 데스크톱 (≥ 1440px): 4열 (
column-count: 4또는 4개의 flex 열 트랙). - 표준 데스크톱 (1024px – 1439px): 3열 (
column-count: 3또는 3개의 flex 열 트랙). - 태블릿 / 소형 화면 (640px – 1023px): 2열 (
column-count: 2또는 2개의 flex 열 트랙). - 모바일 (< 640px): 1열 (
column-count: 1또는 단일 수직 스택). 모든 항목이 표준 수직 간격으로 자연스럽게 쌓입니다.
의사 결정 규칙
아키텍처 선택 매트릭스
| 콘텐츠 및 상호작용 유형 | 권장 아키텍처 전략 | 근거 |
|---|---|---|
| 순수 이미지 갤러리 (라이트박스 트리거) | CSS 다중 열 (column-count) | JS 제로, 브라우저 네이티브 다중 열 성능, 깔끔한 수직 이미지 벽돌형. |
| 대화형 카드 (버튼, 입력, 링크) | JS 최단 열 Flex 분배 | 엄격한 왼쪽에서 오른쪽 DOM 탭 순서를 유지하여 스크린 리더 및 키보드 포커스 점프를 방지합니다. |
| 동적 로딩 피드 (무한 스크롤) | CSS Grid 행 스패닝 또는 JS 열 분배 | 전체 페이지 레이아웃을 재배치하지 않고 새 카드를 가장 짧은 열에 부드럽게 추가할 수 있습니다. |
| 텍스트 중심 편집 핀보드 | CSS Grid 행 스패닝 (grid-auto-rows: 10px) | 다양한 텍스트 길이를 정확하게 수용하면서 가로 읽기 순서를 유지합니다. |
제약 조건
- 접근성 (WCAG 2.1 AA 준수):
- SC 1.3.2 의미 있는 순서: 대화형 카드의 시각적 배열이 키보드 탭 탐색 순서(
tabindex="0"포커스 흐름)와 논리적으로 정렬되어야 합니다. - SC 1.4.3 명암비 (최소): 카드 표면이나 이미지 오버레이 위에 렌더링된 텍스트는 최소 4.5:1 명암비를 충족해야 합니다. 이미지 위에 직접 배치된 텍스트에는 어두운 스크림 오버레이(
background: linear-gradient(to top, rgba(0,0,0,0.8), transparent))를 사용해야 합니다. - SC 2.1.1 키보드: 모든 대화형 카드 요소(버튼, 북마크 트리거, 외부 링크 등)는
Space및Enter키를 통해 완전히 작동할 수 있어야 합니다. - SC 2.4.7 포커스 가시성: 대화형 카드 및 트리거는 상위 카드
overflow: hidden속성에 의해 클리핑되지 않는 명확한 포커스 링을 표시해야 합니다. - SC 2.5.8 대상 크기: 벽돌형 카드 내의 모든 터치 대상은 최소 24x24px (터치/모바일 뷰포트에서는 최소 44x44px)의 대화형 영역을 유지해야 합니다.
- SC 1.3.2 의미 있는 순서: 대화형 카드의 시각적 배열이 키보드 탭 탐색 순서(
- 레이아웃 변경 성능: 벽돌형 카드 내의 이미지는 CLS가 0.1 미만으로 유지되도록 명시적으로 정의된 고유 종횡비 또는 크기 예약이 있어야 합니다.
일반적인 실패 패턴
- 키보드 탭 혼란: 대화형 카드에 CSS
column-count를 사용하여 키보드Tab키가 열 2의 맨 위로 다시 점프하기 전에 첫 번째 열 전체(항목 1에서 항목 10까지)를 수직으로 이동하게 합니다. - CLS(Cumulative Layout Shift) 혼란: 종횡비 스타일링이나 로딩 스켈레톤 없이 이미지를 삽입하여 각 이미지가 로드될 때 벽돌형 열이 반복적으로 재배치되고 점프하게 합니다.
- 클리핑된 포커스 링: 둥근 이미지 모서리를 적용하기 위해 벽돌형 카드에
overflow: hidden을 설정하면 내부 대화형 요소의 표준 개요 포커스 링이 잘립니다. - 모바일에서 제약되지 않은 열 높이: 모바일 장치에서 벽돌형 그리드를 단일 열로 축소하지 못하여 매우 좁고 찌그러진 다중 열 카드와 읽을 수 없는 텍스트 줄바꿈이 발생합니다.
- 고르지 않은 열 개수: 열 높이를 확인하는 대신 동적 피드에 새 항목을 열 전체에 순차적으로 추가(1, 2, 3, 1, 2, 3)하여 짧은 열 하단에 거대한 수직 빈 공간을 만듭니다.
검증 기준
- 아키텍처 정렬: 선택한 전략(CSS Columns 대 CSS Grid Row-Span 대 JS Shortest-Column)이 카드 상호작용 요구 사항과 일치합니다.
- 의도하지 않은 수직 간격 제로: 카드가 가로 행 정렬 공백 없이 빽빽하게 채워집니다.
- 키보드 탭 탐색: 대화형 카드가 논리적인 시각적 탭 순서(왼쪽에서 오른쪽, 위에서 아래로)를 따릅니다.
- 레이아웃 변경 방지: 종횡비 또는 스켈레톤 컨테이너가 원격 미디어 로드 시 CLS(<0.1)를 방지합니다.
- 반응형 중단점 적응: 그리드가 와이드스크린의 4열에서 모바일(<640px)의 단일 수직 열까지 부드럽게 조정됩니다.
- WCAG AA 준수: 모든 텍스트가 ≥4.5:1 명암비를 충족하고, 터치 대상이 ≥24x24px(모바일에서 ≥44x44px)이며, 포커스 링이 클리핑되지 않고 명확하게 보입니다.