見出し画像

たった17音の川柳を美しく見せたくて。noteを「縦書き」に変えるツール作りました。

※本記事にはプロモーションが含まれます

noteで縦書きを試す——まず動かしてみる

テキストを貼るだけで縦書きになる、ブラウザツールを配布します。

たった17音の言葉を、どうしても縦書きで残したかった

先日、妻とよく出かけた思い出の街・堺市の「堺SDGs川柳2025」というコンテストに応募し、佳作に入選しました。

$$
\begin{array}{c c c}
\text{ } & \text{ } & \text{鍵} \cr
\text{ } & \text{ } & \text{穴} \cr
\text{ } & \text{気} & \text{を} \cr
\text{ } & \text{球} & \text{ } \cr
\text{未} & \text{で} & \text{ } \cr
\text{来} & \text{覗} & \text{ } \cr
\text{都} & \text{く} & \text{ } \cr
\text{市} & \text{ } & \text{ } \cr
\end{array}
$$

『鍵穴を 気球で覗く 未来都市』

堺の歴史と未来への想像を、17音にギュッと詰め込んだ思い入れのある一句です。受賞の喜びをnoteで報告しようと、エディタに打ち込みました。しかし、ここで手が止まりました。

横書きで表示された自分の川柳が、ひどく味気なく見えたのです。

横書きでは、単なる「短いインフォメーション」のように視線が素早く通り過ぎてしまいます。川柳や短歌が持つ、言葉と言葉の間の「余白」、そして読者に立ち止まって想像させる「重み」が、横書きのフォーマットによって奪われているように感じました。

「自分の作品を、本来の美しい姿(縦書き)で読んでもらいたい」

noteの標準機能にないのなら、自分で作るしかない。そう思い立ち、テキストをそのまま縦書きで表示できるツールを開発しました。

【サンプル例】

$$
\begin{array}{c c c c c c c c c c}
\text{彼} & \text{ } & \text{﹁} & \text{ } & \text{1} & \text{窓} & \text{ } & \text{﹁} & \text{ } & \text{彼} \cr
\text{女} & \text{ } & \text{も} & \text{ } & \text{9} & \text{の} & \text{ } & \text{少} & \text{ } & \text{女} \cr
\text{の} & \text{ } & \text{う} & \text{ } & \text{9} & \text{外} & \text{ } & \text{し} & \text{ } & \text{は} \cr
\text{声} & \text{ } & \text{一} & \text{ } & \text{9} & \text{で} & \text{ } & \text{冷} & \text{ } & \text{コ} \cr
\text{は} & \text{ } & \text{度} & \text{ } & \text{年} & \text{は} & \text{ } & \text{め} & \text{ } & \text{︱} \cr
\text{ど} & \text{ } & \text{だ} & \text{ } & \text{の} & \text{︑} & \text{ } & \text{て} & \text{ } & \text{ヒ} \cr
\text{こ} & \text{ } & \text{け} & \text{ } & \text{春} & \text{秋} & \text{ } & \text{し} & \text{ } & \text{︱} \cr
\text{か} & \text{ } & \text{︑} & \text{ } & \text{︑} & \text{の} & \text{ } & \text{ま} & \text{ } & \text{カ} \cr
\text{遠} & \text{ } & \text{や} & \text{ } & \text{2} & \text{風} & \text{ } & \text{い} & \text{ } & \text{ッ} \cr
\text{く} & \text{ } & \text{っ} & \text{ } & \text{5} & \text{が} & \text{ } & \text{ま} & \text{ } & \text{プ} \cr
\text{に} & \text{ } & \text{て} & \text{ } & \text{歳} & \text{木} & \text{ } & \text{し} & \text{ } & \text{を} \cr
\text{聞} & \text{ } & \text{み} & \text{ } & \text{の} & \text{々} & \text{ } & \text{た} & \text{ } & \text{持} \cr
\text{こ} & \text{ } & \text{よ} & \text{ } & \text{彼} & \text{を} & \text{ } & \text{が} & \text{ } & \text{ち} \cr
\text{え} & \text{ } & \text{う} & \text{ } & \text{女} & \text{揺} & \text{ } & \text{︙} & \text{ } & \text{上} \cr
\text{た} & \text{ } & \text{!} & \text{ } & \text{は} & \text{ら} & \text{ } & \text{︙} & \text{ } & \text{げ} \cr
\text{︒} & \text{ } & \text{﹂} & \text{ } & \text{夢} & \text{し} & \text{ } & \text{﹂} & \text{ } & \text{た} \cr
\text{ } & \text{ } & \text{ } & \text{ } & \text{を} & \text{て} & \text{ } & \text{ } & \text{ } & \text{︒} \cr
\text{ } & \text{ } & \text{ } & \text{ } & \text{追} & \text{い} & \text{ } & \text{ } & \text{ } & \text{ } \cr
\text{ } & \text{ } & \text{ } & \text{ } & \text{い} & \text{る} & \text{ } & \text{ } & \text{ } & \text{ } \cr
\text{ } & \text{ } & \text{ } & \text{ } & \text{か} & \text{︒} & \text{ } & \text{ } & \text{ } & \text{ } \cr
\text{ } & \text{ } & \text{ } & \text{ } & \text{け} & \text{ } & \text{ } & \text{ } & \text{ } & \text{ } \cr
\text{ } & \text{ } & \text{ } & \text{ } & \text{て} & \text{ } & \text{ } & \text{ } & \text{ } & \text{ } \cr
\text{ } & \text{ } & \text{ } & \text{ } & \text{い} & \text{ } & \text{ } & \text{ } & \text{ } & \text{ } \cr
\text{ } & \text{ } & \text{ } & \text{ } & \text{た} & \text{ } & \text{ } & \text{ } & \text{ } & \text{ } \cr
\text{ } & \text{ } & \text{ } & \text{ } & \text{︒} & \text{ } & \text{ } & \text{ } & \text{ } & \text{ } \cr
\end{array}
$$

今回は、私と同じように「どうしても縦書きで伝えたい言葉」を持つ方へ向けて、ブラウザで動くLite版ツールを配布します

目次

そもそも、なぜ縦書きをnoteで使うのか

横書きで書いた文章を、縦書きにするだけで印象が変わる場面があります。

詩の一節。手紙の書き出し。広告コピーの一行。こうした文章は、縦書きにした瞬間に「読み流せない重さ」を持ちます。読者の目の動きが変わり、文章の前でわずかに立ち止まる時間が生まれます。

【サンプル例】

$$
\begin{array}{c c c}
\text{成} & \text{探} & \text{や} \cr
\text{長} & \text{す} & \text{ら} \cr
\text{は} & \text{の} & \text{な} \cr
\text{止} & \text{が} & \text{い} \cr
\text{ま} & \text{う} & \text{理} \cr
\text{る} & \text{ま} & \text{由} \cr
\text{︒} & \text{く} & \text{を} \cr
\text{ } & \text{な} & \text{ } \cr
\text{ } & \text{る} & \text{ } \cr
\text{ } & \text{と} & \text{ } \cr
\text{ } & \text{︑} & \text{ } \cr
\end{array}
$$

 出展:GLIP/リクルートキャリア/ポスター/2014年

$$
\begin{array}{c c}
\text{幸} & \text{引} \cr
\text{せ} & \text{っ} \cr
\text{だ} & \text{越} \cr
\text{っ} & \text{し} \cr
\text{た} & \text{が} \cr
\text{証} & \text{少} \cr
\text{拠} & \text{し} \cr
\text{で} & \text{さ} \cr
\text{す} & \text{び} \cr
\text{︒} & \text{し} \cr
\text{ } & \text{い} \cr
\text{ } & \text{の} \cr
\text{ } & \text{は} \cr
\text{ } & \text{︑} \cr
\end{array}
$$

出展:ハウスメイト/雑誌/2009/小林麻衣子

$$
\begin{array}{c c}
\text{一} & \text{別} \cr
\text{生} & \text{れ} \cr
\text{弱} & \text{が} \cr
\text{く} & \text{人} \cr
\text{て} & \text{を} \cr
\text{い} & \text{強} \cr
\text{い} & \text{く} \cr
\text{と} & \text{す} \cr
\text{思} & \text{る} \cr
\text{っ} & \text{な} \cr
\text{た} & \text{ら} \cr
\text{︒} & \text{︑} \cr
\end{array}
$$

出展: 西日本典礼/ポスター/2012/西村麻里

$$
\begin{array}{c c c c}
\text{座} & \text{一} & \text{ど} & \text{入} \cr
\text{っ} & \text{生} & \text{こ} & \text{学} \cr
\text{て} & \text{の} & \text{か} & \text{式} \cr
\text{い} & \text{友} & \text{に} & \text{︒} \cr
\text{る} & \text{達} & \text{︑} & \text{ } \cr
\text{︒} & \text{が} & \text{ } & \text{ } \cr
\end{array}
$$

出展: 立教大学/ポスター/2014/前野岳允

noteという媒体は、文芸・クリエイター・思索系のコンテンツを好む読者が多い場所です。縦書きという形式そのものが、そうした読者への無言のメッセージになります。「この文章は、ゆっくり読んでほしい」という意思表示です。

とはいえ、noteの標準エディタには縦書き機能がありません。では、どうするか。

noteで縦書きを実現する方法は3つある

現時点で縦書きをnoteに載せる方法は、大きく3つに分かれます。

方法①:画像として貼り付ける

WordやPagesなど縦書き対応のアプリで文章を作り、スクリーンショットや画像(PNG・JPG)として書き出してnoteに貼る方法です。

レイアウトが崩れないという意味では最も確実です。ただし、画像の中の文字は検索エンジンに認識されません。読者がテキストをコピーすることもできません。「見た目は縦書き、中身は画像」という状態になります。

方法②:縦書き変換ツールで変換してコピー&ペーストする

Web上の縦書き変換ツールでテキストを変換し、全角スペースや改行で位置を調整してからnoteに貼り付ける方法です。

テキスト情報は残りますが、環境によって表示が崩れやすいという問題があります。自分のPCでは問題なく見えても、スマートフォンや別のブラウザで崩れることが多く、微調整に時間がかかります。

方法③:専用ツールで変換してnoteの専用ブロックに貼り付ける

ツールの操作画面

本記事で配布する方法です。ツールでテキストを変換し、生成されたコードをnoteの特定のブロックに貼り付けます。

テキスト情報を維持しながら、環境による崩れが起きにくい形式で縦書きを実現できます。操作はシンプルで、テキストを入力してコピーボタンを押すだけです。

専用ツールで変換してnoteに貼り付けた結果

3つの方法、どれを選ぶか

絶対にレイアウトを崩したくない場合、または文字数が少なく一点もののビジュアルを作りたい場合は、画像方式が確実です。

テキスト情報を残したい場合、定期的に縦書きコンテンツを作成する予定がある場合は、方法③が実務上の選択肢になります。本記事ではこの方法のツールを配布します。

使い方——3ステップで完了

ステップ1:テキストを入力する

ツールを開くと、左側に入力欄があります。縦書きにしたいテキストをそのまま入力するか、貼り付けます。入力と同時に右側のプレビューが自動更新されます。

「小説」ボタンを押すとサンプルテキストがセットされます。まず試してみたい場合はこちらから動かしてみてください。

入力と同時にプレビューが自動更新される(サンプルもボタンからリアルタイム反映)

ステップ2:コードをコピーする

プレビューが意図通りであれば、「note用コードをコピー」ボタンを押します。ボタンが緑色に変わり「✓ コピーしました」と表示されれば成功です。

ステップ3:noteに貼り付ける

noteのエディタを開き、縦書きを挿入したい位置にカーソルを置きます。

コピーしたコードを貼り付けます。

貼り付け直後はエディタ上で記号や文字が羅列して見えます。これは正常な状態です。noteの「プレビュー」ボタンを押すと、縦書きとして表示されることが確認できます。

貼り付け後、プレビューで縦書きが確認できる

こんな用途に向いている

このLite版ツールが特に有効なコンテンツの類型を挙げます。

詩・俳句・短歌: 短い文章ほど縦書きの効果が際立ちます。行数が少ないため、プレビューで意図通りの見た目を確認しやすいです。

手紙形式の文章: 書き出しの「拝啓」から結びの「敬具」まで、縦書きにすることで手紙らしい雰囲気が出ます。

小説の冒頭: 記事の導入部として縦書きの一節を置くことで、横書き本文との対比が生まれます。

キャッチコピー・見出し: 短いコピー一行を縦書きにするだけで、視覚的なアクセントになります。

【サンプル例】

$$
\begin{array}{c c c}
\text{耐} & \text{長} & \text{見} \cr
\text{え} & \text{い} & \text{事} \cr
\text{て} & \text{冬} & \text{な} \cr
\text{き} & \text{の} & \text{サ} \cr
\text{た} & \text{時} & \text{ク} \cr
\text{こ} & \text{間} & \text{ラ} \cr
\text{と} & \text{︑} & \text{で} \cr
\text{を} & \text{ } & \text{あ} \cr
\text{思} & \text{ } & \text{れ} \cr
\text{う} & \text{ } & \text{ば} \cr
\text{の} & \text{ } & \text{あ} \cr
\text{で} & \text{ } & \text{る} \cr
\text{し} & \text{ } & \text{ほ} \cr
\text{た} & \text{ } & \text{ど} \cr
\text{︒} & \text{ } & \text{︑} \cr
\end{array}
$$

出展: 3月27日 そうだ京都、行こう。/東海旅客鉄道 ポスター 2009年

逆に向いていない用途もあります。記事の本文全体を縦書きにしたい場合、数値・単位・引用符を正確に処理したい場合は、後述するフルバージョンの方が適しています。

使用上の注意点

率直に書きます。

note実環境での確認が必須です。 ツール上のプレビューと、実際にnoteに貼り付けた結果が微妙に異なる場合があります。特にスマートフォンでの表示は、PC表示と細部が異なることがあります。公開前に必ずnoteのプレビュー機能で確認し、スマートフォンからも表示を確認してください。

テキスト量には実用上の上限があります。 一度に変換するテキスト量が増えるほど処理が重くなります。実用上は一度に300〜500字程度に抑えることを推奨します。長い文章を縦書きにしたい場合は、段落単位で分割して変換・貼り付けを繰り返す方が安定します。

noteの仕様変更の影響を受けます。 このツールはnoteの特定のブロック機能に依存しています。note側が将来この機能を変更・廃止した場合、表示されなくなる可能性があります。重要な文章は元のテキストを必ず別途保存しておいてください。

継続的なメンテナンスは保証していません。 状況に応じた対応になります。この点を承知の上でご使用ください。

もっと細かく制御したい場合

Lite版を使っていると、こんな不満が出てくることがあります。

「"こんにちは" の引用符が変な向きになる」「cm や kg がアルファベットのまま縦に並ぶ」「1,000円 の表示が崩れる」「段落の頭を1字下げたい」「1999年 を 一九九九年 にしたい」

これらはLite版が意図的にシンプルに絞っているためです。引用符の縦書き変換、単位の組み文字化、数字の最適化、段落一字下げ、漢数字変換(逐字・位取り)の6つの変換オプションを搭載したフルバージョンを別記事で紹介しています。

フルバージョンの記事では、ツールの仕組みの説明、動作要件の詳細、HTMLファイルとして保存してブラウザで使う初心者向けの導入手順も含めて解説しています。

フルバージョンの記事はこちら(今後投稿予定です)

HTMLファイルの使い方——初めての方へ

以下に配布するのはHTMLファイルのコードです。難しくありません。テキストをファイルとして保存するだけです。

手順の概要:

  1. 以下のコードをすべてコピーする

  2. メモ帳(Windows)またはテキストエディット(Mac)を開く

  3. コードを貼り付ける

  4. ファイル名を 縦書きジェネレーター.html として保存する(拡張子 .html が重要)

  5. 保存したファイルをダブルクリックするとブラウザで開く

保存時の注意点(Windowsのメモ帳の場合):

「名前を付けて保存」ダイアログで「ファイルの種類」を「すべてのファイル」に変更し、文字コードを「UTF-8」に設定してから保存してください。この2点を変更しないと .html.txt という名前になり、ブラウザで正しく開けません。

ファイルの種類を「すべてのファイル」に変更する

保存時の注意点(Macのテキストエディットの場合):

テキストエディットを起動後、メニューの「フォーマット」→「標準テキストにする」を必ず選択してからコードを貼り付けてください。この操作をしないと、リッチテキスト形式で保存されHTMLとして機能しません。保存時のファイル名は 縦書きジェネレーター.html と入力します。

保存後、ファイルのアイコンがブラウザのマークになっていれば成功です。.html.txt になっている場合は、末尾の .txt を削除してください。

アイコンがブラウザのマークなら保存成功

ブラウザで開いた後の確認:

アドレスバーに file:/// で始まるアドレスが表示されていれば正常です。初回起動時に小説サンプルが自動表示されます。これはツールが正常に動作しているという確認のためのデモです。

ツールが表示されない場合は、インターネットに接続されているか(起動時に外部ライブラリを読み込むため必要)、ファイルの拡張子が .html になっているか、ブラウザがChrome・Firefox・Safari・Edgeのいずれかであるかの3点を確認してください。

ブラウザで開くと初期サンプルが自動表示される

表示例1

$$
\begin{array}{c c c c c c c c c c}
\text{ } & \text{ } & \text{﹁} & \text{ } & \text{一} & \text{ } & \text{ } & \text{﹁} & \text{ } & \text{ } \cr
\text{彼} & \text{ } & \text{も} & \text{ } & \text{九} & \text{窓} & \text{ } & \text{少} & \text{ } & \text{彼} \cr
\text{女} & \text{ } & \text{う} & \text{ } & \text{九} & \text{の} & \text{ } & \text{し} & \text{ } & \text{女} \cr
\text{の} & \text{ } & \text{一} & \text{ } & \text{九} & \text{外} & \text{ } & \text{冷} & \text{ } & \text{は} \cr
\text{声} & \text{ } & \text{度} & \text{ } & \text{年} & \text{で} & \text{ } & \text{め} & \text{ } & \text{コ} \cr
\text{は} & \text{ } & \text{だ} & \text{ } & \text{の} & \text{は} & \text{ } & \text{て} & \text{ } & \text{︱} \cr
\text{ど} & \text{ } & \text{け} & \text{ } & \text{春} & \text{︑} & \text{ } & \text{し} & \text{ } & \text{ヒ} \cr
\text{こ} & \text{ } & \text{︑} & \text{ } & \text{︑} & \text{秋} & \text{ } & \text{ま} & \text{ } & \text{︱} \cr
\text{か} & \text{ } & \text{や} & \text{ } & \text{二} & \text{の} & \text{ } & \text{い} & \text{ } & \text{カ} \cr
\text{遠} & \text{ } & \text{っ} & \text{ } & \text{十} & \text{風} & \text{ } & \text{ま} & \text{ } & \text{ッ} \cr
\text{く} & \text{ } & \text{て} & \text{ } & \text{五} & \text{が} & \text{ } & \text{し} & \text{ } & \text{プ} \cr
\text{に} & \text{ } & \text{み} & \text{ } & \text{歳} & \text{木} & \text{ } & \text{た} & \text{ } & \text{を} \cr
\text{聞} & \text{ } & \text{よ} & \text{ } & \text{の} & \text{々} & \text{ } & \text{が} & \text{ } & \text{持} \cr
\text{こ} & \text{ } & \text{う} & \text{ } & \text{彼} & \text{を} & \text{ } & \text{︙} & \text{ } & \text{ち} \cr
\text{え} & \text{ } & \text{!} & \text{ } & \text{女} & \text{揺} & \text{ } & \text{︙} & \text{ } & \text{上} \cr
\text{た} & \text{ } & \text{﹂} & \text{ } & \text{は} & \text{ら} & \text{ } & \text{﹂} & \text{ } & \text{げ} \cr
\text{︒} & \text{ } & \text{ } & \text{ } & \text{夢} & \text{し} & \text{ } & \text{ } & \text{ } & \text{た} \cr
\text{ } & \text{ } & \text{ } & \text{ } & \text{を} & \text{て} & \text{ } & \text{ } & \text{ } & \text{︒} \cr
\text{ } & \text{ } & \text{ } & \text{ } & \text{追} & \text{い} & \text{ } & \text{ } & \text{ } & \text{ } \cr
\text{ } & \text{ } & \text{ } & \text{ } & \text{い} & \text{る} & \text{ } & \text{ } & \text{ } & \text{ } \cr
\text{ } & \text{ } & \text{ } & \text{ } & \text{か} & \text{︒} & \text{ } & \text{ } & \text{ } & \text{ } \cr
\text{ } & \text{ } & \text{ } & \text{ } & \text{け} & \text{ } & \text{ } & \text{ } & \text{ } & \text{ } \cr
\text{ } & \text{ } & \text{ } & \text{ } & \text{て} & \text{ } & \text{ } & \text{ } & \text{ } & \text{ } \cr
\text{ } & \text{ } & \text{ } & \text{ } & \text{い} & \text{ } & \text{ } & \text{ } & \text{ } & \text{ } \cr
\text{ } & \text{ } & \text{ } & \text{ } & \text{た} & \text{ } & \text{ } & \text{ } & \text{ } & \text{ } \cr
\text{ } & \text{ } & \text{ } & \text{ } & \text{︒} & \text{ } & \text{ } & \text{ } & \text{ } & \text{ } \cr
\end{array}
$$

noteプレビューで縦書きの最終確認をする

表示例2(フルバージョン)

$$
\begin{array}{c c c c c c c}
\text{通} & \text{総} & \text{ } & \text{ } & \text{前} & \text{二} & \text{ } \cr
\text{信} & \text{務} & \text{一} & \text{ } & \text{年} & \text{十} & \text{二} \cr
\text{距} & \text{省} & \text{方} & \text{ } & \text{比} & \text{八} & \text{〇} \cr
\text{離} & \text{の} & \text{︑} & \text{ } & \text{百} & \text{㎓} & \text{二} \cr
\text{は} & \text{調} & \text{端} & \text{ } & \text{二} & \text{帯} & \text{五} \cr
\text{最} & \text{査} & \text{末} & \text{ } & \text{十} & \text{の} & \text{年} \cr
\text{大} & \text{に} & \text{の} & \text{ } & \text{%} & \text{五} & \text{の} \cr
\text{二} & \text{よ} & \text{平} & \text{ } & \text{増} & \text{G} & \text{国} \cr
\text{㎞} & \text{る} & \text{均} & \text{ } & \text{の} & \text{基} & \text{内} \cr
\text{ま} & \text{と} & \text{価} & \text{ } & \text{約} & \text{地} & \text{通} \cr
\text{で} & \text{︑} & \text{格} & \text{ } & \text{八} & \text{局} & \text{信} \cr
\text{安} & \text{月} & \text{は} & \text{ } & \text{千} & \text{が} & \text{市} \cr
\text{定} & \text{額} & \text{九} & \text{ } & \text{五} & \text{全} & \text{場} \cr
\text{し} & \text{料} & \text{万} & \text{ } & \text{百} & \text{国} & \text{は} \cr
\text{た} & \text{金} & \text{八} & \text{ } & \text{万} & \text{に} & \text{大} \cr
\text{接} & \text{の} & \text{千} & \text{ } & \text{人} & \text{展} & \text{き} \cr
\text{続} & \text{平} & \text{五} & \text{ } & \text{に} & \text{開} & \text{な} \cr
\text{が} & \text{均} & \text{百} & \text{ } & \text{達} & \text{さ} & \text{転} \cr
\text{可} & \text{は} & \text{円} & \text{ } & \text{し} & \text{れ} & \text{換} \cr
\text{能} & \text{四} & \text{と} & \text{ } & \text{た} & \text{︑} & \text{期} \cr
\text{だ} & \text{千} & \text{高} & \text{ } & \text{︒} & \text{利} & \text{を} \cr
\text{︒} & \text{二} & \text{止} & \text{ } & \text{ } & \text{用} & \text{迎} \cr
\text{ } & \text{百} & \text{ま} & \text{ } & \text{ } & \text{者} & \text{え} \cr
\text{ } & \text{八} & \text{り} & \text{ } & \text{ } & \text{数} & \text{た} \cr
\text{ } & \text{十} & \text{し} & \text{ } & \text{ } & \text{は} & \text{︒} \cr
\text{ } & \text{円} & \text{て} & \text{ } & \text{ } & \text{ } & \text{ } \cr
\text{ } & \text{︒} & \text{い} & \text{ } & \text{ } & \text{ } & \text{ } \cr
\text{ } & \text{ } & \text{る} & \text{ } & \text{ } & \text{ } & \text{ } \cr
\text{ } & \text{ } & \text{︒} & \text{ } & \text{ } & \text{ } & \text{ } \cr
\end{array}
$$

ツールのコード

以下のコードをコピーし、上記の手順でHTMLファイルとして保存してください。

インターネット接続が必要です(起動時に外部ライブラリを読み込みます)。入力したテキストは外部に送信されず、すべて手元のブラウザ内で処理されます。

使ってみた感想や、うまく動かない場合はコメント欄に書いていただければ対応します。

より細かい変換制御が必要になった場合は、今後投稿するフルバージョンの記事をご覧ください。

お願い

【コードのコピーと、唯一の「使用条件」】
このツールは無料で配布しますが、今後のアップデートや新たな開発を続けるために「この記事に『スキ♡』を押すこと」を唯一の使用条件とさせてください。
これは、どれくらいの方に必要とされているかを「計測」するための指標であり、私にとって次作を生み出すための「モチベーション(燃料)」になります。
システムで縛ることはしませんが、この紳士協定にご合意いただける方のみ、以下のコードをコピーしてご活用ください!

※スキはnoteに登録していなくても押せます
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>note用 縦書きジェネレーター Lite</title>
    <link rel="stylesheet" href="/https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.css">
    <script defer src="/https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.js"></script>
    <style>
        :root { --g: #2cb696; --bg: #f4f5f6; --tx: #333; --bd: #dcdcdc; }
        * { box-sizing: border-box; }
        body {
            font-family: -apple-system, BlinkMacSystemFont, sans-serif;
            background: var(--bg); color: var(--tx);
            max-width: 1040px; margin: 0 auto; padding: 30px 20px;
        }
        h1 { font-size: 1.8rem; margin: 0 0 8px; color: #111; }
        .subtitle { font-size: 0.9rem; color: #666; margin-bottom: 20px; }
        .sample-bar { display: flex; align-items: center; gap: 8px; margin-bottom: 20px; flex-wrap: wrap; }
        .sample-bar > span { font-size: 0.85rem; color: #888; font-weight: bold; white-space: nowrap; }
        .btn-smp {
            font-size: 0.8rem; padding: 5px 14px;
            border: 1px solid var(--g); border-radius: 20px;
            background: #fff; color: var(--g); cursor: pointer; transition: 0.2s;
        }
        .btn-smp:hover { background: var(--g); color: #fff; }
        .btn-smp.active { background: var(--g); color: #fff; font-weight: bold; }
        .btn-smp:focus-visible { outline: 2px solid var(--g); outline-offset: 2px; }
        .btn-clr { border-color: #bbb; color: #999; }
        .btn-clr:hover, .btn-clr.active { background: #bbb; color: #fff; }
        .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; align-items: stretch; }
        @media (max-width: 768px) { .grid { grid-template-columns: 1fr; } }
        .left-col { display: flex; flex-direction: column; gap: 12px; }
        .card {
            background: #fff; border-radius: 12px;
            border: 1px solid var(--bd);
            box-shadow: 0 2px 8px rgba(0,0,0,0.04);
        }
        .input-card {
            padding: 20px;
            display: flex; flex-direction: column; flex: 1;
            position: relative;
        }
        .card-label {
            font-size: 0.72rem; font-weight: 700; letter-spacing: 0.08em;
            text-transform: uppercase; color: var(--g);
            margin-bottom: 10px; flex-shrink: 0;
        }
        textarea {
            width: 100%; flex: 1; min-height: 200px;
            padding: 12px 12px 28px;
            border: 1px solid var(--bd); border-radius: 8px;
            font-size: 14.5px; resize: vertical; background: #fafafa;
            line-height: 1.7; transition: border 0.2s; font-family: inherit;
        }
        textarea:focus { outline: none; border-color: var(--g); background: #fff; }
        .input-meta {
            font-size: 0.72rem; color: #bbb;
            position: absolute; bottom: 30px; right: 28px;
            pointer-events: none; user-select: none;
        }
        .right-col { position: sticky; top: 16px; display: flex; flex-direction: column; gap: 12px; }
        @media (max-width: 768px) { .right-col { position: static; } }
        .preview-card {
            display: flex; flex-direction: column;
            min-height: 400px; max-height: 65vh;
            padding: 0; overflow: hidden;
        }
        .preview-header {
            padding: 14px 20px 10px;
            border-bottom: 1px solid #f0f0f0;
            flex-shrink: 0;
            display: flex; align-items: center; justify-content: space-between;
        }
        .preview-hint { font-size: 0.72rem; color: #bbb; }
        .preview-scroll {
            flex: 1; overflow: auto;
            scrollbar-gutter: stable;
            padding: 24px 20px 20px;
            display: flex; justify-content: center; align-items: flex-start;
            scrollbar-width: thin;
            scrollbar-color: #ddd transparent;
        }
        .preview-scroll::-webkit-scrollbar { width: 4px; }
        .preview-scroll::-webkit-scrollbar-track { background: transparent; }
        .preview-scroll::-webkit-scrollbar-thumb { background: #ddd; border-radius: 2px; }
        #preview-content { max-width: 100%; }
        .btn-copy {
            width: 100%; background: var(--g); color: #fff;
            border: none; padding: 15px 12px; font-size: 1rem;
            border-radius: 12px; cursor: pointer; font-weight: bold;
            box-shadow: 0 4px 12px rgba(44,182,150,0.25); transition: background 0.2s, transform 0.2s, box-shadow 0.2s;
        }
        .btn-copy:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(44,182,150,0.35); }
        .btn-copy:active:not(:disabled) { transform: translateY(0); box-shadow: 0 2px 6px rgba(44,182,150,0.2); }
        .btn-copy:disabled { background: #e0e0e0; color: #aaa; box-shadow: none; cursor: not-allowed; }
        .btn-copy.copied { background: #1a8c6e; }
        .toast {
            position: fixed; bottom: -60px; left: 50%; transform: translateX(-50%);
            background: #222; color: #fff; padding: 12px 28px; border-radius: 30px;
            font-weight: bold; font-size: 0.95rem;
            transition: bottom 0.4s cubic-bezier(0.175,0.885,0.32,1.275);
            z-index: 1000; box-shadow: 0 4px 15px rgba(0,0,0,0.2); white-space: nowrap;
        }
        .toast.show { bottom: 30px; }
    </style>
</head>
<body>

    <h1>note用 縦書きジェネレーター Lite</h1>
    <p class="subtitle">テキストを入力すると、noteに貼り付けられる縦書きコードを生成します。</p>

    <div class="sample-bar" role="group" aria-label="サンプルテキスト">
        <span>プリセット:</span>
        <button class="btn-smp" id="smpBtn0" data-sample="0">小説</button>
        <button class="btn-smp btn-clr" id="smpBtnClr" data-action="clear">クリア</button>
    </div>

    <div class="grid">
        <div class="left-col">
            <div class="card input-card">
                <div class="card-label" id="inputLabel">横書きテキストを入力</div>
                <textarea id="inputText" aria-labelledby="inputLabel" placeholder="ここに文章を入力してください"></textarea>
                <output class="input-meta" id="char-count" for="inputText">0文字</output>
            </div>
        </div>

        <div class="right-col">
            <div class="card preview-card">
                <div class="preview-header">
                    <div class="card-label" style="margin-bottom:0;">縦書きプレビュー</div>
                    <span class="preview-hint">入力と同時に自動更新</span>
                </div>
                <div class="preview-scroll">
                    <div id="preview-content" role="status" aria-live="polite">
                        <span style="color:#ccc; font-size:0.85rem; line-height:2.5; text-align:center; display:block;">
                            テキストを入力すると<br>縦書きプレビューが表示されます
                        </span>
                    </div>
                </div>
            </div>

            <button id="copyBtn" class="btn-copy" disabled>note用コードをコピー</button>
        </div>
    </div>

    <div id="toast" class="toast" role="status" aria-live="polite">コードをコピーしました — note の $$ ブロックに貼り付けてください</div>

    <script>
        const SAMPLES = [
            '彼女はコーヒーカップを持ち上げた。\n\n「少し冷めてしまいましたが……」\n\n窓の外では、秋の風が木々を揺らしている。\n1999年の春、25歳の彼女は夢を追いかけていた。\n\n「もう一度だけ、やってみよう!」\n\n彼女の声はどこか遠くに聞こえた。'
        ];

        const charMap = {
            'ー': '︱', '-': '︱', '—': '︱', '−': '︱', '―': '︱',
            '…': '︙', '‥': '︰',
            '。': '︒', '、': '︑',
            '「': '﹁', '」': '﹂', '『': '﹃', '』': '﹄',
            '(': '︵', ')': '︶', '{': '︷', '}': '︸', '[': '﹇', ']': '﹈',
            '【': '︻', '】': '︼', '〈': '︿', '〉': '﹀',
            '《': '︽', '》': '︾', '〔': '︹', '〕': '︺', '〖': '︗', '〗': '︘',
            '\u201C': '〝', '\u201D': '〟', '\u2018': '〝', '\u2019': '〟'
        };

        const EMPTY_PLACEHOLDER = '<span style="color:#ccc;font-size:0.85rem;line-height:2.5;text-align:center;display:block;">テキストを入力すると<br>縦書きプレビューが表示されます</span>';

        const DOM = {
            in:    document.getElementById('inputText'),
            prev:  document.getElementById('preview-content'),
            btn:   document.getElementById('copyBtn'),
            cnt:   document.getElementById('char-count'),
            toast: document.getElementById('toast'),
            smpBtns: ['smpBtn0', 'smpBtnClr'].map(id => document.getElementById(id))
        };

        const segmenter = typeof Intl.Segmenter === 'function'
            ? new Intl.Segmenter('ja', { granularity: 'grapheme' })
            : null;

        function segmentText(str) {
            if (segmenter) return Array.from(segmenter.segment(str)).map(s => s.segment);
            return [...str];
        }

        function toFullWidth(str) {
            return str
                .replace(/ /g, '\u3000')
                .replace(/[!-~]/g, s => String.fromCharCode(s.charCodeAt(0) + 0xFEE0));
        }

        function transformChar(char) {
            return charMap[char] ?? char;
        }

        function convertToKaTeX() {
            let text = DOM.in.value;

            DOM.cnt.textContent = `${segmentText(text).length}文字`;

            if (!text.trim()) {
                DOM.prev.innerHTML = EMPTY_PLACEHOLDER;
                DOM.btn.disabled = true;
                return;
            }

            text = toFullWidth(text).replace(/\n+$/, '');

            const lines = text.split('\n').map(l => segmentText(l));
            const rowCount  = lines.length;
            const maxLength = lines.reduce((mx, l) => Math.max(mx, l.length), 0);
            const columns   = Array(rowCount).fill('c').join(' ');

            const resultParts = [`$$\n\\begin{array}{${columns}}\n`];
            for (let ci = 0; ci < maxLength; ci++) {
                const cells = [];
                for (let li = rowCount - 1; li >= 0; li--) {
                    const raw  = lines[li][ci];
                    const char = raw === undefined ? '\u3000' : transformChar(raw);
                    cells.push(`\\text{${char}}`);
                }
                resultParts.push(cells.join(' & ') + ' \\cr\n');
            }
            resultParts.push(`\\end{array}\n$$`);
            const result = resultParts.join('');

            DOM.btn.disabled = false;

            try {
                const clean = result.replace(/^\$\$\n?/, '').replace(/\n?\$\$$/, '');
                katex.render(clean, DOM.prev, { throwOnError: true, displayMode: true });
            } catch (err) {
                const errMsg = err.message.length > 200 ? err.message.slice(0, 200) + '…' : err.message;
                const errSpan = document.createElement('span');
                errSpan.style.cssText = 'color:red;font-size:0.9rem;';
                errSpan.textContent = `⚠️ プレビューエラー: ${errMsg}`;
                DOM.prev.replaceChildren(errSpan);
            }

            DOM._result = result;
        }

        function setActiveBtn(idx) {
            DOM.smpBtns.forEach((b, i) => b.classList.toggle('active', i === idx));
        }
        function loadSample(idx) { DOM.in.value = SAMPLES[idx]; setActiveBtn(idx); convertToKaTeX(); }
        function clearInput()    { DOM.in.value = '';            setActiveBtn(1);   convertToKaTeX(); }

        document.querySelector('.sample-bar').addEventListener('click', (e) => {
            const btn = e.target.closest('[data-sample], [data-action]');
            if (!btn) return;
            if (btn.dataset.action === 'clear') { clearInput(); return; }
            if (btn.dataset.sample != null) loadSample(parseInt(btn.dataset.sample, 10));
        });

        DOM.btn.addEventListener('click', async () => {
            const code = DOM._result || '';
            try {
                await navigator.clipboard.writeText(code);
                DOM.btn.textContent = '✓ コピーしました';
                DOM.btn.classList.add('copied');
                DOM.toast.classList.add('show');
                setTimeout(() => {
                    DOM.btn.textContent = 'note用コードをコピー';
                    DOM.btn.classList.remove('copied');
                    DOM.toast.classList.remove('show');
                }, 2500);
            } catch {
                const ta = document.createElement('textarea');
                ta.value = code;
                ta.style.cssText = 'position:fixed;opacity:0;';
                document.body.appendChild(ta);
                ta.select();
                document.execCommand('copy');
                document.body.removeChild(ta);
                DOM.toast.textContent = '自動コピーできません — 手動でコピーしてください';
                DOM.toast.classList.add('show');
                setTimeout(() => {
                    DOM.toast.classList.remove('show');
                    DOM.toast.textContent = 'コードをコピーしました — note の $$ ブロックに貼り付けてください';
                }, 2500);
            }
        });

        let timer;
        DOM.in.addEventListener('input', () => {
            setActiveBtn(-1);
            clearTimeout(timer);
            timer = setTimeout(convertToKaTeX, 200);
        });

        const init = () => typeof katex !== 'undefined' ? loadSample(0) : setTimeout(init, 50);
        document.addEventListener('DOMContentLoaded', init);
    </script>
</body>
</html>

#noteの書き方 #縦書き #ツール配布 #エッセイ #小説 #川柳 #短歌 #詩 #創作 #表現 #文章術 #ライティング #デザイン #便利ツール

【サンプル】

$$
\begin{array}{c c c}
\text{人} & \text{そ} & \text{ふ} \cr
\text{生} & \text{れ} & \text{だ} \cr
\text{を} & \text{が} & \text{ん} \cr
\text{変} & \text{い} & \text{を} \cr
\text{え} & \text{ち} & \text{変} \cr
\text{る} & \text{ば} & \text{え} \cr
\text{︒} & \text{ん} & \text{る} \cr
\text{ } & \text{ } & \text{︒} \cr
\end{array}
$$

出展: 1月1日 本田技研工業 新聞 2010年

※本記事のリンクはAmazonアソシエイトを利用しています。紹介するのは私が実際に手にとった書籍・商品だけです。リンクからのご購入はあなたの価格を変えることなく、次の記事を生み出す力になります。

音声解説


ここから先は

36,165字

¥ 200

Amazon Payで支払うと最大2%還元のチャンス! 9/30まで

この記事が参加している募集

この記事が気に入ったらチップで応援してみませんか?