1. 試行錯誤の記録
TokiQRのplay.htmlにPC向け印刷機能を実装した。A4横のレイアウトに、QRコードとメタデータを配置し、二ページ目にはブローシャを収めた。PCのブラウザで「印刷」を押せば、そのまま美しいシートが出力される。声を閉じ込めたQRコードが、物理的な紙の上に降り立つ瞬間だ。
当然のように思った。同じ体験をiPhone Safariでも提供しよう、と。
そこから始まった試行錯誤は、30を超えるプルリクエストに刻まれている。QRコードの表示サイズを150mmから115mmへ、さらに108mmへ。@pageのマージンを何度も書き換えた。100vhを固定mmに置き換え、ネガティブマージンで微調整し、iframeでの描画を試し、PNG画像への変換を試し、Service Workerのキャッシュが邪魔をする問題と格闘した。
一つ直せば別の場所が崩れる。97%のビューポートで収まるが、100%ではみ出る。その3%の隙間に、デスクトップとモバイルの間に横たわる深い溝が見えた。
3%の余白に潜む溝は、技術的な問題ではなかった。
設計思想の断層だった。
iOS Safariは@page { size }を無視する。column-count: 2はiframe内で機能しない。window.print()にはユーザージェスチャーの制約がある。一つひとつは些細な制限に見える。だがそれらが重なったとき、「モバイルでの印刷」という体験は、砂上の楼閣になった。
2. 境界の発見
ブラウザの印刷APIは、デスクトップを前提に設計されている。
これは非難ではない。歴史的な事実だ。印刷という行為は、大きな画面で文書を確認し、接続されたプリンターに出力するという、物理的な作業環境を想定して設計された。モバイルブラウザがその機能を「サポートしている」のは事実だが、サポートしていることと、信頼できる体験を提供することの間には、埋めがたい距離がある。
モバイルで「ほぼ動く」は、「動かない」と同義だ。
98%のケースで正しく表示されるレイアウトは、残り2%で崩れる。QRコードが紙の端で切れる。二段組みが一段に戻る。余白が消えて文字が詰まる。ユーザーはその2%に遭遇したとき、「たまたま崩れた」とは思わない。「このサービスは壊れている」と思う。
98%で崩れるレイアウトは、ユーザーの信頼を100%損なう。
技術者にとっての98%は「ほぼ完成」だ。だがユーザーにとっての98%は「壊れている」だ。この認知の非対称性に気づいたとき、問題の本質が見えた。これは実装の問題ではない。そもそもモバイルブラウザで本番品質の印刷を提供するという前提が、現時点では成り立たないのだ。
3. ブラウザ依存の断層
モバイルの印刷ボタンを消した。これで解決したはずだった。
だがPC Safariが、新たな断層を突きつけてきた。macOS上のChromeでは2ページに収まる印刷レイアウトが、同じmacOS上のSafariでは4ページに散る。コンテンツが次のページにはみ出し、空白のページが挿入される。
原因を探った。Safariの印刷エンジンは、overflow: hiddenを無視する。Flexコンテナに設定したheight制約も無視する。break-inside: avoidも機能しない。CSSで「ここからはみ出すな」と指示しても、印刷エンジンがその指示を尊重しない。
さらに10以上のPRを重ねた。高さを180mmから178mmへ、マージンを10mmから13mmへ。ルーラー要素でmm→px変換を試み、beforeprintイベントでtransform: scale()による強制縮小まで実装した。CSSだけでは無理だから、JavaScriptで力技で押し込もうとした。
すべて無駄だった。同じHTMLを、同じCSSで描画しているのに、結果が異なる。機種の違いではない。OSの違いでもない。同じマシンの上で、レンダリングエンジンが異なるだけで、印刷結果が変わる。画面表示では差異のないCSSプロパティが、印刷時にはまったく異なる挙動を示す。
これはバグではない。WebKitとBlinkの、印刷エンジンにおける設計思想の違いだ。仕様書に書かれていないグレーゾーンを、それぞれのエンジンが異なる方法で解釈している。
機種を揃えても、OSを揃えても、ブラウザが異なればレイアウトは崩れる。
ブラウザ依存は、機種依存より深い断層だ。
4. 失うという決断
二度、捨てた。
最初にモバイルの印刷を捨てた。次にSafariの印刷を捨てた。印刷機能が動作する環境は、macOSのChromeだけになった。30以上のPRで積み重ねた試行錯誤の結果として「Chromeでしか動きません」と認めることは、技術者としての矜持に触れる。もう少し工夫すれば、もう少し時間をかければ、きっと解決できる。そう思いたかった。
だが「もう少し」の先にあるのは、脆い体験の上に築かれた機能だ。今日直しても、次のSafariアップデートで崩れるかもしれない。その不安を抱えながら機能を提供し続けることは、誠実ではない。
失ったもの
Safari、Firefox、モバイル——Chrome以外のすべての環境で印刷する導線を失った。iPhoneで録音し、QRコードを生成し、その場で印刷するという一気通貫のワークフローは消えた。
得たもの
- 壊れた体験を届けないという品質保証——ユーザーが「印刷」を押して期待を裏切られることはない
- 注文ボタンへの明確な誘導——印刷の代わりに、プロが仕上げた高品質なQRシールを注文する導線が前面に出る
- Chrome印刷の品質に集中できる余地——クロスブラウザ対応に費やしていたリソースを、一つのブラウザの完成度に向けられる
「ご自身で印刷する場合はPC(macOS)のChromeをご利用ください」——この一文を添えた。機能を削除したのではない。機能を配置し直したのだ。Chromeで「だけ」ではなく、「Chromeが最善」であるという案内。それは制限ではなく、最適化だ。
捨てたのは機能ではない。
「すべてのブラウザで同じ体験を」という、実現不可能な約束を捨てた。
5. もう一つの断層——コスト構造
機種依存とブラウザ依存を掘り下げるうちに、三つ目の断層が見えてきた。組織のコスト構造だ。
大規模なプロジェクトには、中間コストが構造的に発生する。デザインとエンジニアリングを別組織が担当する場合の調整コスト。複数ベンダーが関わる場合のハンドオフコスト。意思決定の承認チェーンを通過させるための合意形成コスト。これらは組織の欠陥ではなく、規模に伴う構造的な現実だ。
PoCで「できること」を証明し、引き継ぎ文書を書き、次のフェーズを別チームが担当する。なぜその技術選定をしたのか、どこに落とし穴があったのか——こうした文脈は、フェーズの境界で薄れていく。結果として、同じ検証が繰り返され、その分のコストがプロダクトの価格に積み上がる。
機種依存がハードウェアの構造的制約であるように、
組織の中間コストはスケールの構造的制約だ。
6. 中間コストの不在がもたらすもの
TokiQRの30以上のPRは、すべて一人の開発者が、一つのリポジトリで、連続した文脈の中で積み重ねた。PoCの報告書を書いて別チームに引き継ぐ必要はない。ベンダー間の責任分界を調整する会議もない。「97%で収まるが100%ではみ出る」という知見は、コミットログに直接残り、次の判断に直接反映される。
この構造には、中間コストが存在しない。
ベンダー調整がないから、意思決定から実装までが直線になる。知識のハンドオフがないから、30以上のPRで蓄積された知見が散逸しない。承認チェーンがないから、「Safariの印刷を捨てる」という判断を、検証した当日に実行できる。
記録されなかった知識は、存在しなかったのと同じになる。
だが個人開発では、すべての試行錯誤が一本の線としてつながっている。
中間コストの不在は、二つのものを可能にする。一つは、蓄積された知識に基づく品質。もう一つは、合理的な価格設定だ。組織的なオーバーヘッドが価格に転嫁されないから、高品質なQRシールを合理的な価格で提供できる。
7. 確実に届く体験のために
「声と記憶を1000年先に届ける」——トキストレージのこの約束を支えるのは、技術だけではない。コスト構造そのものが、サービスの設計に組み込まれている。
物理的なQRシールは、注文を通じて高品質に提供できる。UV印刷とラミネート加工を施した、耐候性のあるシール。それは家庭用プリンターの出力とは次元の異なる品質だ。そしてその品質を合理的な価格で届けられるのは、中間コストの不在という構造的な理由がある。
1000年先に届けることを約束するサービスが、手元の端末で崩れる印刷を提供していたら、その約束は信じてもらえるだろうか。機種依存やブラウザ依存という現実を受け入れ、プロの品質で届けるほうが、サービスの本質に近い。
検証された仮説——物理化の難易度
30以上のPRを経て見えたのは、技術的な限界だけではない。「デジタルデータを物理的な成果物にする」という行為そのものの難易度が、期待以上に高いという事実だ。
端末を選び、ブラウザを指定し、用紙の向きを設定し、余白を調整し、ヘッダとフッタをオフにする。技術者ですら安定しなかった体験を、一般のユーザーに求めることは現実的ではない。これは30以上のPRで検証された、実証的な知見だ。
この知見は、注文サービスの存在意義を裏付ける。「印刷できないから注文してください」ではない。「物理化は本質的に難しいから、プロに委ねるのが合理的です」という説明が、技術的な根拠をもって成立する。自力での物理化が難しいからこそ、プロの品質に価値がある。
「自分でもできるけど注文したほうがいい」よりも、
「自分でやると実は難しい、だから注文がある」のほうが、
注文動機として自然で、誠実だ。
8. 構造的な強み
この文章で描いた三つの断層——機種依存、ブラウザ依存、組織のコスト構造——は、いずれも構造的な制約だ。技術革新やリソース投入では容易に解消しない。
逆に言えば、中間コストの不在という構造もまた、容易には模倣されない。大規模な組織が同じ品質のQRシールを同じ価格で提供しようとしても、調整コスト・ハンドオフコスト・合意形成コストが構造的に上乗せされる。規模の経済でカバーできる領域もあるが、少量多品種の「一人ひとりの声を物理化する」というサービスでは、規模の経済が効きにくい。
これは一時的な技術的優位ではない。コスト構造に根ざした、持続的な競争優位だ。
万能を目指すことは、何も守らないことに等しい。
境界を認めることが、品質の始まりだ。
30以上のPRを経てChromeだけに絞ったあの日、技術的には何も解決していない。Safariのoverflow: hidden無視は変わらない。height制約の無視も残っている。変わったのは、設計者としての視座だ。
捨てる決断、境界を引く決断。それは「できません」という敗北宣言ではない。「ここに境界がある」という発見の記録だ。そしてその記録を残すこと自体が、同じ場所で立ち止まる次の誰かへの、静かな贈り物になる。
機種依存はハードウェアの境界を教えてくれた。ブラウザ依存はソフトウェアの境界を教えてくれた。そして組織のコスト構造は、中間コストの不在がもたらす合理的な価格という、サービス設計の起点を教えてくれた。
失う決断の先に、守るべきものが見える。
機種依存も、ブラウザ依存も、コスト構造も、制約ではない。設計の起点だ。