antislop-layoutmobile
안티 슬롭: AI 코딩 에이전트를 위한 규칙. 모바일 레이아웃 스킬
안티슬롭 시스템의 일부입니다.
antislop.md(핵심)과 함께 읽으세요. 이 스킬은 반응형 레이아웃 문제를 심층적으로 다룹니다: 레이아웃이 화면 크기(휴대폰부터 데스크톱까지)에 따라 어떻게 재구성되어야 하는지에 대한 것입니다. 중단점, 스케일, 그리드, 오버플로우, 터치 대상, 내비게이션을 다룹니다. 핵심 규칙을 번호로 참조하며, 중복하거나 번호를 다시 매기지 않습니다. 레이아웃을 구축하거나 편집하는 작업으로, 어떤 화면 너비에서도 잘 작동해야 할 때 이 스킬을 로드하세요.
이 스킬 사용 방법
- 작업이 모바일 또는 반응형 레이아웃 작업일 때마다
antislop.md와 함께 로드하세요. 핵심 스킬은 메커니즘(목적 테스트, 세 가지 계층, 전달 게이트)을 담고 있습니다. 이 스킬은 모바일 레이아웃의 깊이를 담고 있습니다. - 모든 항목은 동일한 형식을 따릅니다: Tell (패턴), Why (슬롭으로 읽히는 이유), Fix (대신 할 일), 그리고 해당 핵심 규칙이 R-XX로 인용됩니다.
- 이 스킬의 기본 원칙: 모바일 레이아웃은 데스크톱 레이아웃을 작게 만든 것이 아니라, 완전히 다른 레이아웃입니다. 의도적으로 재배열되어야 합니다: 다시 쌓고, 크기를 조정하고, 순서를 변경해야 합니다. 아래의 각 패턴은 레이아웃이 재배열에 실패하는 방식입니다.
- 핵심 스킬의 전달 게이트는 여전히 게이트 역할을 합니다. 이 파일 끝에 있는 "레이아웃모바일 스킬 체크리스트"는 함께 실행할 모바일 전용 보충 자료입니다.
중단점
데스크톱 전용 레이아웃
- Tell: 모든 화면에 대해 하나의 레이아웃 상태만 있으며, 모바일 보기는 데스크톱 레이아웃을 휴대폰에 쥐어짜 넣은 것입니다.
- Why: R-03은 완벽한 모바일 레이아웃을 요구하며, 이는 부차적인 고려사항이 아닙니다. 단지 축소만 하는 페이지에는 모바일 디자인이 전혀 없는 것입니다: 나란히 있던 카드가 겹치고, 넓은 캔버스를 위해 만들어진 텍스트가 좁은 공간에 밀집됩니다.
- Fix: 콘텐츠가 더 이상 작동하지 않는 중단점에서 실제 모바일 상태를 정의하세요. 모바일 레이아웃은 재배열됩니다: 열이 쌓이고, 크기가 줄어들며, 콘텐츠가 필요로 하는 곳에서 순서가 변경됩니다. 모바일 보기가 단지 더 작은 너비의 데스크톱 보기라면 레이아웃이 완료된 것이 아닙니다.
기기 목록에 의해 결정된 중단점
- Tell: 중단점이 "그게 아이폰 크기라서" 선택된 휴대폰 너비(375px, 414px, 768px)의 이름을 따서 지어졌으며, 콘텐츠가 거기서 깨지기 때문이 아닙니다.
- Why: 기기 너비는 매년, 모델마다 바뀝니다. 중단점은 레이아웃이 더 이상 유지되지 않는 지점입니다. 강제로 기기 목록에 맞추면 레이아웃이 콘텐츠 대신 사양서를 따르게 됩니다 (R-03).
- Fix: 콘텐츠가 실제로 깨지는 지점에 중단점을 배치하세요: 열이 더 이상 읽기 어려워질 때, 카드 행이 너무 좁아질 때. 뷰포트를 좁혀서 어디에서 스냅되는지 관찰한 후, 그곳에 중단점을 설정하세요.
모바일이 마지막에 스타일링됨
- Tell: 모바일 규칙이 후행 재정의로 덧붙여진 경우: 긴 데스크톱 스타일시트 끝에 작은 미디어 쿼리 하나가 한두 가지를 수정합니다.
- Why: 재정의 패치는 모바일 디자인이 아닙니다. 보고된 증상을 수정하고 다음 증상은 남겨둡니다. 기본 스타일은 여전히 넓은 화면에 맞춰져 있습니다 (R-03).
- Fix: 모바일을 재정의가 아닌 설계된 상태로 취급하세요. 좁은 뷰포트에 의도적인 크기와 스태킹을 부여하고, 패치된 부분뿐만 아니라 전체 레이아웃을 확인하세요 (R-35).
두 가지 상태 레이아웃
- Tell: 정확히 두 가지 상태만 있는 레이아웃: 하나의 중단점 아래에서는 단일 스태킹 열, 그 위에서는 넓은 다중 열 그리드이며, 그 사이에는 정의된 것이 없습니다. 그러면 태블릿이나 작은 노트북 너비는 가장 가까운 상태를 상속받습니다: 휴대폰 스택이 터무니없이 넓게 늘어나거나, 데스크톱 그리드가 의도된 캔버스의 일부로 쪼그라듭니다.
- Why: 페이지는 연속적인 너비 범위이며, R-03은 선택된 두 중단점뿐만 아니라 모든 너비에서 페이지가 유지되도록 요구합니다. 두 가지 상태는 범위의 중간 대역(대략 600~1024px, 태블릿과 작은 노트북이 있는 영역)을 사고로 남겨둡니다: 의도적으로 쌓이지도 않고, 맞는 그리드에 있지도 않은 콘텐츠. 레이아웃은 두 개의 샘플 지점에서만 설계된 것으로 읽히고 그 사이에서는 모두 깨진 것으로 읽힙니다.
- Fix: 콘텐츠가 더 이상 작동하지 않는 너비에서 실제 상태를 정의하고, 콘텐츠가 필요로 하는 만큼 많은 상태를 허용하세요. 일반적인 재배열은 세 가지 상태입니다: 단일 열, 그런 다음 카드가 단일 스택으로 너무 넓어질 때 두 열 그리드, 마지막으로 실제로 들어맞을 때만 전체 다중 열 그리드. 두 너비를 확인하고 완료했다고 말하는 대신 뷰포트를 전체 범위로 드래그하여 확인하세요 (R-35).
스케일 및 크기 조정
데스크톱 크기의 모든 것
- Tell: 패딩, 간격, 히어로 높이, 카드 크기가 데스크톱에서 모바일로 변경되지 않고 그대로 유지되어, 휴대폰에서 모든 섹션이 확대되어 보입니다.
- Why: 1440px 캔버스에 맞춰진 요소는 375px 캔버스를 지배합니다. 데스크톱에서 자신감 있게 보이는 것이 모바일에서는 지나치게 커집니다: 아무것도 맞지 않고, 숨 쉴 공간이 없으며, 페이지가 손에 든 화면이 아닌 다른 화면을 위해 설계된 것처럼 느껴집니다 (R-03). 간격과 타이포그래피는 디자인 리듬을 따라야 하며 (R-05), 그 리듬은 모바일에서 더 작은 레지스터를 가집니다.
- Fix: 모바일에 자체 크기 단계를 부여하세요: 더 작은 타이포그래피 스케일, 더 좁은 섹션 패딩, 더 작은 간격. 터치 대상은 최소 크기로 유지하고 (터치 대상 참조), 다른 모든 것은 중단점에서 의도적으로 줄이세요.
고정 픽셀 타이포그래피
- Tell: 데스크톱과 모바일 사이에 절대 변경되지 않는 고정 px 글꼴 크기로, 휴대폰에서 제목과 본문 텍스트가 지나치게 커집니다.
- Why: 뷰포트에 반응하지 않는 타이포그래피는 하나의 화면에 맞춰진 타이포그래피입니다. R-03은 모바일 레이아웃이 유지되도록 요구하고, R-06은 가독성을 향상시키는 타이포그래피를 요구합니다. 휴대폰 너비 전체를 차지하는 제목이나 넓은 줄에 맞춰진 본문 크기는 둘 다 위반합니다.
- Fix: 유동적 타이포그래피(
clamp())를 사용하여 크기가 뷰포트에 따라 조정되도록 하거나, 중단점에서 더 작은 타이포그래피 단계를 설정하세요. 데스크톱 미리보기뿐만 아니라 좁은 너비에서 결과를 확인하세요 (R-35).
100vh 섹션
- Tell: 히어로 및 섹션 높이가
100vh로 설정되어, 섹션이 전체 휴대폰 화면을 채우고 다른 모든 것을 접힌 부분 아래로 밀어냅니다. - Why: 데스크톱 모니터를 위해 설계된 전체 뷰포트 섹션은 휴대폰에서 거대한 판이 되고,
100vh는 브라우저 크롬을 포함하므로 모바일 브라우저에서 보이는 영역을 넘쳐흐릅니다. 레이아웃을 소개하는 대신 지배합니다 (R-03). - Fix: 섹션이 콘텐츠에 맞게 크기를 조정하도록(
auto) 하거나, 실제 전체 높이 섹션이 의도된 경우 동적 뷰포트 단위(dvh)를 사용하세요. 접힌 부분 아래에는 뷰포트 단위의 사고가 없어야 합니다.
거대한 빈 패딩
- Tell: 데스크톱 스케일의 섹션 패딩(96px, 128px)이 모바일에서 유지되어, 휴대폰에서 섹션 사이에 크고 빈 간격이 생깁니다.
- Why: 큰 캔버스에 맞춰진 패딩은 작은 캔버스에서 낭비되는 수직 공간으로 변합니다. 페이지는 공허함을 스크롤하고, R-05가 요구하는 리듬은 모든 섹션 사이의 공백이 됩니다.
- Fix: 중단점에서 섹션 패딩을 모바일 레지스터(대략 절반 이하)로 줄이고, 페이지가 공백의 사막을 통과하는 대신 자연스러운 밀도로 스크롤되는지 확인하세요.
그리드 및 스태킹
축소되지 않는 열
- Tell: 다중 열 그리드가 모바일에서도 나란히 열을 유지하여, 열이 줄어들고, 텍스트가 어색하게 줄바꿈되며, 요소가 충돌합니다.
- Why: 그리드는 사용 가능한 너비에 대한 약속입니다. 뷰포트가 좁아지고 그리드가 다시 쌓이지 않으면 모든 열이 얇은 조각을 얻고, 텍스트를 읽을 수 없게 되며, 카드가 겹칩니다 (R-03). 이것이 충돌 실패입니다: 데스크톱의 나란히가 모바일의 쌓임이 됩니다.
- Fix: 중단점에서 그리드를 단일 재배열 열로 축소하세요. 나란히가 쌓임이 되고, 각 항목은 다시 전체 너비를 얻습니다. 좁은 너비에서 다시 확인하세요 (R-35).
고정 너비 그리드
- Tell:
grid-template-columns가 고정 px로 설정되거나 재배열할 수 없는 그리드 영역이 있어, 뷰포트가 줄어들 때 그리드가 고정됩니다. - Why: 고정 px 트랙은 뷰포트를 신경 쓰지 않습니다. 너비를 유지하고 오버플로우나 충돌을 강제합니다. 레이아웃은 하나의 캔버스를 위해 만들어졌으며 모양을 변경할 수 없습니다 (R-03).
- Fix:
minmax()또는auto-fit및auto-fill로 트랙의 크기를 조정하여 열이 콘텐츠와 함께 줄어들고 줄바꿈되도록 하고, 중단점에서 축소되는 그리드 영역을 정의하세요. 그리드는 기본적으로 유동적이어야 하며, 고정 크기는 의도적인 경우에만 사용하세요.
강제 12열
- Tell: 하나 또는 두 개의 열이 필요한 모바일 콘텐츠에 12열 그리드가 강제되어, 스팬이 임의적으로 보이고 계산이 레이아웃과 싸웁니다.
- Why: 12열 시스템은 많은 콘텐츠 열을 가진 넓은 캔버스를 위한 것입니다. 휴대폰에 강제하면 모든 요소가 사용자가 보지 못하는 보이지 않는 그리드의 일부가 되고, 콘텐츠가 그리드에 맞춰지고 그리드가 콘텐츠에 맞춰지지 않습니다 (R-03).
- Fix: 열이 콘텐츠를 따르도록 하세요. 모바일에서 콘텐츠는 일반적으로 하나의 열을 원하거나 많아야 두 개의 열을 원합니다. 12열 스팬은 레이아웃에 실제로 그 많은 것들이 나란히 있을 때만 의미가 있습니다.
오버플로우
가로 스크롤 누출
- Tell: 일부 요소가 뷰포트보다 넓기 때문에 페이지가 옆으로 스크롤됩니다: 테이블, 코드 블록, 이미지, 긴 끊김 없는 문자열.
- Why: 가로 스크롤은 모바일에서 깨진 약속입니다. 사용자는 페이지가 끝나는 지점을 볼 수 없고, 레이아웃이 화면 밖으로 명백하게 흘러넘칩니다 (R-03). 데스크톱 미리보기에서 범인이 화면 밖에 있어 눈치채지 못하고 휴대폰이 열릴 때까지 발견되지 않기 때문에 가장 흔한 오버플로우 슬롭입니다.
- Fix: 뷰포트보다 넓은 요소(재배열 레이아웃 또는 스크롤 컨테이너가 필요한 테이블, 줄바꿈되는 코드 블록,
max-width: 100%인 이미지)를 찾은 다음, 포함하거나 재배열하세요. 가장 좁은 목표 너비에서 전체 페이지에 가로 스크롤이 없는지 확인하세요 (R-35).
오버플로우 히든 클리핑
- Tell: 컨테이너에
overflow: hidden이 있어 좁은 너비에서 콘텐츠를 잘라내어, 맞추는 대신 텍스트나 컨트롤을 숨깁니다. - Why: 클리핑은 실패를 숨기는 것입니다. 컨테이너가 레이아웃을 맞출 수 없어 콘텐츠를 잘라낼 때, 사용자는 정보와 상호 작용을 잃습니다 (R-03). 이에 대한 확대 및 텍스트 크기 조정 측면은
antislop-human에서 다룹니다. - Fix: 클리핑 대신 콘텐츠가 재배열되도록 하세요: 컨테이너가 커지도록 허용하고, 콘텐츠를 줄바꿈하거나 중단점에서 축소하세요. 디자인 의도가 자르기인 경우(예: 썸네일)에만 클리핑하고, 콘텐츠를 숨기는 데 절대 사용하지 마세요.
고정 너비 자식 요소
- Tell: flex 또는 grid 자식 요소에 고정 px 너비 또는
min-width가 있어 좁은 화면에서 부모를 벗어납니다. - Why: 절대 px로 크기가 조정된 자식 요소는 부모가 얼마나 많은 공간을 가지고 있는지 신경 쓰지 않습니다. 모바일에서 부모는 줄어들고 자식은 넓게 유지되므로, 컨테이너와 페이지를 넘쳐흐릅니다 (R-03).
- Fix: 자식 요소의 크기를 상대 단위로 조정하고 줄바꿈을 허용하세요(
flex-wrap, 유동적 너비, 그리드 자식에min-width: 0). 자식 요소는 컨테이너와 함께 줄어들 수 있어야 하며, 데스크톱 크기를 고수하지 않아야 합니다.
터치 대상
너무 작은 대상
- Tell: 약 44 x 44 px보다 작은 버튼, 링크 및 컨트롤로, 데스크톱에서 커서로 클릭하기는 쉽지만 엄지로 터치하기는 어렵습니다.
- Why: 데스크톱 커서는 픽셀 정확도를 가지지만, 엄지는 그렇지 않습니다. 16px에서 괜찮은 대상은 휴대폰에서 좌절감을 주는 연습이 되며, UI가 모바일에서 사용 가능하다는 약속을 위반합니다 (R-03).
- Fix: 대화형 대상에 최소 터치 영역 44 x 44 px을 부여하고, 시각적 요소가 더 작더라도 패딩 또는 더 큰 히트 박스를 사용하세요. 휴대폰 너비에서 모든 컨트롤 세트를 확인하세요 (R-35).
너무 가까운 대상
- Tell: 44px 대상이 간격 없이 함께 밀집되어 있어, 엄지 터치가 잘못된 것을 누릅니다.
- Why: 대상 크기는 대상 간격과 함께 중요합니다. 서로 닿아 있는 두 개의 큰 컨트롤은 하나의 큰 컨트롤처럼 동작합니다: 사용자는 어느 쪽도 안정적으로 선택할 수 없습니다 (R-03).
- Fix: 인접한 대화형 대상 사이에 명확한 간격을 두고, 최소 몇 px, 이상적으로는 손가락 누름 영역이 겹치지 않을 만큼 충분히 두세요. 간격은 탭 가능성의 나머지 절반입니다.
호버 전용 상호 작용
- Tell: 호버에만 존재하는 메뉴, 공개(reveal) 및 툴팁으로, 터치 사용자는 절대 열 수 없습니다.
- Why: 터치스크린에는 호버가 없습니다. 호버에만 반응하는 상호 작용은 모바일 사용자에게 단순히 존재하지 않으며, 이에 의존하는 모든 컨트롤은 막다른 길입니다 (R-03).
- Fix: 모든 호버 전용 상호 작용에 탭 등가물을 부여하세요: 호버 시 열리는 메뉴는 탭 시에도 열리고, 공개는 클릭 시에도 보여야 하며, 대화형 요소는 탭이 등록되도록 보이는
:active피드백을 표시해야 합니다. 터치만으로 UI를 테스트하여 확인하세요 (R-35).
모바일 내비게이션
데스크톱 상태를 유지하는 내비게이션
- Tell: 데스크톱 상단 막대가 링크 행을 모바일에서도 나란히 유지하여, 링크가 좁아지고, 두 줄로 줄바꿈되거나, 뷰포
[truncated for translation]