HTML+CSSで宛名印刷
あけましておめでとうございます。
近頃のCSSは writing-mode: vertical-rl
で縦書きができます。皆さんご存知の通り mm での位置指定は余裕ですし、 page-break-after
で改ページもできます。宛名印刷できますね。
というわけで今年の年賀状の宛名面のメイキングです。
なお下のQiita記事に触発され、土台部分を参考にしています。
レイアウト
基本となるCSSはこれだけです。ほとんど前掲のQiita記事の通りですが、調整した点はコメントに記載しました。
/* UAデフォルトのマージンを除去 */ html, body { margin: 0; padding: 0; } @page { /* はがきサイズ。手元の環境では用紙サイズの自動選択は働かなかった。 */ size: 100mm 148mm; margin: 0; } @media screen { body { background: #eee; } .page { background: white; box-shadow: 0 .5mm 2mm rgba(0,0,0,.3); margin: 5mm; /* 一覧しやすいようにfloatさせる */ float: left; } } .page { width: 100mm; height: 147mm; page-break-after: always; /* ページ上の配置を position: absolute で行うため */ position: relative; }
あとは好きなものを、好きな位置に、好きなフォントで配置するだけ。
といっても何の参考もなしにやるのはつらいので、はがきの画像をスキャンなりしてページの背景にしておくと位置調整の参考になります。また、他のソフトでだいたいのレイアウトを決めてから、その画像や数値を使うのも手です。
その他メモ。
- bottomで位置指定 + min-height + text-align: left/center で「普段は下に伸びるけど足りなければ上の余白も使う」的なレイアウト。
- 縦中横は
text-combine
というCSSプロパティもあるが、愚直に一行分の幅に詰め込んでしまうのでつらい。実際にはちょっとはみ出すぐらいにしたかったので、結局display: inline-block
を使った。 line-height
、複数行のとこはどうせいじるので、一行の要素向けにデフォルト 1 でよさそう。
JavaScriptで流し込む
CSSでのレイアウトが終わったものの、住所録をCSVから取り込んだりすることを考えると、
- 郵便番号の前半と後半を分けたい、とか
- 住所の数値は別のスタイルを適用したいからタグで囲みたい、とか
- 宛名を均等割り付けしたい、とか
- そもそもテンプレートに流し込みたい、とか
色々と課題が残っています。せっかくHTMLなのですからJavaScriptで解決しましょう。
今回はあらかじめどうにかして*1 <page name="山田太郎" postal="1030027" addr1="東京都中央区..."></page>
みたいな形に変形しておいて、そこから先をRiotでやることにしました。
タグ定義はJadeで書きました。
format-addr script. let text = opts.text; text = text.replace(/-/g, 'の'); let wrap_numbers = content => { let elem = document.createElement("span"); elem.className = "numbers"; elem.textContent = content; return elem; }; let re = /(\w+)|([^\w]+)/g; for (let m; m = re.exec(text);){ if(m[1]) this.root.appendChild(wrap_numbers(m[1])); else this.root.appendChild(document.createTextNode(m[2]));} page section.page div.to-postal | {opts.postal.substr(0,3)} span.right: {opts.postal.substr(3,4)} div.to-addr format-addr(text='{opts.addr1}') div.rest: format-addr(text='{opts.addr2 || ""}') div.to-name | {opts.name} 様 script. // justify this.on('updated', function() { var range = document.createRange(); for (var elem of document.querySelectorAll('.to-name')) { range.selectNodeContents(elem); elem.style.letterSpacing = 0; elem.style.letterSpacing = (elem.clientHeight - range.getBoundingClientRect().height) / elem.innerText.length; }; });
先ほどの課題については次のように解決しています。
- 郵便番号の前半と後半を分ける→
String.prototype.substr()
- 住所の数値をタグで囲む→
this.root
上に構築する別のカスタムタグを作成 - 宛名を均等割り付け→ Rangeオブジェクトで取得した文字列の描画領域とボックスの高さを元に
letter-spacing
を調整
あとは body 内に上記で定義したpageタグを並べるだけ。