본문 바로가기
Frontend2026년 9월 30일19분 읽기

목록 카드에서 잘리지 않는 썸네일 — OG 이미지 1200×630 세이프존과 헤드리스 크롬 자동 생성

YS
김영삼
조회 9
목록 카드에서 잘리지 않는 썸네일 — OG 이미지 1200×630 세이프존과 헤드리스 크롬 자동 생성

OG 이미지(1200×630)를 목록 카드에서도 그대로 쓰려면, 핵심 글자는 가운데 약 700px 안에 두 줄 이내로 넣고 양옆은 잘려도 되는 장식으로 채우면 된다.

카드 레이아웃은 대부분 object-fit: cover로 이미지를 잘라 낸다. 그래서 1200×630 전체에 글자를 꽉 채운 썸네일은 SNS 미리보기에서는 멀쩡해 보여도 내 사이트 목록에서는 양끝 글자가 날아간다. 내가 youngsam.net 프로그램 목록에서 실제로 겪은 일이고, 그 뒤로 썸네일은 HTML 템플릿과 헤드리스 크롬으로 만든다. 그 과정에서 정한 규칙을 정리해 둔다.

3줄 요약
  • PC 목록 카드는 1200×630을 거의 정사각(약 280×228)으로 잘라서, 원본 기준 좌우 약 210px씩이 보이지 않는다.
  • 핵심 글자는 가운데 약 700px, 두 줄 이내. 양옆은 잘려도 아무 손해 없는 장식(도면 선, 표, 차트)으로 채운다.
  • HTML/CSS로 카드를 그리고 --headless=new --screenshot로 PNG를 뽑되, 한글 폰트는 base64로 박아 넣어야 서버에서 두부(□)가 안 생긴다.

PART 01목록 카드는 썸네일을 생각보다 많이 자른다

썸네일을 흔히 "SNS 공유용 그림"으로만 생각한다. 1200×630 캔버스를 꽉 채워 제목을 깔고 구석구석 정보를 넣어도, 공유 미리보기로 보면 대개 그럴듯하다. 내 경우 문제는 바깥이 아니라 내 사이트 안이었다.

youngsam.net의 프로그램 목록(/programs) PC 화면은 카드 위쪽 이미지 칸이 약 280×228, 거의 정사각에 가까운 비율이다. 여기에 가로로 긴 1200×630 이미지를 object-fit: cover로 넣으면 브라우저는 높이를 칸에 맞춘 뒤 넘치는 좌우를 잘라 버린다. 계산해 보면 높이 630을 228로 줄이는 배율이 약 0.36이고, 그러면 폭은 약 434px이 되어 칸보다 150px 넘게 넓다. 양쪽으로 나눠 잘리니 원본 기준으로 좌우 약 210px씩이 화면에 안 나온다. 1200px 중 실제로 보이는 건 가운데 780px 남짓이다.

모바일 목록은 사정이 또 달랐다. 이미지 칸 비율이 원본과 조금 어긋나 있어서 이번엔 위아래가 약 47px 정도씩 잘리는 배치였다. 이쪽은 카드 이미지 칸 자체를 aspect-ratio: 1200 / 630으로 맞춰서 잘림을 없앴다. 반면 PC 카드는 목록 디자인상 정사각에 가까운 칸을 유지하고 싶었기 때문에, 이미지를 고치는 쪽을 택했다.

같은 1200×630 이미지가 놓이는 자리별 잘림 영역
보이는 곳표시 형태잘리는 영역(원본 1200×630 기준)대응
PC 목록 카드약 280×228, object-fit: cover좌우 약 210px씩핵심은 가운데 약 700px 안에
모바일 목록 카드처음엔 비율이 어긋난 칸위아래 약 47px 정도칸을 aspect-ratio 1200/630으로 맞춤
SNS·메신저 미리보기플랫폼마다 다름가로로 더 긴 비율이면 위아래, 정사각이면 좌우가운데·두 줄 원칙이면 대부분 안전
검색 결과·피드 작은 썸네일아주 작게 축소잘리기보다 글자가 뭉개짐글자 수를 줄이고 크게

이 표를 만들고 나서야 감이 왔다. 썸네일은 "한 장의 그림"이 아니라 여러 크기의 창문으로 동시에 들여다보는 그림이다. 어느 창문으로 봐도 남는 공통 영역은 가운데 한 덩어리뿐이고, 거기에 들어갈 수 있는 정보는 생각보다 적다.

삽질 기록 · 세 번째 시안에서야 통과했다
CAD 프로그램 썸네일을 만들 때 일이다. 첫 시안은 기능 아이콘과 설명을 빼곡히 넣은 버전, 두 번째는 스크린샷을 크게 깔고 제목을 얹은 버전이었다. 둘 다 같이 보던 사람에게 "별로"라는 한마디로 퇴짜를 맞았다. 목록 카드 크기로 줄여 보니 이유가 바로 보였다. 첫 시안은 글자가 깨알이었고, 두 번째는 스크린샷 때문에 제목이 배경에 묻혔다. 세 번째는 정보를 거의 다 덜어 냈다. 배경은 청사진 격자, 위에 브랜드 한 줄, 가운데 두 줄짜리 제목만 두고, 둘째 줄에 그라데이션을 준 다음 그 아래 AI 입력창 모양의 바 하나를 놓았다. 양옆 청사진 도면 선은 잘려도 그만인 장식이다. 이 시안이 한 번에 통과했다. 그때 배운 건 단순하다. 정보를 덜어 내고, 한 문장만 크게.

PART 02세이프존 규칙 — 가운데 700px, 두 줄, 짧게

그 뒤로 정한 규칙은 세 가지다. 첫째, 핵심 글자(제목)는 가운데 약 700px 폭 안에 둔다. 좌우 210px씩을 빼면 780px 정도가 남지만 카드 테두리 둥근 모서리와 여백까지 생각해 조금 더 안쪽으로 잡았다. 둘째, 제목은 두 줄 이내. 세 줄이 되는 순간 글자 크기를 줄여야 하고, 줄인 글자는 목록에서 안 읽힌다. 셋째, 양옆은 장식이다. CAD 프로그램이면 청사진 도면 선, 스프레드시트 프로그램이면 표와 차트 조각처럼 프로그램 성격은 드러내되 잘려도 의미가 안 바뀌는 것만 둔다.

하나 더 있다. 자동으로 버전업되는 프로그램 썸네일에는 버전 숫자를 넣지 않는다. 처음엔 버전을 넣으면 최신 느낌이 나서 좋다고 생각했는데, 업데이트가 몇 번 지나면 썸네일만 옛날 버전을 말하고 있다. SNS 미리보기는 캐시가 오래 남기도 해서, 틀린 숫자가 생각보다 오래 돌아다닌다. 버전은 본문과 다운로드 버튼이 말하면 충분하다.

세이프존 레이아웃 뼈대
/* 1200x630 캔버스: 가운데 700px만 '말하는' 영역 */
body { width: 1200px; height: 630px; margin: 0; overflow: hidden;
       position: relative; font-family: P, sans-serif; }

/* 양옆 장식: 잘려도 되는 영역 */
.deco { position: absolute; inset: 0; pointer-events: none; }

/* 세이프존: 글자는 전부 여기 안에 */
.safe {
  position: absolute; top: 0; bottom: 0;
  left: 50%; width: 700px; transform: translateX(-50%);
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; text-align: center;
}
.safe h1 { margin: 0; line-height: 1.1; letter-spacing: -2px; }
.safe .l1 { display: block; font-size: 58px; font-weight: 800; }
.safe .l2 { display: block; font-size: 86px; font-weight: 900;
            background: linear-gradient(90deg, #4f9dff, #79e3ff);
            -webkit-background-clip: text; color: transparent; }

/* 검수용: 이 클래스를 켜면 세이프존 테두리가 보인다 */
.debug .safe { outline: 2px dashed rgba(255, 0, 0, .6); }

여기서 중요한 건 .safe 폭을 숫자로 못 박아 둔 것이다. 제목이 길어서 700px을 넘으면 줄바꿈이 되고, 두 줄을 넘으면 템플릿을 고칠 게 아니라 문장을 고쳐야 한다는 신호다. 검수할 때는 debug 클래스를 붙여 빨간 점선을 켜 놓고 한 번 찍어 본다. 점선 밖으로 글자가 삐져나오면 그 썸네일은 목록 어딘가에서 잘린다.

영삼
내 생각
썸네일은 "축소했을 때 읽히는가"가 전부라고 본다. 1200×630 원본을 모니터에 띄워 놓고 보면 뭘 넣어도 다 읽힌다. 그래서 정보를 자꾸 더하게 된다. 하지만 사람들이 실제로 보는 건 손톱만 한 카드나 메신저 미리보기다. 나는 이제 썸네일을 검수할 때 원본은 보지 않고, 목록 카드 크기로 줄인 것만 본다. 정보 욕심이 썸네일을 망친다.

PART 03왜 이미지 편집 툴 대신 HTML 템플릿인가

썸네일을 디자인 툴로 한 장씩 만들던 시절도 있었다. 한두 장이면 그게 빠르다. 그런데 프로그램이 늘고 기술노트를 꾸준히 쓰기 시작하니 이야기가 달라졌다. 제목만 바꿔 같은 틀로 수십 장을 찍어야 하고, 규칙(세이프존, 두 줄, 버전 숫자 금지)을 바꾸면 이미 만든 것도 다시 뽑아야 한다. 툴 파일로는 그 반복이 지옥이다.

이미지 편집 툴한 장 특화
  • 자유로운 배치, 세밀한 보정
  • 틀 변경 시 한 장씩 다시 손봐야 함
  • 글자 내용이 파일 안에 갇혀 자동화가 어렵다
  • 결과가 사람 손에 따라 조금씩 달라짐
HTML 템플릿 + 헤드리스 크롬반복 특화
  • 제목·색만 데이터로 넣으면 끝
  • CSS 한 줄 고치고 전부 재생성
  • 세이프존을 코드로 강제할 수 있다
  • 폰트 임베드만 잘하면 어디서 찍어도 같은 결과

나는 반복 작업에는 HTML 템플릿이 확실히 낫다고 본다. 웹 개발자라면 이미 CSS로 레이아웃을 다루는 데 익숙하고, flex로 가운데 정렬하는 게 툴에서 가이드라인 맞추는 것보다 빠르다. 그라데이션 글자, 격자 배경, 반투명 도형 같은 것도 CSS면 몇 줄이다. 무엇보다 썸네일이 "데이터에서 나오는 결과물"이 된다는 게 크다. 글 제목이 바뀌면 썸네일도 같은 스크립트로 다시 뽑으면 된다.

기술노트 썸네일도 같은 방식이다. 템플릿은 하나고, 카테고리별로 강조색과 배경 광원 색만 바꾼다. Frontend는 파란 계열, Backend는 초록 계열 하는 식이다. 글마다 넣는 건 상단 칩 한 줄, 제목 두 줄, 부제 한 줄뿐이다.

PART 04헤드리스 크롬으로 PNG 뽑기

HTML을 PNG로 바꾸는 방법은 여러 가지지만, 나는 크롬 자체의 헤드리스 모드를 쓴다. 별도 라이브러리 없이 명령 한 줄이면 되고, 내가 브라우저에서 보던 렌더링과 결과가 같다. 요즘 크롬은 --headless=new로 실제 브라우저와 같은 엔진을 쓰는 새 헤드리스 모드를 켠다.

헤드리스 크롬 스크린샷 명령
# card.html 을 1200x630 PNG로 저장
chrome \
  --headless=new \
  --disable-gpu \
  --hide-scrollbars \
  --force-device-scale-factor=1 \
  --window-size=1200,630 \
  --screenshot=out.png \
  file:///path/to/card.html

# 서버(root 컨테이너 등)에서 샌드박스 문제로 안 뜨면
# 권한 구조를 확인한 뒤 --no-sandbox 를 검토한다

옵션 몇 개는 꼭 챙긴다. --window-size=1200,630은 캔버스 크기 그 자체다. --hide-scrollbars가 없으면 혹시 내용이 넘칠 때 스크롤바가 찍힐 수 있다. --force-device-scale-factor=1은 고해상도 화면 설정이 끼어들어 2400×1260으로 뽑히는 걸 막는다.

용량도 한 번은 봐야 한다. 격자와 그라데이션이 많은 PNG는 수백 KB가 되기 쉽다. 목록 페이지에 카드가 수십 개 깔리면 그게 그대로 로딩 시간이 된다. 목록용으로는 작은 크기로 줄여 내보내는 경로를 두는 게 좋고, SNS용 og:image는 원본 크기 그대로 두면 된다. 그리고 목록 카드의 alt에는 썸네일 문구가 아니라 글 제목을 넣는다. 그림 속 글자는 스크린 리더가 읽지 못하니까.

PART 05서버에서 한글이 두부로 깨지는 문제 — 폰트를 base64로 박는다

HTML 템플릿 방식의 함정은 폰트다. 폰트가 깔린 내 PC에서는 멀쩡한 템플릿도, 폰트 없는 서버에서 찍으면 한글이 전부 네모(□), 이른바 두부로 나온다. 이유는 간단하다. 서버에는 한글 폰트가 깔려 있지 않고, 크롬은 글자를 그릴 폰트를 못 찾으면 빈 상자를 그린다. CSS에 font-family: Pretendard라고 써 봤자 그 이름의 폰트가 시스템에 없으면 소용없다.

외부 CDN에서 웹폰트를 불러오는 방법도 있지만, 스크린샷 타이밍에 폰트가 다 안 받아지면 또 깨진다. 그래서 나는 폰트 파일을 base64로 인코딩해 @font-face의 src에 data URI로 직접 넣는다. HTML 파일 하나가 폰트까지 다 품고 있으니 네트워크도, 시스템 폰트도 필요 없다. 굵기는 900, 800, 700, 500 네 가지를 각각 따로 임베드했다. 굵기를 하나만 넣으면 브라우저가 가짜 볼드를 만들어서 글자가 뭉개 보인다.

Pretendard를 data URI로 임베드한 @font-face (base64는 줄임)
/* 굵기별로 따로 선언. base64는 실제로 수백 KB 길이 */
@font-face {
  font-family: P; font-weight: 900;
  src: url(data:font/woff2;base64,d09GMgABAAAA...) format('woff2');
}
@font-face {
  font-family: P; font-weight: 800;
  src: url(data:font/woff2;base64,d09GMgABAAAA...) format('woff2');
}
@font-face {
  font-family: P; font-weight: 700;
  src: url(data:font/woff2;base64,d09GMgABAAAA...) format('woff2');
}
@font-face {
  font-family: P; font-weight: 500;
  src: url(data:font/woff2;base64,d09GMgABAAAA...) format('woff2');
}
body { font-family: P, sans-serif; }
두부 확인법. 생성 스크립트를 처음 서버에 올렸다면, 결과 PNG를 열어 한글 받침이 있는 글자(예: "읽", "썸")를 꼭 확인한다. 영문과 숫자는 서버 기본 폰트로 멀쩡히 나오기 때문에, 한글만 깨진 걸 썸네일을 대충 보면 놓치기 쉽다. woff2 base64는 보통 d09GMg로 시작하니, 인코딩이 제대로 들어갔는지도 이걸로 눈대중할 수 있다.

PART 06자동 생성 + 사람 눈 검수, 1인 운영자의 조합

템플릿으로 자동화했다고 검수가 필요 없어지지는 않는다. 오히려 자동화하면 실수도 대량으로 찍힌다. 제목이 길면 세 줄로 넘어가고, 긴 영문 단어 하나가 세이프존을 뚫기도 한다. 템플릿은 그걸 막아 주지 않고 그대로 찍어 낼 뿐이다. 그래서 나는 생성은 스크립트가 하고, 마지막 확인은 반드시 사람 눈으로 한다.

썸네일 검수 체크리스트
✓목록 카드 크기(약 280×228)로 줄였을 때 제목이 한눈에 읽히는가
✓제목이 두 줄 이내이고, 세이프존(가운데 약 700px) 점선 안에 다 들어가는가
✓양옆 210px을 가려도 의미가 안 바뀌는가(장식만 있는가)
✓한글이 두부(□)로 깨지지 않았는가 — 받침 있는 글자로 확인
✓버전 숫자처럼 금방 낡을 정보가 들어 있지 않은가
✓배경과 글자 대비가 충분한가(작게 줄였을 때 묻히지 않는가)
✓PNG 용량이 지나치게 크지 않은가, og:image URL이 실제로 열리는가
✓목록 카드 alt에 글 제목이 들어가는가

혼자 사이트를 굴리면 디자이너도, 매번 툴을 열 시간도 없다. 그렇다고 전부 기계에 맡기면 이상한 썸네일이 조용히 쌓인다. 기계가 반복하고 사람이 판단하는 조합이 1인 운영자에게 가장 현실적이라고 본다.

영삼
내 생각
나는 썸네일 자동 생성의 목표를 "예쁜 그림"이 아니라 "실수할 수 없는 틀"로 잡는 게 맞다고 생각한다. 세이프존을 코드로 고정하고, 넣을 수 있는 글자 칸을 세 개로 제한해 버리면 아무리 급하게 만들어도 크게 망가지지 않는다. 자유도를 뺏는 게 오히려 품질을 지킨다.
SNS 미리보기는 따로 확인한다. og:image 권장 크기로 흔히 1200×630이 쓰이고, X(트위터)는 twitter:card를 summary_large_image로 주면 큰 이미지 카드로 보여 준다. 다만 카카오톡, 슬랙, 각종 메신저는 미리보기 크롭 방식이 서로 다르고 바뀌기도 한다. 정확한 수치를 외우기보다 가운데·두 줄 원칙을 지키고 실제로 한 번 공유해 보는 편이 확실하다.
썸네일을 만들 때 남겨 둘 것
  1. 1200×630이라도 내 목록 카드가 어떻게 자르는지부터 계산한다. PC 카드는 좌우 약 210px씩 사라졌다.
  2. 핵심 글자는 가운데 약 700px, 두 줄 이내. 양옆은 잘려도 되는 장식만.
  3. 금방 낡는 정보(버전 숫자)는 넣지 않는다.
  4. HTML 템플릿 + --headless=new --screenshot로 찍고, 한글 폰트는 굵기별 base64로 임베드한다.
  5. 자동 생성 뒤에는 반드시 축소본으로 사람 눈 검수를 한다.

자주 묻는 질문

OG 이미지 크기는 1200×630이면 충분한가요?

대부분의 SNS와 메신저가 1200×630 근처의 가로형 이미지를 무리 없이 보여 주기 때문에 기준 크기로 많이 쓴다. 다만 크기보다 중요한 건 잘림이다. 플랫폼마다, 그리고 내 사이트 목록 카드마다 잘리는 부분이 달라서 핵심 글자를 가운데에 모아 두는 게 더 효과가 크다.

목록 카드에서 썸네일 양끝 글자가 잘리는 이유는 무엇인가요?

카드 이미지 칸 비율이 원본(약 1.9:1)보다 정사각에 가까운데 object-fit: cover를 쓰면, 높이를 맞춘 뒤 넘치는 좌우를 잘라 내기 때문이다. 약 280×228 칸이라면 1200×630 원본 기준 좌우 약 210px씩이 안 보인다. 칸 비율을 바꾸거나, 글자를 가운데 안전 영역에 두면 해결된다.

헤드리스 크롬으로 찍은 썸네일에서 한글이 네모로 깨질 때는 어떻게 하나요?

서버에 한글 폰트가 없어서 생기는 두부 현상이다. 폰트 파일을 base64로 인코딩해 @font-face의 src에 data URI로 넣으면 시스템 폰트와 네트워크 없이도 한글이 제대로 그려진다. 굵기별로 따로 임베드해야 가짜 볼드가 생기지 않는다.

썸네일에 버전 번호를 넣으면 안 되나요?

자주 업데이트되는 프로그램이라면 넣지 않는 걸 권한다. 업데이트가 몇 번만 지나도 썸네일이 옛 버전을 말하게 되고, SNS 미리보기 캐시 때문에 틀린 숫자가 오래 남는다. 버전은 본문이나 다운로드 영역에서 보여 주는 편이 정확하다.

썸네일은 디자인 툴로 만드는 게 낫나요, HTML로 만드는 게 낫나요?

한두 장이면 디자인 툴이 빠르다. 같은 틀로 제목만 바꿔 계속 만들어야 한다면 HTML 템플릿과 헤드리스 크롬이 훨씬 낫다. 규칙을 코드로 강제할 수 있고, 틀을 바꿔도 스크립트 한 번으로 전부 다시 뽑을 수 있다.

참고 자료

댓글 0

아직 댓글이 없습니다.
Ctrl+Enter로 등록