designpaca/packages/skill/references/print-email.md
Yun Chan 6805fb2be7 feat(skill): absorb external design skills, restore interview gate, add review route
- Restore the step-0 interview as a mechanical gate the skill explicitly
  depends on; add harness.md (per-harness question tools, limits,
  fallbacks) and brief-interview.md (slots, question cards, rounds).
- Add 10 reference docs absorbed from external design skills
  (accessibility, interaction-feel, elevation, color, icons, product-copy,
  component-systems, critique, change-review, print-email) and extend
  existing references.
- Add a review-only route and two hard-gate clauses (truncated content
  reachability, three-flashes limit).
- design-gate: split tap targets into WCAG 2.5.8 and 44px contract layers,
  run axe-core when available, and fix false positives found on a real
  site (decorative alt="", stacked wordmark line count, url-only pages).
- lint-skill: fail if the interview gate section or its links disappear.
- Ship agents/openai.yaml and THIRD_PARTY_NOTICES.md.
2026-09-24 13:26:03 +09:00

14 KiB

print-email — 인쇄와 이메일

브리프가 인쇄 가능한 문서(출력·PDF 저장·서명용 서류)나 이메일(뉴스레터·트랜잭션 메일·초대장)을 명시할 때만 연다. 둘 중 하나만 필요하면 해당 절만 읽는다.

이 문서는 SKILL.md 4-5(서류로서의 완성)의 인쇄 규칙을 일반화한다. 4-5는 프리셋이 서류·원장·콘솔 계열(장부, 시간표, 관리 화면)일 때만 도는 좁은 규칙이고, 여기서는 그 밖의 어떤 화면이든 브리프가 인쇄를 요구하면 적용할 수 있게 넓힌다. 4-5의 규칙(모달이 열려 있으면 그 서류만, print-color-adjust: exact)과 모순되지 않으며, 겹치는 부분은 새로 쓰지 않고 그대로 가져와 쓴다.

이 문서를 읽는 법

상황 읽을 곳
페이지를 인쇄·PDF 저장 가능하게 만든다 §1 인쇄
인쇄 결과가 맞는지 확인한다 §2 인쇄 검증
뉴스레터·트랜잭션 메일·초대장을 만든다 §3 이메일
이메일 클라이언트에서 실제로 확인한다 §4 이메일 검증
출시 전 한 번에 훑는다 §5 체크리스트

0. 언제 여는가

  • 브리프에 "인쇄", "PDF로 저장", "출력해서 제출", "서명 후 인쇄" 같은 말이 있으면 §1·§2.
  • 브리프에 "뉴스레터", "이메일로 보낸다", "가입 확인 메일", "영수증 메일", "초대 메일" 같은 말이 있으면 §3·§4.
  • 둘 다 아니면 이 문서는 읽지 않는다. 모든 웹 페이지를 기본적으로 인쇄·이메일 대응시키지 않는다 — 그것은 이 문서가 조건부로 존재하는 이유 자체를 없앤다.

1. 인쇄

언제: 브리프가 인쇄 가능한 문서를 요구할 때. 프리셋이 서류·원장·콘솔이면 SKILL.md 4-5를 먼저 따르고, 이 절은 그 규칙이 없는 일반 페이지(랜딩, 포트폴리오, 안내문 등)에 인쇄 대응을 추가할 때 쓴다.

1-1. @media print 뼈대

프로젝트 계약: 인쇄가 요구되면 @media print 블록으로 화면과 서류를 분리한다. 화면에서 필요한 앱 크롬(내비, 툴바, 플로팅 버튼, 사이드바)은 인쇄에서 의미가 없다 — 사용자는 종이 위에서 그것을 누를 수 없다.

@media print {
  header.app-nav,
  [role="toolbar"],
  .floating-action,
  .cookie-banner,
  button:not(.print-keep) {
    display: none !important;
  }
}

프로젝트 계약: 모달이 열린 채로 인쇄가 시작되면 배경의 앱 화면이 아니라 그 모달 내용만 서류가 되어야 한다. SKILL.md 4-5의 기존 규칙을 그대로 쓴다.

@media print {
  body:has(dialog[open]) > *:not(:has(dialog[open])) {
    display: none !important;
  }
}

관찰 후보(시작값): @page의 여백은 브라우저 기본값에서 시작한다. 제본이나 클립이 필요한 서류만 여백을 늘린다. 정확히 몇 cm가 맞는지는 프로젝트마다 다르므로 숫자를 단정하지 않고, 실제 출력물로 확인한다(§2).

@page {
  margin: 2cm 1.5cm; /* 제본 쪽에 더 필요하면 margin-left 만 늘린다 — 실측 조정 */
}

1-2. 콘텐츠를 서류에 맞게 바꾼다

프로젝트 계약: 카드·표 행·영수증 구획처럼 한 덩어리로 읽혀야 하는 블록은 페이지 경계에서 잘리지 않게 한다.

@media print {
  .card,
  tr,
  .receipt-line,
  figure {
    break-inside: avoid;
  }
  h2, h3 {
    break-after: avoid; /* 제목만 페이지 끝에 남고 본문이 다음 장으로 넘어가는 것을 막는다 */
  }
}

프로젝트 계약: 상태색처럼 의미를 나르는 색(경고·성공·실패 배지 등)만 print-color-adjust: exact로 보존한다. 나머지는 브라우저의 기본 인쇄 설정(그레이스케일·절약 모드 포함)에 맡긴다. 전체를 강제 컬러로 찍으면 사용자의 잉크 절약 설정을 무시하게 된다.

@media print {
  .status-badge,
  .status-dot {
    print-color-adjust: exact;
    -webkit-print-color-adjust: exact;
  }
}

하드 게이트: 화면에서 잘라 보여주던 것(짧은 링크 텍스트, 접힌 섹션)은 종이 위에서 클릭이나 hover로 나머지에 닿을 수 없다. typography.md §13의 "잘린 텍스트 — 전체 값에 도달하는 수단" 원칙과 같은 이유로, 인쇄에서는 그 값 자체를 펼쳐 보여줘야 정보 손실이 없다.

@media print {
  a[href^="http"]:not([href*="#"])::after {
    content: " (" attr(href) ")";
    word-break: break-all;
  }
}

닫힌 <details>의 내용은 브라우저가 내부 슬롯으로 숨기므로, 자식 요소에 display를 주는 CSS로는 확실히 펼쳐지지 않는다. 인쇄 직전에 open을 켜고 끝나면 되돌린다.

let reopened = [];
addEventListener('beforeprint', () => {
  reopened = [...document.querySelectorAll('details:not([open])')];
  reopened.forEach((d) => { d.open = true; });
});
addEventListener('afterprint', () => {
  reopened.forEach((d) => { d.open = false; });
  reopened = [];
});

1-3. 서류의 신원 — 머리말·바닥말·출력일

관찰 후보: 여러 장으로 인쇄될 문서(보고서, 명세서)는 페이지 번호와 문서 제목을 각 장에 남긴다. 독자가 순서를 잃어버리지 않게 하는 목적이므로, 한 장짜리 인쇄물(영수증, 초대장)에는 강제하지 않는다.

@media print {
  @page {
    @bottom-right { content: counter(page) " / " counter(pages); }
  }
  .print-footer::after {
    content: "출력일 " attr(data-print-date);
  }
}

@page 안의 여백 상자(@bottom-right 등)는 브라우저 지원이 고르지 않으므로 점진적 향상으로 둔다 — 지원하지 않는 브라우저에서는 페이지 번호가 빠질 뿐이다. 페이지 번호가 계약상 반드시 필요하면 인쇄 미리보기에서 대상 브라우저로 확인하고, 안 되면 PDF 생성 도구 쪽에서 넣는다. attr(data-print-date)는 CSS만으로 오늘 날짜를 넣을 수 없으므로, 인쇄 전에 JS로 document.querySelector('.print-footer').dataset.printDate = new Date().toLocaleDateString('ko-KR') 같은 식으로 채워 둔다.


2. 인쇄 검증

인쇄는 화면 렌더링과 다른 엔진 경로를 타기 때문에, 화면에서 괜찮아 보인다고 인쇄도 괜찮다고 결론 내리지 않는다.

  1. 인쇄 미리보기를 캡처한다. 브라우저의 인쇄 미리보기(Ctrl/Cmd+P)를 열어 각 페이지를 실제로 넘겨 본다. 브라우저 자동화 도구가 있으면 인쇄 미디어를 에뮬레이트해 스크린샷으로 남긴다 — 쓸 수 있는 도구는 harness.md를 따른다.
  2. PDF로 저장해 연다. "PDF로 저장"으로 실제 파일을 만들고 별도 뷰어로 열어, 브라우저 미리보기와 최종 PDF가 다르게 나오는 경우(특히 폰트·배경색)가 없는지 확인한다.
  3. 경계에서 확인할 것: 카드·표·영수증 구획이 페이지 경계에서 잘리지 않는지, 앱 크롬이 실제로 사라졌는지, 모달만 인쇄될 상황에서 배경 화면이 섞여 나오지 않는지, 링크 URL과 펼친 details가 실제로 종이에 보이는지, 상태색이 흑백 인쇄에서도 배지 모양(테두리·아이콘)만으로 구분되는지(색만으로 구분되면 흑백에서 정보가 사라진다).
  4. 확인하지 못했으면 "미검증"이라고 적는다. 소스만 보고 통과로 추정하지 않는다 — audit-gate.md의 미검증 관례를 그대로 따른다.

3. 이메일

언제: 브리프가 뉴스레터, 트랜잭션 메일(가입 확인·영수증·비밀번호 재설정), 초대장처럼 이메일 클라이언트 안에서 열리는 HTML을 명시할 때. 웹사이트에 "문의하기 → 메일 발송" 버튼이 있는 정도는 해당하지 않는다.

이메일 클라이언트는 웹 브라우저가 아니다. 관찰 후보 — 이 문서에서 실측하지 않았다. 일부 클라이언트는 데스크톱 문서 편집기의 렌더링 경로를 그대로 쓰거나, 외부 스타일시트·최신 레이아웃 CSS를 지원하지 않거나 부분적으로만 지원한다는 관찰이 있다. 정확히 어떤 클라이언트가 무엇을 지원하는지는 이 문서에서 확인하지 않았으므로 클라이언트별 지원 수치를 단정하지 않는다. 아래는 그런 제약을 가정했을 때 안전한 기본값이며, 실제 확인은 §4를 따른다.

3-1. 레이아웃

프로젝트 계약: 폭은 600px 안팎의 단일 컬럼을 기본값으로 한다. 화면이 넓어도 이메일 본문 폭을 늘리지 않는다 — 클라이언트의 미리보기 창, 모바일 메일 앱 폭이 그보다 좁은 경우가 흔하다[SKILL-IMPECCABLE].

프로젝트 계약: 레이아웃은 표(<table>) 기반으로 짜고, 스타일은 <style> 블록이 아니라 각 태그의 style 속성에 인라인으로 넣는다. display: flex나 grid 같은 최신 레이아웃 CSS, 외부 스타일시트 링크는 이메일에서 기대한 대로 렌더링되지 않을 수 있다는 것이 근거다[SKILL-IMPECCABLE].

<table role="presentation" width="600" cellpadding="0" cellspacing="0" style="margin:0 auto; max-width:600px;">
  <tr>
    <td style="padding:24px; font-family:Arial, sans-serif; font-size:16px; line-height:1.5; color:#1a1a1a;">
      본문 내용
    </td>
  </tr>
</table>

3-2. 인터랙션

프로젝트 계약: 행동 유도는 텍스트 링크가 아니라 버튼처럼 보이는 요소로 만든다. 배경색을 채운 <a>를 표 셀 안에 넣는 방식이 흔한 구현이다[SKILL-IMPECCABLE](<button> 태그 자체는 이메일 클라이언트에서 일관되게 렌더링되지 않는 경우가 있어 피한다 — 관찰 후보, 이 문서에서 실측하지 않았다).

<a href="https://example.com/confirm"
   style="display:inline-block; padding:12px 24px; background:#1a56db; color:#ffffff;
          text-decoration:none; border-radius:6px; font-weight:600;">
  가입 확인하기
</a>

하드 게이트: 대부분의 이메일 클라이언트는 hover 상태 자체가 없다(모바일 메일 앱, 미리보기 창). 핵심 동작(다음 단계로 가는 CTA, 정보 확인)이 hover에만 반응하도록 만들면 애초에 작동하지 않는다. 추가 정보나 보조 동작이 hover에 의존해서도 안 된다 — 항상 보이는 상태로 둔다[SKILL-IMPECCABLE].

프로젝트 계약: 폼 제출, 다단계 흐름, 필터처럼 복잡한 상호작용은 이메일 안에서 구현하지 않는다. 버튼으로 웹의 해당 화면에 딥링크한다[SKILL-IMPECCABLE].

3-3. 이미지가 막혀도, 어두운 테마에서도 읽힌다

프로젝트 계약: 많은 이메일 클라이언트가 기본적으로 이미지를 차단한 채 미리보기를 띄운다. 로고·CTA·핵심 문구를 이미지에만 담으면 이미지가 막힌 순간 그 내용이 통째로 사라진다. 핵심 텍스트(제목, 본문, 버튼 라벨)는 실제 HTML 텍스트로 쓰고, 이미지에는 내용을 설명하는 alt를 붙이며, 이미지가 있어야 할 자리에는 배경색을 지정해 이미지가 빠져도 빈 흰 칸이 아니라 브랜드 색 영역으로 보이게 한다.

<img src="logo.png" alt="회사 로고" width="120"
     style="display:block; background-color:#f3f4f6;">

관찰 후보: 일부 클라이언트는 사용자가 어두운 테마를 켰을 때 메일 배경·글자색을 자동으로 반전하거나 재조정한다. 이 동작은 클라이언트마다 다르고 이 문서에서 실측하지 않았으므로 어떤 클라이언트가 어떻게 반전하는지는 단정하지 않는다. 실무적으로 안전한 방향은 배경색을 투명에 맡기지 않고 컨테이너마다 명시적으로 지정하는 것, 로고처럼 투명 배경을 가정한 자산을 흰 배경 전용으로 만들지 않는 것이다. 실제 확인은 §4를 따른다.


4. 이메일 검증

브라우저 렌더링과 실제 이메일 클라이언트 렌더링은 별개다. 로컬 브라우저에서 HTML 파일을 열어 봤다고 이메일에서도 같다고 보고하지 않는다.

  1. 실제 클라이언트로 확인한 경우만 "검증됨"으로 보고한다. 예를 들어 실제 계정으로 지메일·아웃룩·애플 메일 등에 발송해 열어 보고, 폭·표 레이아웃·버튼·이미지 차단 상태·어두운 테마에서 각각 확인한다.
  2. 확인하지 못했으면 "미검증"이라고 명시한다. 코드가 규칙(§3)을 따랐다는 것과 실제 클라이언트에서 그대로 보인다는 것은 다른 주장이다. "표 레이아웃과 인라인 CSS를 썼으니 호환될 것이다"는 추정이지 검증이 아니다.
  3. 클라이언트별 지원 수치·점유율을 지어내지 않는다. 이 스킬은 "아웃룩이 몇 퍼센트를 지원한다" 같은 구체 수치를 확인하지 않았다. 필요하면 사용자에게 발송 대상 클라이언트 범위를 물어 §3의 어떤 항목을 더 엄격하게 지킬지 좁힌다.

5. 체크리스트

인쇄

  • @media print로 앱 크롬(내비·툴바·플로팅 버튼)을 숨겼다
  • 모달이 열린 채 인쇄되면 그 모달만 서류가 된다
  • 카드·표 행이 페이지 경계에서 잘리지 않는다(break-inside: avoid)
  • 상태색은 print-color-adjust: exact로 보존하되, 색만으로 상태를 구분하지 않는다(흑백에서도 구분 가능)
  • 짧은 링크 텍스트가 전체 URL로 펼쳐진다
  • 접힌 섹션(details 등)이 인쇄에서는 펼쳐진다
  • 여러 장 문서면 페이지 번호·문서 제목이 있다
  • 인쇄 미리보기와 PDF 출력을 실제로 열어 확인했다(§2). 못 했으면 미검증이라고 적었다

이메일

  • 폭 600px 안팎, 단일 컬럼
  • 표 기반 레이아웃, 인라인 CSS
  • CTA가 버튼처럼 보이는 요소다(텍스트 링크가 아니다)
  • 핵심 동작·정보가 hover에 의존하지 않는다
  • 복잡한 상호작용은 웹으로 딥링크했다
  • 이미지가 막혀도 핵심 텍스트가 읽히고, alt와 배경색을 지정했다
  • 컨테이너 배경색을 명시해 다크모드 반전에 대비했다
  • 실제 클라이언트에서 확인했다(§4). 못 했으면 미검증이라고 적었다