
『Under the Hood UI Design』를 읽고 404 페이지와 마주한 이야기
요약
『Under the Hood UI Design』을 읽고 얻은 깨달음을 바탕으로, 서비스의 정체성을 반영한 404 페이지를 설계하는 과정을 다룹니다. 단순한 에러 페이지를 넘어 사용자의 경험을 설계하는 관점과 Claude Code를 활용한 의사결정 과정을 기술합니다.
핵심 포인트
- 404 페이지는 '막다른 길에 도착한 순간에 무엇을 보여줄 것인가'에 대한 설계다.
- 에러 페이지를 사이트의 일부로 취급할 때 서비스의 완성도와 촉감이 결정된다.
- Claude Code를 활용해 시각적 구현 전 컨셉과 언어적 정의를 먼저 확립했다.
- 사용자를 '길을 잃은 사람'이 아닌 '정비 구역에 온 사람'으로 정의하여 경험을 설계했다.

『Under the Hood UI Design (縁の下のUIデザイン)』라는 책을 읽었다. UI의 세부 사항만을 모은 실전 TIPS 모음집인데, 그중에는 「대기 시간의 디자인」을 다룬 장이 있다. 종료 시간을 표시할지 말지, 표시하지 않는다면 스켈레톤 스크린 (Skeleton Screen)이나 팁 (tips) 연출로 「기다리는 동안 무엇을 보여줄 것인가」를 설계한다는 내용이다.
읽으면서 이것이 내가 만든 AWS 학습 사이트의 다른 문제와 같은 구조라는 것을 깨달았다. 사이트 내에는 아직 준비되지 않은 페이지로 연결되는 링크가 몇 개 남아 있는데, 이를 클릭하면 나오는 것은 Next.js의 순정 404 페이지, 즉 새하얀 화면에 "404"라고만 적혀 있는 그 차가운 화면이었다. 대기 시간이 「기다리는 동안 무엇을 보여줄 것인가」의 설계라면, 404 페이지는 「막다른 길에 도착한 순간에 무엇을 보여줄 것인가」의 설계다. 시간축을 「기다림」에서 「막힘」으로 바꾸었을 뿐, 같은 문제였다.
책에 대한 감상은 따로 작성했다 (끝에 링크를 남겨두었다). 이 기사에서는 그 깨달음을 바탕으로 실제로 404 페이지를 다시 만든 과정을 기술한다. 구현 방법(How-to)이 아니라, Claude Code와 함께 한 장의 empty state를 어떻게 완성했는가에 대한 의사결정의 기록이다.
결론부터 말하자면, 404 페이지를 「사이트의 일부」로 취급할지 여부에 따라 그 사이트의 촉감이 달라진다고 생각했기 때문이다.
개편 전의 404 페이지는 이런 화면이었다.
![[before-404.png]]
Next.js가 표준으로 제공하는 틀에 링크 카드만 직접 추가한 상태. 정보로서는 충분하지만, 사이트의 일부라기보다는 「에러가 발생했으므로 기계적으로 출력했습니다」라는 표정을 짓고 있다.
책에서 읽은 「대기 시간」 장은 기다리게 하고 있다는 사실을 숨기는 것이 아니라, 기다리는 동안 무엇을 보여줄지를 설계한다는 발상이었다. 같은 말을 404 페이지에도 적용할 수 있다. 학습 사이트의 정체성은 「학습 경로를 안내하는 것」에 있다. 그렇다면 존재하지 않는 페이지에 길을 잃은 사람에게도 그럴듯한 경험을 돌려주어야 한다고 생각했다. 순정 404 페이지 그대로라면 그 부분만 사이트 외부로 던져진 듯한 단절이 생긴다.
Next.js의 기본 not-found.tsx를 직접 수정하면 끝날 문제이기도 하지만, 「무엇을 수정할 것인가」를 결정하기 전에 먼저 「이 페이지에 온 사람에게 어떤 느낌을 주고 싶은가」를 언어화할 필요가 있었다. 여기서부터 Claude Code와의 상호작용이 시작된다.
Tailwind 클래스명을 나열하기 전에 결정한 것은 컨셉을 담은 한 문장이었다. 「404의 차가움」을 「로드맵 위의 작은 휴식」으로 바꾸는 재정의다.
존재하지 않는 페이지에 온 사용자를 「길을 잃은 사람」으로 취급하는 것이 아니라, 「아직 정비되지 않은 구역에 온 것뿐」이라고 느끼게 하고 싶었다. 이 차이는 작아 보이지만 후속되는 모든 판단에 영향을 미친다. 마스코트가 「죄송합니다, 길을 잃게 해드렸습니다」라고 사과하는 역할인지, 「이쪽은 아직 공사 중이에요, 이쪽에서 배울 수 있어요」라고 안내하는 역할인지에 따라 표정, 대사, 배색의 온도까지 달라지기 때문이다.
Claude Code에 던진 첫 번째 지시는 이 한 문장의 재정의를 축으로 한 컨셉 정의였다. 색상이나 레이아웃 이야기는 그 이후에야 겨우 나왔다.
결론적으로, 기존 UI에서 빌려온 것은 시각적인 세부 사항이 아니라 요소들 사이의 「관계성」이었다.
참고한 패턴은 두 가지다. 하나는 Notion이나 Linear에서 볼 수 있는, 정사각형과 여백을 주인공으로 한 깔끔한 empty state다. 일러스트, 헤드라인, CTA가 위에서부터 순서대로 나열되는 3존(3-zone) 구성으로, 카드 내부에서 완결되어 외부로 벗어나지 않는다. 다른 하나는 Duolingo형의 「마스코트가 상태를 설명하는」 패턴이다. 마스코트는 단순한 장식이 아니라, 45도 각도로 손을 들어 「이쪽이야」라고 포즈를 취하며, 그 자세 자체가 「지금 어떤 상태인가」를 말해주는 역할을 한다.
여기서 중요했던 것은 이 두 가지 패턴에서 스크린샷이나 배색 자체를 복사하는 것이 아니라, 「마스코트는 장식이 아닌 상태 설명역으로서 기능하게 한다」는 관계성의 설계만을 추출해낸 것이다. 컬러 토큰(Color token)은 기존 사이트의 slate / sky 계열을 그대로 계승하여 신규 정의를 제로(0)로 만들었다. 프로덕트 내의 기존 화면으로서 자연스럽게 어우러지게 하기 위한 판단이었다.
한 일보다 하지 않은 일이 지금도 기억에 남는다.
우선 채택하지 않은 것이 「길을 잃은 인물 일러스트 + 돋보기」라는 404 페이지의 전형적인 템플릿이다. 검색하면 나오는 대부분의 404 디자인 기사가 이 구도를 사용하고 있다. 학습 사이트의 컨셉과는 맞지 않기에, 초기 아이디어 도출 단계에서 제외했다.
다시 되돌아보면, 정말 이 구도뿐이었다는 생각이 든다. 다만, 이번에 채택한 로드맵(Roadmap)과 마스코트의 조합이 처음부터 학습 사이트의 컨셉에 딱 들어맞았기에, 다른 불채택 후보들을 이것저것 비교할 필요조차 없었다. 하나의 안이 돌출되어 있으면 소거법으로 나머지를 검토하는 수고 자체를 덜 수 있다는 것도 이번에 배운 점이다.
다음으로 불채택한 것이 '에러 코드를 화면 가득한 거대한 숫자로 표시하는' 구성이다. 이것도 404 페이지의 정석이지만, "404"를 주인공으로 만들면 '고장 난 느낌'이 강조되어 버린다. 이번에는 컨셉을 '잠시 쉬어가는 시간'에 두었기에, 404 표시는 eyebrow(작은 부제)로서 아주 작게 곁들이는 정도에 그쳤다.
또 하나, 눈에 띄지는 않지만 효과적이었던 것은 '로드맵을 막대그래프나 계층 트리로 표현하는' 안을 불채택한 것이다. 학습 경로라는 추상적인 개념을 시각화하려고 하다 보면, 자칫 업무용 대시보드의 도표처럼 만들기 쉽다. 하지만 이번에 원했던 것은 '걸어가는 길'이라는 체감이었고, 그것은 수치화하는 막대그래프와는 상성이 좋지 않다. 결국, 길은 가로로 흐르는 곡선으로 그리기로 했다.
이러한 '빼기' 작업은 사실 Claude Code가 처음에 내놓은 안에도 일부 포함되어 있었다. 템플릿적인 발상은 AI가 먼저 손을 대기 쉽다. 그것을 하나씩 "이것은 아니다"라고 말하며 깎아 나가는 작업이, 컨셉을 날카롭게 다듬는 과정 그 자체였다고 생각한다.
외형이 결정된 후의 뒷순위 작업이 아니라, 색상을 결정하는 단계부터 접근성(Accessibility) 기준을 포함했다.
WCAG는 'Web Content Accessibility Guidelines'의 약자로, 색약이 있는 사람이나 시력이 약한 사람도 글자를 제대로 읽을 수 있도록 정해진 국제 가이드라인이다. 그중 'AA'라는 달성 기준 중 하나에 글자색과 배경색의 명암 차이에 관한 규칙이 있다. '명암 대비(Contrast ratio) 4.5:1 이상'이라는 것은 배경색과 글자색의 밝기 차이를 수치화한 것으로, 수치가 낮을수록 글자와 배경의 구분이 어려워져 희미하고 읽기 힘든 표시가 된다. 팔레트를 결정하는 시점에서 사용하는 모든 배색 조합에 대해 이 수치를 확인했다.
구현이 진행된 후에 eyebrow 라벨(화면 상단의 작은 보충 텍스트)의 명암 대비가 4.6:1로 아슬아슬한 수치였기에, 미세 조정을 통해 대비를 높이는 수정을 넣었다. 기준인 4.5:1은 넘었지만, 아슬아슬한 수치 그대로 두면 향후 미세 조정 시 쉽게 기준 미달이 될 수 있다고 판단하여 여유를 두는 방향으로 결정했다.
애니메이션에 대해서도 색상과 마찬가지로 완성도가 아닌 구조부터 결정했다. CSS에는 '사용자가 OS 측에서 애니메이션을 억제하는 설정을 했는지 여부'를 판정할 수 있는 prefers-reduced-motion이라는 미디어 쿼리(Media query)가 있다. 마스코트의 손짓 애니메이션은 이 안에만 가두어, 사용자가 애니메이션 억제 설정을 해두었다면 정지 화면으로 표시되도록 했다.
/* prefers-reduced-motion: no-preference 안에서만 애니메이션을 가둔다.
사용자가 '동작 줄이기' 설정을 한 경우에는 이 블록 전체가 적용되지 않고 정지 화면이 된다 */
@media (prefers-reduced-motion: no-preference) {
...
이렇게 작성하는 이유는 단순하다. "움직임이 불편한 사람에게는 처음부터 움직임을 보여주지 않는다"를 CSS의 조건 분기만으로 보장할 수 있기 때문이다. JavaScript로 사용자 설정을 판정한 뒤 나누어 보여주는 것보다, 브라우저 표준 미디어 쿼리에 맡기는 편이 판정 누락이 일어나기 어렵다.
링크 카드에는 focus-visible의 링 표시를 전부에 적용하여, 키보드 조작 시에도 어디에 포커스(Focus)가 있는지 알 수 있도록 했다. 마우스를 사용하지 않고 키보드의 Tab 키만으로 페이지 내를 이동하는 사람에게 '지금 어떤 링크를 선택하고 있는지' 보이지 않는 것은 치명적이므로, 이 부분은 처음부터 모든 링크에 일괄적으로 적용했다.
// 모든 링크 카드에 공통으로 부여하는 클래스 (Tailwind)
// focus-visible: 키보드 조작으로 포커스가 닿았을 때만 링을 표시한다
// (마우스 클릭 시에는 표시되지 않으므로 시각적 노이즈가 되지 않는다)
...
focus-visible을 사용하는 이유는 단순한 focus를 사용하면 마우스로 클릭했을 때도 링이 나타나 시각적 노이즈가 되기 때문이다. 키보드 조작을 하는 사람에게만 필요한 정보를, 키보드 조작을 하는 사람에게만 제공한다.
다시 만들고 나서 시간이 조금 흐른 지금, 솔직한 감상을 적어둔다. 현재의 404 페이지는 다음과 같은 화면이 되었다.
![[after-4.4.png]]
로드맵 길 위에 깃발을 세우고, 구름 마스코트가 손을 흔들며 "아래 링크에서 배울 수 있어!"라고 안내하는 구도로 만들었다. 에러 표시가 아니라, 학습 경로 도중에 들른 작은 휴식 같은 느낌을 목표로 했다.
캐릭터의 움직임은 아직 딱딱하다고 느낀다. 손을 흔드는 애니메이션도, 말풍선이 나타나는 방식도 의도했던 만큼의 부드러움에는 미치지 못했다. 이 부분은 현재 구현의 한계로 인정해두려 한다.
다만, 첫 번째 목적이었던 "사용자가 길을 잃었을 때의 이탈 방지"는 일단 달성했다고 생각한다. 아무런 정보 없는 404 페이지로 내버려 두는 것이 아니라, 다음에 어디로 나아갈 수 있는지 보여주는 대체 동선을 마련함으로써, 막다른 길에서 끝나지 않는 화면이 되었다.
구체적으로는 손을 흔드는 애니메이션의 타이밍이나 움직임 자체가 아직 기계적이고 부자연스럽다고 느낀다. 마스코트를 2D 도형으로 움직이는 지금의 방식에는 한계가 있어서, 예를 들어 3D 오브젝트로 따로 만든 뒤 이를 페이지에 포함하는 식의 접근 방식을 취한다면 훨씬 자연스러운 움직임에 가까워질 수 있지 않을까 하는 생각도 든다. 지금은 그럴 기술도 지식도 없어서 일단 보류해 두었지만, 언젠가 시도해보고 싶다.
디자인 측면에서는 아직 발전 가능성이 큰 화면이라고 생각한다. 이번 프로세스를 통해 컨셉의 언어화나 패턴 추출은 할 수 있게 되었지만, 실제 조형이나 모션의 질을 높이는 부분은 앞으로의 과제다. UI의 디자인성을 더욱 높일 수 있도록 계속해서 학습을 이어가고 싶다.
『Under the Hood UI Design』을 읽고, 404 페이지라는 작은 화면이 "단순한 에러 표시"가 아니라 "막다른 길에서 무엇을 보여줄지 설계하는 화면"이라는 것을 깨달았다. 그 깨달음을 그대로 두지 않고, 실제로 컨셉의 언어화, 패턴 추출, 덜어내기(Subtraction)의 판단, 접근성(Accessibility)의 포함이라는 의사결정을 쌓아 올리며 화면 하나를 다시 만들어 보았다.
책을 읽는 것으로 끝내지 않고 직접 손을 움직여 보니 처음으로 알게 된 것들이 있었다. 다음에 새로운 화면을 만들 때도 우선 책 속에서 비슷한 과제를 찾는 것부터 시작해보고 싶다.
읽기 전에는 404 페이지와 같은 작은 화면은 에러를 뱉지 않으면 그만이라는 취급이었다. 읽은 후에는 작은 화면이라고 해서 대충 해도 되는 이유는 아니라고 생각하게 되었다.
서평 『Under the Hood UI Design』에서는 이 책의 배움에 대해 자세히 적고 있다. 이번 404 페이지의 재제작은 그 배움을 내 손으로 직접 시험해 본 기록이다.
note 서평 『Under the Hood UI Design』: https://note.com/fumi_ai_202507/n/n7064b8fa4f70?app_launch=false
Q: 책에서 읽은 내용을 UI 개선에 어떻게 활용하면 좋을까?
A: 책 속의 추상적인 원칙을 자신이 가진 구체적인 화면의 과제에 연결해 보는 것이 좋다. 이번에는 "대기 시간의 디자인 = 기다리는 동안 무엇을 보여줄 것인가"라는 배움을 "404 페이지 = 막다른 길에서 무엇을 보여줄 것인가"라는 다른 과제로 치환하여 생각했다.
Q: 404 페이지 디자인에서 주의할 점은?
A: "길을 잃은 일러스트 + 돋보기"와 같은 전형적인 템플릿을 그대로 사용하면 개성이 사라진다. 기존 사이트의 토큰(색상, 타이포그래피)을 따르면서도, 마스코트를 단순 장식이 아닌 상태 설명 역할로 기능하게 한다는 판단 기준을 갖는 것이 좋다.
Q: AI가 만든 UI 디자인 초안을 어떻게 개선할까?
A: 피드백의 말을 그대로 반영하는 것이 아니라, 그 말이 가리키는 구조적인 문제를 그때마다 확인하며 고쳐나간다. 템플릿적인 발상은 AI가 먼저 시도하기 쉬우므로, 하나씩 "이것은 아니다"라고 말로써 깎아 나가는 작업이 컨셉을 날카롭게 다듬어준다.
Q: 접근성 대응에서 최소한으로 해야 할 일은?
A: 글자와 배경의 명도 차이를 나타내는 대비비(Contrast Ratio) 4.5:1 이상(WCAG AA 기준), prefers-reduced-motion을 통한 애니메이션 제어, focus-visible을 통한 키보드 포커스 표시라는 3종 세트를 색상이나 레이아웃을 결정하는 초기 단계부터 포함하는 것이 좋다 (WCAG 2.1 Understanding SC 1.4.3 / MDN prefers-reduced-motion).
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기