긴 콘텐츠와 반응형
100분 안팎
학습 목표
좁은 화면에서 긴 제목과 URL의 넘침을 해결합니다.
개념
왜 긴 콘텐츠를 넣고 확인하나요
짧은 행사명 세 개로 화면을 완성하면 실사용에서 긴 행사명 하나가 전체 페이지를 밀어낼 수 있습니다. 제목이 길고 주소에 공백이 없거나 이미지 원본이 큰 경우를 처음부터 fixture에 넣습니다. 이미지 없는 카드도 함께 확인합니다. 예쁜 데이터만 넣고 화면을 맞추면 예외가 들어오는 순간 고정 폭과 최소 크기 문제가 드러납니다.
이 레슨 starter에는 앞 단계의 Flex와 Grid가 구현돼 있지만 카드 최소 폭 320px, 줄바꿈 금지 설명, 1200px 이미지 규칙이 들어 있습니다. 페이지 전체 가로 스크롤이 생겨도 세 원인이 같은 속성으로 고쳐지는 것은 아닙니다. 가장 넓게 튀어나온 요소를 찾고 상자, 텍스트, 이미지 순서로 원인을 줄입니다.
먼저 상자와 콘텐츠를 구분합니다
Grid 트랙을 minmax(0,1fr)로 만들었어도 그 안의 카드에 min-width:320px가 있으면 카드 자체가 더 작아지지 않습니다. 카드에 min-width:0을 적용해 열 너비에 맞게 축소할 수 있게 합니다. 이 선언은 글자를 줄바꿈시키는 명령이 아닙니다. 상자가 줄어든 다음에도 내용이 밖으로 그려질 수 있어 텍스트를 별도로 처리합니다.
긴 한국어 제목과 공백 없는 URL은 서로 다른 줄바꿈 조건을 가질 수 있습니다. 문장 안의 일반 공백으로 나누기 어려운 문자열에 overflow-wrap:anywhere를 적용하면 필요한 곳에서 줄을 나눌 수 있습니다. 원래 링크 주소를 바꾸지 않고 화면의 텍스트 배치를 바꿉니다. href를 잘라서 짧게 만들면 목적지 계약이 달라질 수 있으므로 그런 방법은 사용하지 않습니다.
white-space:nowrap은 줄바꿈을 막습니다. 줄바꿈 속성을 추가했는데 설명이 한 줄로 남으면 이 선언이 적용됐는지 봅니다. 실습은 event-description의 white-space를 normal로 되돌립니다. word-break:break-all을 모든 문장에 적용하면 읽기 어려운 위치에서도 단어가 끊길 수 있습니다. 먼저 긴 콘텐츠가 어디에 있는지 보고 필요한 범위를 선택합니다.
이미지는 비율을 유지하며 축소합니다
HTML의 width와 height는 이미지의 원본 비율을 알려 주는 데 도움이 됩니다. 예시 SVG는 1200 대 600의 비율입니다. CSS max-width:100%는 포함 영역보다 커지지 않게 하고 height:auto는 너비가 줄어들 때 높이가 비율에 맞춰 변하도록 합니다. 원본보다 크게 늘려야 한다는 요구는 없으므로 항상 width:100%로 확대시키지는 않습니다.
starter의 img width:1200px 선언을 제거하고 max-width와 자동 높이를 적용합니다. 너비만 줄이고 높이를 600px로 남기면 그림이 길게 늘어날 수 있습니다. 카드에 이미지가 없어도 제목과 설명이 문서 흐름에 남아 읽혀야 합니다. 이미지가 있는 카드 높이에 맞추려고 모든 카드 내용에 고정 높이를 주는 방식은 긴 설명을 자를 수 있습니다.
외부 이미지 주소를 쓰지 않고 실습 assets/event.svg를 사용합니다. 네트워크 접근 없이 같은 경계 상황을 재현하기 위한 선택입니다. 이미지 로드 실패와 큰 이미지 넘침은 다른 문제입니다. 깨진 이미지 표시가 있다면 src의 상대 경로와 파일 존재를 먼저 확인합니다. 그림을 CSS 배경으로 옮겨 alt 설명 관계를 잃을 필요는 없습니다.
작은 화면부터 전체 문서를 점검합니다
index.html뿐 아니라 event.html과 results.html도 공통 CSS와 viewport를 사용해야 합니다. 목록이 정상이어도 상세에 긴 주소가 있거나 viewport가 빠져 모바일에서 다른 축척으로 보일 수 있습니다. 이전 모듈의 간단한 두 페이지를 확장하면서 상대 경로와 돌아가기 링크를 유지합니다. 한 화면만 수정해 사용자 흐름 중간에 문제가 남지 않게 합니다.
콘솔에서 document.documentElement.scrollWidth와 clientWidth를 비교합니다. scrollWidth가 더 크면 문서 전체에 가로 넘침이 있다는 단서입니다. 수치가 같아도 숨김 처리로 내용이 잘렸을 수 있으므로 전체 제목과 링크 텍스트를 읽습니다. 링크가 다음 줄에서 잘리거나 포커스 외곽선이 숨겨지는지도 봅니다. 측정과 관찰을 서로 대신하지 않습니다.
320·390·768·1280 CSS px에서 목록, 상세, 결과를 각각 확인합니다. 좁은 폭에서 제목이 여러 줄이 되는 것은 자연스러운 결과입니다. 글자가 한 줄에 남는 것을 목표로 삼으면 화면을 넓히거나 글자를 과도하게 줄이게 됩니다. 행 높이가 내용에 맞게 늘어나면서 다음 요소와 겹치지 않는지를 완료 기준으로 삼습니다.
흔한 임시 해결을 경계합니다
body에 overflow-x:hidden을 지정하면 스크롤 막대가 사라질 수 있지만 밖으로 나간 내용까지 돌아오는 것은 아닙니다. 이 프로젝트는 페이지 넘침을 숨기는 선언을 허용하지 않습니다. 카드나 글이 큰 이유를 고칩니다. 코드나 넓은 표처럼 자체 스크롤이 필요한 영역은 별도 설계할 수 있으나 이번 행사 제목과 안내는 줄바꿈으로 전체를 읽게 합니다.
문자 수를 일정 길이로 잘라 표시하면 짧은 카드에서는 좋아 보여도 행사 구분에 필요한 정보가 사라질 수 있습니다. 요약 표시가 제품 요구라면 원문에 접근할 경로와 이름을 따로 설계해야 합니다. 이번 레슨의 목표는 임의로 정보를 제거하지 않고 긴 내용을 담는 것입니다. ellipsis로 테스트 데이터를 감추지 않습니다.
FAIL 이미지 축소와 비율 유지는 img의 max-width 또는 height 선언을 확인하라는 단서입니다. FAIL 카드 최소 너비와 URL 줄바꿈은 트랙 규칙만 바꾸고 카드나 글을 놓쳤는지 보라는 뜻입니다. npm ENOENT나 Python traceback이 나타나면 먼저 폴더와 파일을 확인합니다. 검사 메시지와 실제 브라우저 적용 규칙을 비교해 한 원인씩 수정합니다.
관찰 기록을 남깁니다
LAYOUT.md에는 페이지별 폭과 scrollWidth/clientWidth를 적고 가장 긴 제목, 주소 끝부분, 이미지 비율을 읽은 결과를 남깁니다. 미확인은 실패나 통과로 바꾸지 않습니다. 수정 전 어디가 넘쳤고 어느 선언으로 왜 해결했는지 기록하면 같은 문제가 새 데이터에서 재발했을 때 원인을 빠르게 찾을 수 있습니다. 자동 검사 출력만으로 화면 통과를 선언하지 않습니다.
overflow-wrap:anywhere는 실제 줄바꿈뿐 아니라 최소 콘텐츠 크기 계산에도 줄을 나눌 기회를 반영합니다. overflow-wrap:break-word는 긴 문자열을 나눌 수 있어도 그 기회를 최소 콘텐츠 크기 계산에 같은 방식으로 반영하지 않습니다. 그래서 Grid나 Flex의 자동 최소 크기 문제에서는 두 값이 다른 결과를 낼 수 있습니다. 먼저 카드의 최소 너비 제약을 풀고 텍스트의 줄바꿈 규칙을 확인하면 어느 계층에서 축소가 막혔는지 구분하기 쉽습니다.
줄바꿈과 최소 콘텐츠 크기의 관계는 MDN overflow-wrap 설명에서 더 확인할 수 있습니다. 아래 서재는 Grid 트랙, 카드, 긴 텍스트의 책임을 확장합니다. 이 레슨에서는 행사 탐색 전체 흐름에 긴 fixture를 넣고 문제의 요소를 직접 찾는 능력을 완성합니다.
따라하기
starter와 실패 조건 확인
이 레슨 starter 압축을 새 폴더에 풀고 package.json이 있는 폴더에서 실행합니다. Node/npm과 Python 3가 필요하며 외부 의존 패키지는 없습니다.
npm ci
npm teststarter는 일부 CSS 계약이 FAIL인 상태입니다. check.py와 document-check.py는 고치지 않습니다. ENOENT는 작업 폴더, python3 실행 실패는 Python 설치부터 확인합니다.
해당 단계의 CSS 규칙 교체
assets/site.css 마지막 TODO 실패 블록을 다음 코드로 교체합니다. 이전 단계와 기본 글꼴·포커스 선언은 유지합니다. 동일 선택자의 실패 선언을 뒤에 남기지 않습니다.
.card { min-width: 0; }
h1, h2, h3, p, a { overflow-wrap: anywhere; }
img { display: block; max-width: 100%; height: auto; }
.event-description { white-space: normal; }index.html의 기존 폼 이름과 레이블, GET 목적지는 그대로 둡니다. 저장 후 브라우저를 새로고침합니다.
solution 기준 자동 검사
실습 폴더에서 실행합니다. 아래 출력은 모범 답안을 실제 실행한 결과입니다. 이 검사는 제공 CSS 선언 계약과 앞 모듈 HTML 계약을 확인하며 렌더링 검증 결과는 아닙니다.
npm test실행 결과
> frontend-m02-narrow-screen@1.0.0 test > python3 check.py PASS 앞 모듈 HTML·폼 계약 18개 유지 PASS 긴 제목·URL·이미지 없는 카드 fixture PASS index.html 뷰포트 및 공통 CSS PASS event.html 뷰포트 및 공통 CSS PASS results.html 뷰포트 및 공통 CSS PASS 공통 border-box 및 카드 테두리 PASS 컨테이너 가변 너비와 여백 PASS 카드 padding을 포함하는 가변 너비 PASS 폼 Flex 줄바꿈과 필드 축소 PASS 목록 Grid와 gap PASS 한 열 기본값과 두 열 분기 PASS 폼 이름 및 DOM 순서 보존 PASS 카드 최소 너비와 URL 줄바꿈 PASS 이미지 축소와 비율 유지 PASS 긴 설명 줄바꿈 유지 PASS 페이지 넘침 숨김과 고정 높이 없음 CSS 계약 16개, 실패 0개 화면·200% 확대·실제 Tab 표시는 LAYOUT.md에 별도 기록합니다.
실제 화면과 사용자 흐름 기록
브라우저의 파일 열기로 index.html을 엽니다. index.html·event.html·results.html을 각각 320·390·768·1280px로 확인합니다. 긴 제목과 주소 끝부분이 읽히는지, 이미지 비율과 이미지 없는 카드 흐름이 유지되는지 관찰합니다.
콘솔에서 아래 숫자를 읽고 LAYOUT.md에 환경·페이지·폭·관찰을 남깁니다. 수치가 같아도 잘린 내용이나 포커스가 없는지 눈으로 확인합니다. 실행 전의 결과는 미확인으로 둡니다.
({scrollWidth: document.documentElement.scrollWidth,
clientWidth: document.documentElement.clientWidth})확인 문제
실습
320px 화면의 긴 행사 제목·URL·이미지가 넘치지 않게 고칩니다. starter의 TODO CSS를 수정해 npm ci 후 npm test를 통과시키세요. 자동 검사는 제공 선언 계약만 확인합니다. HTML의 name·label·설명 참조·GET 제출·DOM 순서를 유지하고, 세 페이지 네 폭·200% 확대·키보드 실제 관찰을 LAYOUT.md에 기록합니다. 검사 파일은 수정하지 않습니다.
실행 명령
npm test
기대 결과
CSS 계약 16개, 실패 0개. 화면·확대·키보드 결과는 LAYOUT.md에 별도 기록합니다.
모범 답안
모범 답안 내려받기더 읽기
면접 질문
- Grid 열을 줄였는데 긴 URL이 여전히 넘칠 때 무엇을 확인하나요?
- 이미지에 max-width:100%와 height:auto를 함께 사용하는 이유는 무엇인가요?