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 테이블은 데이터를 비교하기에는 좋지만, 모바일에선 다른 접근이 필요하다.
빠른 점검 순서
- 모바일 DevTools에서 실제 너비 확인
- 수평 스크롤이 필수인가, 아니면 다른 레이아웃으로 가능한가 판단
- 중요한 열만 남기기
- 카드 레이아웃으로 변경 (@media)
- 폰트와 패딩 최적화
- 터치 친화적 높이 (최소 44px)
- 실제 모바일 기기에서 테스트
HTML 테이블을 억지로 모바일에 맞출 필요는 없다. 구조부터 다시 생각하면 더 좋은 UX를 만들 수 있다.