← 전체 글로 돌아가기

Flutter

테이블 모바일에서 레이아웃이 깨질 때 대응하는 방법

반응형 테이블이 모바일에서 깨져 보일 때, 구조부터 CSS까지 확인하고 고치는 순서.

웹앱에서 테이블을 보여주는데, 모바일에서 열이 잘려나간다. 스크롤을 아무리 해도 정보를 다 볼 수 없다. 사용자는 혼란스러워한다.

테이블은 본질적으로 모바일에 적합하지 않다. 열이 많으면, 화면이 좁은 모바일에서는 정보를 표현할 수 없다. 그래서 구조부터 다시 생각해야 한다.

1단계: 모바일에서 실제로 보는 모습 확인

# DevTools에서 모바일 기기 시뮬레이션
# F12 → DevTools → Ctrl+Shift+M (또는 Toggle Device Toolbar)

# 또는 실제 모바일 기기에서 확인

어느 열이 잘려나가는가? 전체 너비가 화면보다 큰가?

개발자 도구의 Element Inspector로 테이블 너비를 본다:

document.querySelector('table').offsetWidth
// 예: 1200px

window.innerWidth
// 모바일: 375px

테이블이 375px 화면에 1200px를 강제로 넣으려고 하니 당연히 깨진다.

2단계: 첫 번째 해결책: 수평 스크롤

.table-container {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;  /* 모바일 smooth scroll */
}

table {
  min-width: 100%;
  white-space: nowrap;  /* 셀 내용 줄바꿈 방지 */
}

가장 간단하지만, 사용자 경험은 떨어진다. 모바일에서 테이블을 옆으로 스크롤하기는 번거롭다.

3단계: 더 나은 해결책: 카드 레이아웃으로 변경

// 테이블
<table>
  <thead>
    <tr><th>Name</th><th>Age</th><th>City</th></tr>
  </thead>
  <tbody>
    <tr><td>John</td><td>25</td><td>NYC</td></tr>
  </tbody>
</table>

// 모바일에서는 카드로
@media (max-width: 768px) {
  table, thead, tbody, th, td, tr {
    display: block;
  }

  thead tr {
    display: none;  /* 헤더 숨김 */
  }

  tr {
    margin-bottom: 1rem;
    border: 1px solid #ddd;
  }

  td {
    padding: 0.5rem 1rem;
    border-bottom: 1px solid #eee;
  }

  /* data-* 속성을 이용해 레이블 표시 */
  td:before {
    content: attr(data-label);
    font-weight: bold;
    float: left;
    width: 50%;
  }

  td {
    text-align: right;
  }
}

HTML:

<table>
  <tbody>
    <tr>
      <td data-label="Name">John</td>
      <td data-label="Age">25</td>
      <td data-label="City">NYC</td>
    </tr>
  </tbody>
</table>

모바일에서 각 행이 카드처럼 보인다.

4단계: 중요한 열만 보여주기

/* 모바일에서는 특정 열만 표시 */
@media (max-width: 768px) {
  .col-secondary {
    display: none;
  }
}

HTML:

<table>
  <tr>
    <th>Name</th>
    <th class="col-secondary">Email</th>
    <th>City</th>
  </tr>
</table>

모바일에서 꼭 필요한 정보만 보여준다.

5단계: 폰트 크기 조정

@media (max-width: 768px) {
  table {
    font-size: 14px;  /* 기본값 16px보다 작음 */
  }

  td, th {
    padding: 0.25rem 0.5rem;  /* 패딩 줄임 */
  }
}

모바일에서 더 작은 폰트와 패딩으로 공간을 절약한다. 하지만 너무 작으면 읽기 어려우므로 14px 이상이어야 한다.

6단계: 테이블의 정렬과 텍스트 길이

td {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100px;  /* 모바일에 맞게 조정 */
}

/* 숫자는 오른쪽 정렬 */
.number {
  text-align: right;
}

긴 텍스트는 잘라내고 (ellipsis), 숫자는 오른쪽 정렬해서 비교하기 쉽게 한다.

7단계: 터치 친화적으로 만들기

/* 모바일에서 터치하기 좋게 높이 늘림 */
@media (max-width: 768px) {
  td, th {
    min-height: 44px;  /* Apple의 권장값 */
    display: flex;
    align-items: center;
  }
}

손가락으로 터치하기 편하게 셀의 높이를 최소 44px 이상으로 한다.

8단계: 실제 테스트

# 다양한 화면 크기에서 테스트
# DevTools: iPhone 12 (390px)
# DevTools: iPhone SE (375px)
# DevTools: iPad (768px)
# DevTools: Galaxy S20 (360px)

MediaQuery 적용 여부, 텍스트 읽기 쉬운지, 터치하기 편한지 확인한다.

9단계: 프레임워크 컴포넌트 사용

// Material-UI, shadcn/ui 같은 라이브러리는
// 반응형 테이블을 지원한다

import { DataTable } from '@/components/ui/data-table'

<DataTable
  columns={columns}
  data={data}
  // 모바일에서 자동으로 카드 레이아웃
/>

처음부터 만들기보다는, 이미 모바일 지원하는 컴포넌트를 쓰는 게 낫다.

최종 결정: 테이블이 필요한가?

모바일 사용자가 대부분이라면, 처음부터 다른 구조를 생각하자:

  • 리스트 뷰: 각 항목을 카드나 행으로 표시
  • : 카테고리별로 정보를 분리
  • 모달: 항목을 클릭하면 상세 정보를 모달로

HTML 테이블은 데이터를 비교하기에는 좋지만, 모바일에선 다른 접근이 필요하다.

빠른 점검 순서

  1. 모바일 DevTools에서 실제 너비 확인
  2. 수평 스크롤이 필수인가, 아니면 다른 레이아웃으로 가능한가 판단
  3. 중요한 열만 남기기
  4. 카드 레이아웃으로 변경 (@media)
  5. 폰트와 패딩 최적화
  6. 터치 친화적 높이 (최소 44px)
  7. 실제 모바일 기기에서 테스트

HTML 테이블을 억지로 모바일에 맞출 필요는 없다. 구조부터 다시 생각하면 더 좋은 UX를 만들 수 있다.