ResponsiveGrid | CoUI
LogoCoUI

ResponsiveGrid

N × M 셀의 반응형 그리드 레이아웃 with col/row span

ResponsiveGrid#

지정된 columns 개의 균등 너비 셀에 자식을 그리드로 배치합니다. responsive: true 일 때 CoreBreakpoint에 맞춰 컬럼 수가 자동 감소합니다 (기본: md 이하 1열, lg 이하 2열, lg 이상 columns열). GridItem으로 감싸 colSpan/rowSpan을 적용하면 여러 셀을 차지합니다.

Live Preview#

사용 시기 (When to Use)#

이 컴포넌트를 사용하세요:

  • 대시보드처럼 N × M 셀의 카드/모듈을 배치할 때
  • 뷰포트 폭에 따라 열 수가 달라져야 할 때
  • Wrap이나 flex보다 명시적으로 열 수를 정하고 싶을 때

대신 다른 컴포넌트를 사용하세요:

  • ResponsiveContainer: 단일 콘텐츠를 화면 중앙에 max-width로 제약
  • Row / flex: 1행 배치
  • Wrap / flex-wrap: 셀 너비가 content 기반인 경우

기본 사용법 (Basic Usage)#

ResponsiveGrid(
  columns: 3,
  cellSpacing: CoreSpace.space16,
  children: [
    for (var i = 1; i <= 6; i++)
      Card(
        cardStyle: const CoreCardStyle(
          padding: CoreEdgeInsets.all(CoreSpace.space16),
        ),
        child: Text('Item $i'),
      ),
  ],
)

col/row span#

ResponsiveGrid(
  columns: 4,
  cellSpacing: CoreSpace.space16,
  responsive: false,
  children: [
    GridItem(colSpan: 2, child: Card(child: Text('Wide'))),
    Card(child: Text('Cell')),
    Card(child: Text('Cell')),
    GridItem(rowSpan: 2, child: Card(child: Text('Tall'))),
    // ...
  ],
)

반응형 커스터마이징#

기본 breakpoint 매핑을 덮어쓰려면 breakpoints를 제공:

ResponsiveGrid(
  columns: 6,
  breakpoints: {
    CoreBreakpoint.xs: 1,
    CoreBreakpoint.sm: 2,
    CoreBreakpoint.md: 3,
    CoreBreakpoint.lg: 4,
    CoreBreakpoint.xl: 5,
    CoreBreakpoint.xxl: 6,
  },
  children: [...],
)

Props / Parameters#

ResponsiveGrid#

속성타입기본값설명
children List<Widget> / List<Component> required 그리드 셀
columns int? null → theme → 12 가장 넓은 breakpoint에서의 컬럼 수
cellSpacing double? null → theme → CoreSpace.space16 셀 사이 간격 (logical px)
responsive bool? null → theme → true breakpoint 기반 반응형 활성화
breakpoints Map<CoreBreakpoint, int>? null → theme → 기본 곡선 명시적 breakpoint → 컬럼 매핑
responsiveGridStyle CoreResponsiveGridStyle? null 위 네 값의 테마 차원 default 를 담는 단일 슬롯 ( columns / cellSpacing / responsive / breakpoints )

GridItem#

속성타입기본값설명
child Widget / Component required 셀 내용
colSpanint?null → 1차지할 컬럼 수
rowSpanint?null → 1차지할 행 수

스타일 시스템 (Style System)#

CoreResponsiveGridStyle 필드#

필드타입설명
columns int? Column count at the widest breakpoint override. null defers to [defaultColumns].
cellSpacing double? Inter-cell spacing override applied uniformly between every column and every row (logical px). null defers to [defaultCellSpacing]. N-sibling distribution — xxxSpacing name per CLAUDE.md (the rendered value is fed straight to RenderGrid / CSS gap ).
responsive bool? Whether responsive breakpoints are enabled override. null defers to [defaultResponsive].
breakpoints Map<CoreBreakpoint, int>? Optional explicit breakpoint-to-column mapping override. null defers to the computed default curve (1 col below md , 2 cols below lg , full [columns] at lg and above).

동작 스펙 (Behavior)#

배치 알고리즘#

자식을 순서대로 좌→우, 상→하로 스캔하며 colSpan × rowSpan이 완전히 비어있는 최초의 사각형 영역을 예약합니다 (row-major packing).

렌더링#

  • Flutter: MultiChildRenderObjectWidgetRenderGrid (bit-field 점유 그리드로 span 계산)
  • Web: CSS Grid (display: grid, grid-template-columns: repeat(N, minmax(0, 1fr))) + @media (min-width: ...) 스코프 블록으로 responsive 처리

반응형 breakpoint 기본값#

Breakpoint기본 컬럼 수
xs (< 640px)1
sm (≥ 640px)1
md (≥ 768px)2
lg (≥ 1024px)columns
xl (≥ 1280px)columns
xxl (≥ 1536px)columns

사용 가이드라인 (Usage Guidelines)#

✅ Do#

고정 span 레이아웃이 필요하면 responsive: false로 컬럼 수를 고정

ResponsiveGrid(
  columns: 4,
  responsive: false,   // 4열 고정 — colSpan 이 항상 columns 이하로 유지됨
  children: [
    GridItem(colSpan: 2, child: Card(child: Text('Wide'))),
    Card(child: Text('Cell')),
    Card(child: Text('Cell')),
  ],
)

colSpan/rowSpan을 가진 레이아웃을 breakpoint마다 컬럼 수가 바뀌는 채로 두면 좁은 화면에서 span 값이 실제 컬럼 수를 넘어설 수 있습니다. 레이아웃이 span 관계에 의존한다면 responsive: false로 컬럼 수를 고정하는 편이 안전합니다.


❌ Don't#

responsive: true인 채로 큰 colSpan을 주지 않기

// ❌ 반응형(columns 축소)인데 colSpan이 최대 columns에 가까움
ResponsiveGrid(
  columns: 4,
  responsive: true,
  children: [
    GridItem(colSpan: 4, child: Card(child: Text('Full width'))),
    // ...
  ],
)

Flutter는 colSpan을 현재 컬럼 수로 자동 clamp 하지만, Web은 grid-column: span N을 그대로 inline CSS로 내보내 clamp 하지 않습니다 — 컬럼이 4 → 2 → 1로 줄어드는 좁은 breakpoint에서 두 플랫폼의 렌더 결과가 갈릴 수 있습니다.

접근성 (Accessibility)#

  • 정적 레이아웃 컴포넌트 — 인터랙션 없음
  • 자식 위젯의 접근성은 각자 책임

크로스 플랫폼 차이점 (Platform Differences)#

항목FlutterWeb
클래스명ResponsiveGrid / GridItem동일
렌더링 RenderGrid (custom RenderBox) <div class style="display:grid">
col/row span GridParentData + bit-mask packing CSS grid-column: span N / grid-row: span N
반응형 LayoutBuilder + resolveColumnsForWidth @media (min-width: ...) 스코프 스타일
테마CoreResponsiveGridTheme동일

레거시 vs 통일 비교 (Migration Notes)#

이전 버전의 Web CoUI 를 참조하는 코드에는 이 컴포넌트가 Grid 라는 이름이었을 수 있습니다. Flutter 쪽 이름(ResponsiveGrid)에 맞춰 Web 도 ResponsiveGrid 로 개명되었습니다.

항목레거시 (구 Web Grid)통일 ResponsiveGrid
API동일 named properties동일 named properties
이름만 변경Flutter 와 동일 이름으로 통일, 반응형 성격을 이름에 명시

마이그레이션: Grid(...)ResponsiveGrid(...) — 파라미터는 그대로이므로 클래스명만 바꾸면 됩니다.