사전 적응형 레이아웃
개념

적응형 레이아웃

gabury1고친 사람 github-actions[bot]

적응형 레이아웃은 미리 만든 배치 몇 가지 가운데 앱이 받은 창의 크기에 맞는 하나를 골라 보여 줍니다. 같은 앱이 휴대폰과 태블릿에서 서로 다른 화면 구성을 띄웁니다. 출발점은 창 너비를 몇 개의 구간으로 나눠 두는 일입니다.

쉽고 빠른 이해

무슨 일을 하나 — 앱이 받은 창의 너비가 어느 구간에 드는지 먼저 봅니다. 기기 화면 전체가 아니라 앱이 띄워진 창의 너비입니다. 그다음 그 구간에 맞춰 미리 만든 배치를 꺼내 씁니다. 메일 앱이 휴대폰에서는 목록만 띄우고 태블릿에서는 목록과 본문을 나란히 띄우는 것이 그 예입니다.

왜 이렇게 하나 — 창 너비는 기기마다, 띄우는 방식마다 제각각이라 하나하나 맞출 수 없습니다. 몇 개 구간으로 묶으면 만들 배치가 몇 벌로 줄어듭니다. 좁은 화면용 배치를 넓은 화면에 늘려 놓기만 하면 빈 곳이 커집니다.

어떻게 도나

  1. 창 너비를 좁음·중간·넓음 같은 구간으로 나눠 둡니다
  2. 구간마다 쓸 배치를 따로 만듭니다
  3. 지금 창 너비가 든 구간을 확인해 그 배치를 띄웁니다
  4. 창 크기가 바뀌어 구간을 넘으면 배치를 바꿔 끼웁니다

대가 — 배치를 구간 수만큼 만들고 시험해야 합니다. 같은 기능이 배치마다 따로 들어가서 한쪽만 고치고 다른 쪽을 빠뜨리기 쉽습니다. 이 값을 치를 만한 때는 휴대폰과 태블릿처럼 창 너비 차이가 클 때입니다. 차이가 작으면 크기만 늘리고 줄이는 배치 하나로 충분합니다.

상세

옷 가게는 손님마다 옷을 새로 짓지 않습니다. S·M·L 같은 치수를 몇 개 정해 두고 치수마다 옷을 만들어 둡니다. 손님은 자기 몸이 드는 치수의 옷을 집어 듭니다.

적응형 레이아웃은 창 너비를 이 옷 가게의 치수처럼 다룹니다. 아래에서는 메일 앱 하나로 그 흐름을 따라갑니다.

구간과 브레이크포인트

앱이 받는 창의 너비는 경우마다 다릅니다. 휴대폰만 해도 화면 너비가 조금씩 다른 기종이 수없이 많습니다. 태블릿과 펼친 폴더블, 노트북의 브라우저 창까지 더하면 경우의 수가 끝이 없습니다.

그렇다고 좁은 화면용 배치 하나를 넓은 화면에 늘려 놓기만 하면 빈 곳이 커집니다. 글줄도 한눈에 읽기 힘들 만큼 길어집니다. 넓은 화면에는 넓은 화면에 맞는 배치가 따로 필요합니다.

적응형 레이아웃은 이 너비를 몇 개의 구간으로 묶습니다. 흔히 좁음·중간·넓음 셋이나 그보다 조금 많은 수로 나눕니다. 구간 하나에 배치 하나를 맞추면 만들 배치가 구간 수만큼으로 줄어듭니다.

구간과 구간을 가르는 너비 값이 브레이크포인트입니다. 창 너비가 이 값을 넘는 순간 다른 구간으로 넘어갑니다. 경계 값에 정해진 답은 없습니다. 플랫폼의 디자인 지침이나 만드는 팀이 정합니다.

구간마다 흔히 드는 화면은 아래와 같습니다.

구간 흔히 드는 화면
좁음 세로로 든 휴대폰
중간 세로로 든 태블릿 · 펼친 폴더블
넓음 가로로 든 태블릿 · 노트북과 데스크톱의 브라우저 창

구간은 대개 너비로 나눕니다. 세로가 모자라면 아래로 스크롤하면 됩니다. 가로가 모자라면 요소가 잘리거나 겹쳐서 쓰기 어렵습니다. 그래서 배치를 바꿀지 정할 때 너비를 먼저 봅니다.

구간마다 배치를 고르는 흐름

메일 앱 하나를 예로 듭니다. 앱이 구간을 판정하는 방법과 구간마다 받는 배치를 차례로 봅니다.

앱은 화면을 그리기 전에 지금 창 너비가 어느 구간인지 판정합니다. 판정은 너비를 브레이크포인트와 차례로 견주면 끝납니다. 아래 코드는 경계를 500과 900으로 잡은 판정입니다. 두 값은 설명을 위해 고른 수입니다.

이 수의 단위는 화소 몇 개가 아닙니다. 기기마다 화소가 촘촘한 정도가 달라서 같은 화소 수라도 실제 너비가 다릅니다. 그래서 너비는 이 차이를 덜어낸 논리 단위로 잽니다. 500이면 어느 기기에서나 엇비슷한 실제 너비가 됩니다.

Python
def size_class(width):
    if width < 500:
        return "좁음"
    if width < 900:
        return "중간"
    return "넓음"

size_class(400)   # "좁음"
size_class(700)   # "중간"
size_class(1200)  # "넓음"

판정이 끝나면 그 구간에 맞춘 배치를 꺼냅니다. 메일 앱이라면 세 구간이 아래처럼 갈립니다.

구간 메뉴 목록과 본문
좁음 화면 아래쪽 탭 막대 목록만 띄움. 메일을 누르면 본문 화면으로 넘어감
중간 왼쪽 가장자리의 세로 아이콘 줄 목록만 띄움. 본문은 넘어가서 봄
넓음 왼쪽에 늘 펼쳐 둔 메뉴 왼쪽에 목록, 오른쪽에 본문을 나란히

표를 보면 구간이 바뀔 때 바뀌는 것은 요소의 크기만이 아닙니다. 메뉴의 모양과 위치가 달라집니다. 화면을 몇 칸으로 나누는지도 달라집니다.

넓음 구간처럼 목록과 본문을 한 화면에 함께 띄우는 구성이 목록-상세 레이아웃입니다. 좁은 화면에서는 두 칸이 들어갈 너비가 없어서 한 번에 한 칸만 보여 줍니다.

기기 크기와 창 크기

판정에 기기 화면의 너비가 아니라 창 너비를 쓰는 까닭은 둘이 자주 다르기 때문입니다. 이 절은 둘이 갈리는 경우를 봅니다.

태블릿에서 앱 두 개를 나란히 띄우는 분할 화면이 대표적입니다. 이때 앱이 받는 창은 화면의 절반 정도입니다. 기기가 태블릿이라는 것만 보고 넓은 배치를 띄우면 절반짜리 창에서 요소가 잘립니다.

브라우저도 같습니다. 모니터가 넓어도 사용자는 창을 좁게 줄여 둘 수 있습니다. 그래서 적응형 레이아웃은 기기 이름이 아니라 지금 받은 창의 너비로 구간을 고릅니다.

창 크기가 바뀌는 순간

창 크기는 앱이 떠 있는 동안에도 바뀝니다. 휴대폰을 가로로 돌리면 너비가 늘어납니다. 접혀 있던 폴더블을 펼칠 때도, 분할 화면의 칸 경계를 끌어 옮길 때도 너비가 바뀝니다.

운영체제는 이런 변화를 앱에 알립니다. 화면 크기처럼 앱이 도는 환경이 바뀌는 일을 구성 변경이라고 합니다. 앱은 이 알림을 받을 때마다 구간을 다시 판정합니다.

구간이 그대로면 지금 배치를 유지합니다. 구간이 바뀌었으면 새 구간의 배치로 바꿔 끼웁니다.

바꿔 끼울 때는 화면을 이루는 요소를 새 배치에 맞춰 다시 만듭니다. 예전 요소가 들고 있던 값은 예전 요소와 함께 버려집니다. 보던 메일, 쓰다 만 답장, 내려 둔 스크롤 위치가 그런 값입니다. 이렇게 화면이 들고 있는 값을 상태라고 합니다.

상태를 잃지 않으려면 배치를 바꾸기 전에 상태를 챙겨 두고 바꾼 뒤에 되살려야 합니다. 화면이 바뀌어도 상태를 잃지 않게 지키는 일이 상태 보존입니다.

flowchart TD
    A["창 크기가 바뀜"] --> B["지금 너비로 구간을 다시 판정"]
    B --> C{"구간이 바뀌었나"}
    C -->|아니오| D["지금 배치를 유지"]
    C -->|예| E["보던 메일과 쓰던 답장을 챙겨 둠"]
    E --> F["새 구간의 배치로 바꿔 끼움"]
    F --> G["챙겨 둔 상태를 되살림"]

반응형 레이아웃과의 차이

반응형 레이아웃은 적응형 레이아웃과 자주 함께 불립니다. 둘 다 화면 크기에 맞춰 배치를 바꿉니다. 갈리는 지점은 바뀌는 방식입니다.

반응형 레이아웃은 너비가 조금 바뀔 때마다 요소의 크기와 간격을 조금씩 늘리고 줄입니다. 변화가 끊기지 않고 이어집니다. 적응형 레이아웃은 구간 안에서는 배치를 유지합니다. 경계를 넘는 순간 다른 배치로 건너뜁니다.

반응형 레이아웃 적응형 레이아웃
바뀌는 방식 너비를 따라 이어서 늘고 줄어듦 경계에서 다른 배치로 건너뜀
만드는 배치 늘어나는 배치 하나 구간 수만큼
바뀌는 범위 크기 · 간격 · 한 줄에 놓는 개수 메뉴 모양 · 화면을 나누는 칸 수까지
들어맞는 화면 너비 차이가 크지 않은 화면들 휴대폰과 태블릿처럼 차이가 큰 화면들

둘은 하나를 고르는 관계가 아닙니다. 흔히 구간마다 배치를 먼저 고릅니다. 구간 안에서는 반응형으로 크기를 맞춥니다. 메일 앱의 넓음 구간에서도 창이 더 넓어지면 본문 칸이 함께 넓어집니다.

두 이름의 경계는 쓰는 사람마다 조금씩 다릅니다. 웹에서는 구간마다 규칙을 바꾸는 방식까지 반응형이라 부르는 경우가 많습니다. 이름보다 바뀌는 방식을 보면 둘이 갈립니다. 이어서 변하면 반응형입니다. 경계에서 배치를 갈아 끼우면 적응형입니다.

웹 페이지의 적응형 배치

웹 페이지에서는 브라우저가 창 너비를 보고 배치를 고릅니다. 페이지의 모양은 CSS(Cascading Style Sheets)로 정합니다. CSS 는 색과 크기와 배치를 적는 언어입니다.

CSS 에는 화면 조건에 따라 다른 규칙을 거는 문법이 있습니다. 이 문법이 미디어 쿼리입니다. 「창 너비가 900 이상」 같은 조건을 걸고 그 안에 넓은 화면용 배치를 적습니다.

브라우저는 창 너비를 보고 조건에 맞는 규칙만 씁니다. 사용자가 창을 끌어 줄이면 곧바로 다른 규칙으로 넘어갑니다.

예전 웹에는 서버가 배치를 고르는 방식도 흔했습니다. 브라우저는 요청마다 자기 이름과 운영체제를 적은 값을 실어 보냅니다. 이 값이 사용자 에이전트 문자열입니다. 서버는 이 문자열로 기기가 휴대폰인지 짐작해 휴대폰용 페이지를 따로 돌려줍니다.

이 방식은 기기 종류를 짐작해서 고르므로 앞에서 본 창 크기 문제를 피하지 못합니다. 페이지를 두 벌 유지하는 짐도 서버 쪽에 남습니다. 지금은 브라우저가 창 너비를 보고 고르는 방식이 흔합니다.

모바일 앱의 적응형 배치

모바일 운영체제는 앞의 판정 코드가 하던 일을 대신 해 줍니다. 안드로이드는 창 너비를 Compact · Medium · Expanded 같은 구간으로 나눠 이름을 붙여 두고, 이 묶음을 창 크기 클래스라 부릅니다. 앱은 브레이크포인트를 직접 정하는 대신 이 구간 이름을 받아 배치를 고를 수 있습니다.

앱에서는 떠 있는 동안 구간이 바뀌는 일이 잦습니다. 폴더블을 펼치면 좁음에서 중간으로 넘어가곤 합니다. 분할 화면에 들어가면 넓음에서 중간이나 좁음으로 내려갑니다. 앱은 앞에서 본 흐름대로 구성 변경을 받을 때마다 구간을 다시 판정합니다.

적응형 레이아웃의 대가

먼저 배치를 구간 수만큼 만들어야 합니다. 구간이 셋이면 화면 하나를 세 번 설계하고 세 번 시험합니다.

같은 기능이 배치마다 따로 들어갑니다. 메뉴에 항목 하나를 더하려면 탭 막대와 세로 아이콘 줄과 펼친 메뉴를 모두 고쳐야 합니다. 한쪽만 고치면 구간에 따라 그 기능이 보였다 안 보였다 합니다.

구간 안에서 배치 크기를 고정하면 같은 구간의 양 끝이 다르게 보입니다. 넓은 끝에서는 양옆이 비고 좁은 끝에서는 빠듯합니다. 그래서 구간 안에서는 반응형으로 크기를 맞추는 방식을 함께 씁니다.

창 크기가 바뀔 때마다 배치를 바꿔 끼우는 일에도 값이 듭니다. 상태를 챙겨 두고 되살리는 코드를 빠짐없이 짜야 합니다. 빠뜨리면 기기를 펼치는 순간 쓰던 글이 사라집니다.

관련 항목

적응형 레이아웃과 견주는 배치 방식

반응형 레이아웃 · 유동 레이아웃 · 고정 레이아웃 · 모바일 우선

적응형 레이아웃이 구간을 나누는 기준

브레이크포인트 · 창 크기 클래스 · 크기 클래스 · 뷰포트 · 화면 방향 · 화면비 · 화면 밀도

적응형 레이아웃이 구간마다 바꿔 끼우는 화면 구성

목록-상세 레이아웃 · 하단 내비게이션 · 내비게이션 레일 · 내비게이션 드로어 · 탭 바

적응형 레이아웃을 구현하는 웹 기술

CSS · 미디어 쿼리 · 컨테이너 쿼리 · CSS 그리드 · 플렉스박스 · 사용자 에이전트 · 콘텐츠 협상

적응형 레이아웃이 맞춰야 하는 화면 변화

폴더블 · 분할 화면 · 멀티 윈도 · 태블릿 · 구성 변경 · 상태 보존

적응형 레이아웃이 속하는 상위 분야

레이아웃 · 모바일 개발 · 프론트엔드 · 사용자 인터페이스

다른 이름: adaptive layout · adaptive design · 적응형 디자인 · 어댑티브 레이아웃