OG 이미지(1200×630)를 목록 카드에서도 그대로 쓰려면, 핵심 글자는 가운데 약 700px 안에 두 줄 이내로 넣고 양옆은 잘려도 되는 장식으로 채우면 된다.
카드 레이아웃은 대부분 object-fit: cover로 이미지를 잘라 낸다. 그래서 1200×630 전체에 글자를 꽉 채운 썸네일은 SNS 미리보기에서는 멀쩡해 보여도 내 사이트 목록에서는 양끝 글자가 날아간다. 내가 youngsam.net 프로그램 목록에서 실제로 겪은 일이고, 그 뒤로 썸네일은 HTML 템플릿과 헤드리스 크롬으로 만든다. 그 과정에서 정한 규칙을 정리해 둔다.
- 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 카드는 목록 디자인상 정사각에 가까운 칸을 유지하고 싶었기 때문에, 이미지를 고치는 쪽을 택했다.
이 표를 만들고 나서야 감이 왔다. 썸네일은 "한 장의 그림"이 아니라 여러 크기의 창문으로 동시에 들여다보는 그림이다. 어느 창문으로 봐도 남는 공통 영역은 가운데 한 덩어리뿐이고, 거기에 들어갈 수 있는 정보는 생각보다 적다.
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 클래스를 붙여 빨간 점선을 켜 놓고 한 번 찍어 본다. 점선 밖으로 글자가 삐져나오면 그 썸네일은 목록 어딘가에서 잘린다.
PART 03왜 이미지 편집 툴 대신 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 네 가지를 각각 따로 임베드했다. 굵기를 하나만 넣으면 브라우저가 가짜 볼드를 만들어서 글자가 뭉개 보인다.
/* 굵기별로 따로 선언. 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; }d09GMg로 시작하니, 인코딩이 제대로 들어갔는지도 이걸로 눈대중할 수 있다.PART 06자동 생성 + 사람 눈 검수, 1인 운영자의 조합
템플릿으로 자동화했다고 검수가 필요 없어지지는 않는다. 오히려 자동화하면 실수도 대량으로 찍힌다. 제목이 길면 세 줄로 넘어가고, 긴 영문 단어 하나가 세이프존을 뚫기도 한다. 템플릿은 그걸 막아 주지 않고 그대로 찍어 낼 뿐이다. 그래서 나는 생성은 스크립트가 하고, 마지막 확인은 반드시 사람 눈으로 한다.
혼자 사이트를 굴리면 디자이너도, 매번 툴을 열 시간도 없다. 그렇다고 전부 기계에 맡기면 이상한 썸네일이 조용히 쌓인다. 기계가 반복하고 사람이 판단하는 조합이 1인 운영자에게 가장 현실적이라고 본다.
twitter:card를 summary_large_image로 주면 큰 이미지 카드로 보여 준다. 다만 카카오톡, 슬랙, 각종 메신저는 미리보기 크롭 방식이 서로 다르고 바뀌기도 한다. 정확한 수치를 외우기보다 가운데·두 줄 원칙을 지키고 실제로 한 번 공유해 보는 편이 확실하다.- 1200×630이라도 내 목록 카드가 어떻게 자르는지부터 계산한다. PC 카드는 좌우 약 210px씩 사라졌다.
- 핵심 글자는 가운데 약 700px, 두 줄 이내. 양옆은 잘려도 되는 장식만.
- 금방 낡는 정보(버전 숫자)는 넣지 않는다.
- HTML 템플릿 +
--headless=new --screenshot로 찍고, 한글 폰트는 굵기별 base64로 임베드한다. - 자동 생성 뒤에는 반드시 축소본으로 사람 눈 검수를 한다.
자주 묻는 질문
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