도식을 만드는 과정. 그림마다 HTML 파일 하나를 쓰고 공통 base.css 를 불러와, Playwright 로 1600 곱하기 640 화면을 2배 배율로 찍어 PNG 로 만든다. 고칠 때는 이미지 편집기를 열 필요 없이 소스 한 줄만 바꾸고 다시 찍으면 된다.

·8분 읽기

글에 넣는 그림을 그림판 대신 HTML로 씁니다


이 블로그에는 글마다 도식이 한두 장씩 들어갑니다. 열일곱 편을 쓰는 동안 스물몇 장이 됐습니다.

그림판이나 포토샵으로 그렸으면 진작 포기했을 겁니다. 전부 HTML로 씁니다.

그림 한 장이 파일 한 개입니다

도식마다 .html 파일을 하나 만듭니다. 안에 든 건 평범한 웹 페이지입니다.

<meta charset="utf-8" />
<link rel="stylesheet" href="base.css" />
<style>
  .grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
  }
  .card {
    background: var(--card);
    border-radius: 14px;
    padding: 18px;
  }
</style>

<div class="wrap">
  <div class="kicker">같은 칸, 두 가지 형식</div>
  <h1>한쪽만 깨지면 더 오래 못 찾습니다</h1>
  ...
</div>

표를 그리고 싶으면 grid를 쓰고, 카드가 필요하면 border-radius를 줍니다. 평소에 쓰던 CSS 그대로입니다. 새로 배울 게 없다는 게 이 방식의 전부입니다.

찍는 건 열 줄입니다

Playwright로 브라우저를 띄우고 스크린샷을 찍습니다.

import { chromium } from 'playwright';

const b = await chromium.launch();
const p = await b.newPage({
  viewport: { width: 1600, height: 640 },
  deviceScaleFactor: 2,
});

for (const name of ['two-date-formats', 'title-to-url']) {
  await p.goto(`file:///.../${name}.html`);
  await p.evaluate(() => document.fonts.ready);
  await p.waitForTimeout(1400);
  await p.screenshot({ path: `${name}.png` });
}
await b.close();

deviceScaleFactor: 2가 중요합니다. 1600×640짜리 화면을 2배로 찍어 3200×1280 PNG가 나옵니다. 고해상도 화면에서 글자가 흐려지지 않습니다.

base.css 하나로 묶습니다

색, 글꼴, 캔버스 크기는 공통 파일에 둡니다.

:root {
  --bg: #1e1f2e;
  --card: #2a2b3f;
  --fg: #f3f0e7;
  --accent: #e3b567;
}

html, body { width: 1600px; height: 640px; }
.wrap { padding: 40px 56px 34px; height: 640px;
        display: flex; flex-direction: column; }

그림마다 제목 위치가 제각각이면 글을 읽을 때 눈이 피곤합니다. 캔버스 크기와 여백을 여기서 고정해두니 스물몇 장이 한 세트처럼 보입니다.

색을 바꾸고 싶으면 이 파일 하나만 고치면 됩니다. 스물몇 장이 같이 바뀝니다.

이 방식이 좋은 진짜 이유

무엇보다 고치기가 쉽습니다.

도식에서 오타를 하나 발견했다고 해봅시다. 이미지 파일이라면 원본을 찾아서 편집기를 열고 같은 글꼴을 찾아 다시 쓰고 다시 내보내야 합니다. 원본을 잃어버렸으면 처음부터입니다.

여기서는 한 줄입니다.

sed -i 's/막한/막힌/' title-to-url.html && node shot.mjs

그리고 그림이 텍스트 파일이니 git에 그대로 들어갑니다. 커밋 기록에 뭐가 바뀌었는지 글자로 남습니다. 이미지 파일은 “바뀜”이라고만 나오죠.

겪은 것 다섯 가지

여기부터가 실제로 시간을 쓴 부분입니다.

도식을 HTML로 만들면서 겪은 함정 다섯 가지. 글꼴이 늦게 와서 다른 글꼴로 찍히는 것, 캔버스를 넘으면 조용히 잘리는 것, flex 안에서 굵은 글씨가 제 줄로 떨어지는 것, 인코딩을 브라우저 추측에 맡겼을 때, 그리고 특정 한글 글자가 굵은 무게에서 겹쳐 보이는 것.

1. 글꼴이 늦게 오면 다른 글꼴로 찍힙니다

웹폰트를 CDN에서 받아 쓰는데, 폰트가 도착하기 전에 스크린샷을 찍으면 대체 글꼴로 찍혀버립니다. 화면에서는 멀쩡해 보이는데 PNG만 이상합니다.

await p.evaluate(() => document.fonts.ready);
await p.waitForTimeout(1400);

fonts.ready만으로는 가변 폰트가 실제로 그려지기 전에 넘어갈 때가 있어서 여유를 좀 더 뒀습니다. 1.4초는 감으로 정한 값입니다.

2. 캔버스를 넘으면 조용히 잘립니다

내용을 추가하다 보면 640px를 넘어갑니다. 그런데 스크린샷은 정해진 크기로 찍히니까 넘친 부분이 그냥 없어집니다. 경고도 없습니다.

그래서 찍을 때마다 잽니다.

const o = await p.evaluate(() => ({
  h: document.body.scrollHeight,
  w: document.body.scrollWidth,
}));
const over = o.h > 640 || o.w > 1600;
console.log(name, o, over ? '⚠ 넘침' : 'ok');

이 두 줄이 없었으면 잘린 그림을 몇 번은 올렸을 겁니다. 실제로 이번 글 도식도 처음 찍었을 때 744px이 나왔습니다.

3. flex 안에서는 굵은 글씨가 줄을 바꿉니다

표 칸을 세로 가운데 정렬하려고 이렇게 했습니다.

.td {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

그랬더니 칸 안의 내부 링크를 <b>최종 주소로</b> 적기가 세 줄로 쪼개졌습니다. flex 컨테이너 안에서는 텍스트 조각과 <b>가 각각 별개 항목이 되어 세로로 쌓입니다.

<span>으로 한 번 감싸면 됩니다.

<div class="td">
  <span>내부 링크를 <b>최종 주소로</b> 적기</span>
</div>

한 번 알고 나면 별것 아닌데, 모르면 “왜 여기만 줄이 바뀌지” 하면서 한참 봅니다.

4. 인코딩을 브라우저 추측에 맡기지 않습니다

한 번은 PNG에서 한글이 깨져 나왔습니다. <meta charset="utf-8" />을 안 적었더군요. 추가하니 사라졌습니다.

그런데 이 글을 쓰면서 다시 재현해보려니 안 깨졌습니다. 브라우저가 내용을 보고 인코딩을 알아서 맞춘 겁니다.

바로 이게 무서운 부분입니다. 대체로 맞으니까 평소엔 모르고, 추측이 빗나가는 날에만 깨집니다. 한 줄 적어두면 추측할 일이 없어집니다.

5. 어떤 한글은 굵게 하면 겹쳐 보입니다

도식 아래 설명에 “여러 번 실행돼도 괜찮게”라고 굵게 썼는데, ‘찮’의 받침이 겹쳐 보였습니다. 본문 굵기에서는 멀쩡한데 800 무게에서만 그랬습니다.

글꼴 문제라 제가 고칠 수 있는 게 아니어서 문구를 바꿨습니다. “문제없게”로요. 뜻이 같으면 이게 제일 빠릅니다.

찍고 나서 눈으로 한 번 보는 과정이 필요한 이유이기도 합니다. 수치로는 안 걸립니다.

이 방식이 못 하는 것

솔직하게 적어두겠습니다.

자유롭게 그리는 건 못 합니다. 곡선 화살표, 손그림 느낌, 일러스트 같은 건 CSS로 하려면 고생스럽습니다. 제 도식이 죄다 네모와 표인 건 취향이기도 하지만 이 방식이 잘하는 게 그거라서이기도 합니다.

그림 속 글자는 검색도 복사도 안 됩니다. PNG니까요. 독자가 도식의 코드 조각을 복사하고 싶어도 못 합니다.

그래서 도식에 들어간 내용은 본문에도 글로 한 번 더 적습니다. 그림만 보면 알 수 있는데 글에는 없는 정보가 생기지 않게요.

그리고 대체 텍스트를 길게 씁니다. 이 블로그의 글머리에는 대표 이미지 설명 칸이 따로 있습니다.

heroImageAlt: 도식을 만드는 과정.
  그림마다 HTML 파일 하나를 쓰고
  공통 base.css 를 불러와 ...

화면 낭독기를 쓰는 분과 검색엔진이 읽는 자리입니다. 도식이 정보를 담고 있으면 그 정보를 글로도 풀어놔야 합니다. 장식용 그림이면 비워두는 게 맞고요.

정리

도구를 새로 배우지 않아도 되는 쪽을 골랐습니다. CSS는 어차피 쓰던 거고, 그리기 도구는 새로 익혀야 합니다. 잘 만들어진 도구들이 많지만, 저는 일주일에 두 장씩 그리는 사람이라 익히는 시간이 안 빠집니다.

고치는 비용이 낮으면 더 많이 고칩니다. 오타 하나 고치자고 편집기를 열어야 하면 그냥 둡니다. sed 한 줄이면 고칩니다. 도구가 결과물의 완성도를 정하는 지점이 여기라고 생각합니다.

눈으로 보는 단계는 못 없앱니다. 넘침은 숫자로 잡히지만 글자가 겹쳐 보이는 건 안 잡힙니다. 자동화해도 마지막엔 사람이 한 번 봐야 합니다.

참고한 문서


댓글

로그인도 이메일도 필요 없습니다. 이름만 적고 편하게 남겨주세요.