Overview
A paper notebook-style HTML data report. Warm paper background + handwriting fonts + sketch borders + notebook binding holes + red margin line. Suitable for scenarios such as competitive analysis, data comparison, strategy summaries, etc.
Design Tokens
Colors
:root {
--paper: #fdf6e3; /* 纸张底色 */
--ink: #2c2c2c; /* 主文字 */
--ink-light: #666; /* 辅助文字 */
--blue: #3b6ea5; /* 品牌A / 数据色1 */
--green: #4a8c6f; /* 品牌B / 数据色2 */
--red: #c0392b; /* 强调 / 警告 / 手写批注 */
--orange: #e67e22; /* 洞察高亮边框 */
--highlight: #fff3b0; /* 荧光笔高亮背景 */
--grid: #e8dcc8; /* 分隔线 / 外层背景 */
}
- Outer body background:
#e8dcc8(kraft paper color) - Page card background:
var(--paper)(#fdf6e3) - For dual-brand comparison: blue = Brand A, green = Brand B
- Handwritten annotations always use
var(--red)
Typography
@import url('https://fonts.googleapis.com/css2?family=Caveat:wght@400;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap');
| Purpose | Font | Font Size | Font Weight |
|---|---|---|---|
| Main Title h1 | Caveat | 38px | 700 |
| Section Title h2 | Caveat | 28px | 600 |
| Large Data Text | Caveat | 42px | 700 |
| Handwritten Annotation | Caveat | 16-18px | 400 |
| Body Text | Noto Sans SC | 13-14px | 400 |
| Auxiliary/Label | Noto Sans SC | 11-12px | 500 |
Notebook Texture
.page {
max-width: 960px;
margin: 0 auto;
background: var(--paper);
padding: 60px 56px;
border-radius: 4px;
box-shadow: 2px 3px 8px rgba(0,0,0,0.12), inset 0 0 60px rgba(0,0,0,0.03);
position: relative;
/* 装订孔 — 5个圆点沿左边 */
background-image:
radial-gradient(circle at 32px 80px, #ccc 6px, transparent 6px),
radial-gradient(circle at 32px 280px, #ccc 6px, transparent 6px),
radial-gradient(circle at 32px 480px, #ccc 6px, transparent 6px),
radial-gradient(circle at 32px 680px, #ccc 6px, transparent 6px),
radial-gradient(circle at 32px 880px, #ccc 6px, transparent 6px);
background-repeat: no-repeat;
}
/* 红色页边线 */
.page::before {
content: '';
position: absolute;
left: 72px; top: 0; bottom: 0;
width: 2px;
background: rgba(220, 80, 80, 0.3);
}
.content { margin-left: 24px; }
Sketchy Effects
All visual elements have a slight rotation and hand-drawn feel:
/* 素描阴影卡片 */
.card {
border: 2px solid var(--ink);
border-radius: 6px;
background: white;
box-shadow: 3px 3px 0 var(--ink);
transform: rotate(-0.3deg); /* 每张卡片不同角度 */
}
/* 手写批注 */
.annotation {
font-family: 'Caveat', cursive;
color: var(--red);
font-size: 18px;
transform: rotate(-2deg);
display: inline-block;
}
/* 赢家标签 */
.winner {
display: inline-block;
background: var(--red);
color: white;
font-family: 'Caveat', cursive;
font-size: 14px;
padding: 1px 8px;
border-radius: 8px;
transform: rotate(-3deg);
}
/* 日期/标签贴纸 */
.date-tag {
display: inline-block;
background: var(--highlight);
padding: 2px 10px;
border-radius: 2px;
font-size: 13px;
transform: rotate(1deg);
}
/* 箭头批注 */
.arrow-note {
font-family: 'Caveat', cursive;
color: var(--red);
font-size: 16px;
}
.arrow-note::before { content: '\2191 '; } /* ↑ */
Component Library
1. Summary Cards (Total Comparison)
Two side-by-side cards with a corner badge:
<div class="cards"> <!-- display:flex; gap:20px -->
<div class="card">
<div class="card-badge">Brand A</div>
<div class="card-label">指标名称</div>
<div class="card-value blue">2,466 件</div>
<div class="card-sub">补充说明</div>
<span class="annotation">批注!</span>
</div>
<div class="card">
<div class="card-badge green-bg">Brand B</div>
<div class="card-value green">1,388 件</div>
</div>
</div>
2. Split Bar (Comparison Bar)
<div class="metric-row"> <!-- flex, white bg, rounded -->
<div class="metric-name">销量</div>
<div class="metric-val blue">2,466</div>
<div class="split-bar"> <!-- flex, rounded, overflow hidden -->
<div class="left" style="width: 64%"></div> <!-- blue -->
<div class="right" style="width: 36%"></div> <!-- green -->
</div>
<div class="metric-val green">1,388</div>
<span class="winner">A 赢</span>
</div>
3. Horizontal Bar Chart
<div class="chart-section"> <!-- white bg, light border -->
<div class="chart-legend">
<div class="legend-item"><div class="legend-dot blue"></div> Brand A</div>
<div class="legend-item"><div class="legend-dot green"></div> Brand B</div>
</div>
<div class="bar-row">
<div class="bar-label">产品名</div> <!-- 120px, right-aligned -->
<div class="bar-track"> <!-- flex:1 -->
<div class="bar blue" style="width: 92%">
<span class="bar-val">892</span> <!-- absolute, right outside -->
</div>
</div>
</div>
</div>
Bar width is calculated as a percentage of the maximum value. bar-val is absolutely positioned outside the right side of the bar.
4. Detail Table
<div class="detail-table"> <!-- full width, sketchy border -->
<div class="table-header blue-bg">Brand A · N品</div>
<table>
<thead><tr><th>产品</th><th>售价</th><th>销量</th><th>销售额</th></tr></thead>
<tbody>
<tr><td>产品名</td><td><span class="price-tag">$147</span></td><td><strong>892</strong></td><td>$11.38万</td></tr>
<tr class="total"><td>合计</td><td>—</td><td>2,466</td><td>$38.35万</td></tr>
</tbody>
</table>
</div>
5. Insight Box
<!-- 黄色高亮版 — 核心发现 -->
<div class="insight-box"> <!-- highlight bg, orange left border -->
<h3>核心看点</h3>
<p><strong>红色强调</strong>,普通文字,<em>白底高亮</em></p>
</div>
<!-- 白色版 — 策略建议 -->
<div class="insight-box" style="background: white; border-left-color: var(--blue);">
<p><strong>1. 标题</strong><br>解释内容</p>
</div>
6. Section Headers
<h2>默认蓝色边</h2>
<h2 class="green">绿色边</h2>
<h2 class="red">红色边</h2>
<h2 class="orange">橙色边</h2>
Left border 4px solid, Caveat font, slight rotation of -0.3deg.
Report Structure
Standard report structure:
1. 标题 + 副标题 + 日期标签
2. 总量对比 — Summary Cards + Split Bars
3. 分项对比 — Bar Charts (销量 + 销售额)
4. 产品明细 — Detail Tables (含价格/日期/佣金)
5. 核心看点 — Insight Box (黄色高亮)
6. 策略启示 — Insight Box (白色)
7. 页脚
PNG Export
Use Playwright to capture the .page element, at 2x resolution:
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page(viewport={'width': 1100, 'height': 900}, device_scale_factor=2)
page.goto(f'file://{html_path}')
page.wait_for_timeout(3000) # 等待字体加载
element = page.query_selector('.page')
element.screenshot(path=png_path)
browser.close()
Key Principles
- Every element must be tilted — cards rotate(-0.3deg), annotations rotate(-2deg), labels rotate(1deg), each angle different
- Handwritten text uses only Caveat — titles, large data text, annotations, and labels all use Caveat; body text uses Noto Sans SC
- Sketch shadow = 2px border + 3px 3px 0 solid shadow — no blur, to keep the hand-drawn feel
- Annotations use red — all annotation / arrow-note / winner use --red
- Highlights use fluorescent yellow — --highlight (#fff3b0) is used for stickers, insight-box, price-tag
- Dashed separators — use dashed rather than solid (more handmade feel)
- HTML must be self-contained — inline CSS + Google Fonts CDN, no dependency on external files