모바일 반응형 전면 대응
데스크톱 전용으로 뷰포트를 차단하던 서비스를 모바일에 열면서, '어느 경로를 열 것인가'라는 정책부터 다시 세운 8개 PR 규모의 작업.
주요 기여
데스크톱 전용이던 서비스를 모바일에 열었습니다. 어느 경로를 열고 어느 경로를 막을지부터 정해야 해서 CSS보다 정책 결정이 더 많은 작업이었고, 8열짜리 표는 억지로 줄이는 대신 같은 값끼리 묶어 4개 블록으로 다시 짰습니다.
App.tsx에서 window.innerWidth < 1024면 경로와 무관하게 'PC 환경에서 접속해 주세요'만 렌더하고 있었습니다. 구글 모바일 우선 색인 기준으로는 크롤러가 모든 페이지에서 안내 문구만 봤을 가능성이 컸고, 차단을 걷어내자 막아야 할 /apply가 깨진 채 열리고 로그인·로그아웃 진입점은 통째로 사라지는 등 정책이 비어 있는 문제가 드러났습니다.
뷰포트 차단을 제거하고, 모바일에 열 경로와 데스크톱 전용 경로를 코드로 명시한 뒤, 열리는 화면은 좁은 폭에서도 읽히게 만드는 것.
브레이크포인트를 2단으로 분리했습니다. 흔한 1024px 대신 실제 레이아웃 폭 기준 belowDesktop(≤1039.98px)을 신설해 1025~1039px 구간의 가로 스크롤을 없앴고, 모바일 레이아웃 전환은 md(≤768px)로 두었습니다. features/viewport에 desktopOnlyPaths와 DesktopOnlyRoute를 만들어 데스크톱 전용 경로 정책을 코드로 세우고, useMediaQuery(useSyncExternalStore)로 리사이즈·회전 시 즉시 판정이 바뀌게 했습니다. 이 가드는 ProtectedRoute 바깥에 두어 어차피 막힐 경로에 로그인부터 시키지 않게 했습니다. 로그인 상태 메뉴 3개가 320px에서 98px 넘치는 것을 실측해 md 이하에서만 햄버거 메뉴로 대체했고(백드롭·ESC 닫기, 44px 터치 영역, aria-expanded, prefers-reduced-motion), 8열 장학금 비교표는 같은 값끼리 묶어 4블록으로 재구성하되 데스크톱 표의 병합 셀 정의를 그대로 슬라이스해 두 화면의 값이 어긋날 수 없게 했습니다.
헤더 메뉴를 숨기는 것만으로는 마이페이지 → /apply/:id 동선과 URL 직접 입력이 남고, 반대로 일괄 숨김은 로그아웃 수단까지 없애 막다른 길을 만들었습니다. PDF 뷰어 툴바는 버튼을 키우면 자식 svg와 ScrollContainer padding이 함께 틀어지는 구조였습니다.
라우트 진입 시점 판정으로 두 동선을 모두 차단하고, 헤더는 일괄 숨김에서 항목별 정책으로 전환해 '진입점이 없으면 사용자에게는 기능이 없는 것과 같다'는 기준으로 로그아웃과 아직 반응형 전인 페이지의 진입점도 열어뒀습니다. 툴바 버튼은 요소를 키우지 않고 오버레이로 탭 영역만 44px로 넓혔습니다. PR은 화면 단위로 쪼개고 열린 PR 4건과 겹치는 파일이 0개임을 본문에 명시했습니다.
1024px은 흔한 값이지만 우리 레이아웃 폭은 1040px이라 그 사이 15px 구간이 깨졌습니다. 값을 빌려오지 말고 실제 레이아웃에서 유도해야 한다는 것, 그리고 좁은 화면에서 안 되는 건 표가 아니라 '훑어보기'라는 걸 배웠습니다.