Fakebook改めSTGYの投稿記事は、Markdown形式で書かれている。なぜMarkdownなのかというと、好きだからだ。構造化文書を最も少ない特殊記法で表現でき、プレーンテキストとの見た目の違いが少なく、画像やリンクの張り込みもやりやすい。ここでは、SNSでのMarkdownの採用がいかに現実的なのかを語ってみたい。サイドバイサイドプレビュー機能付きのMarkdownエディタも作った。

Markdownサイドバイサイドプレビューのデモ
Markdownの美点(簡潔さ、記述力、論理性)と、WYSIWYG的なとっつきやすさを両立するための一案として、Markdownのサイドバイサイドのプレビュー機能を提案する。そのデモを作った。こちらのページを見て欲しい。編集メニュー、自動スクロール、自動ハイライトをサポートし、校正とレイアウト修正が簡単にできるようになっている。

プレビューの機能にスニペット生成のテストも統合している。最大文字数200文字、最大行数10行、アイキャッチ画像抽出、という指定をすると、以下のようなスニペットが生成される。本番サイトのスニペット生成設定と同じだ。ASTを構築してからノードを辿って長さ制限をかけているので、絶対にレイアウトが崩れない。

HTMLではなくプレーンテキストを出力するモードもあるが、これは検索エンジンに食わせるためにある。全部をテキストにするのではなく、タイトルを分離して残りだけテキストにしたいとか、著者名も加えたいとかいった要件はいろいろあるだろうが、ASTを構築してから処理すれば、大抵のことは簡単にできるようになっている。

意気込み
大隊総員傾注!! 諸君、夜が来た。 無敵の敗残兵諸君。最古参の新兵諸君。 万願成就の夜は来た。
諸君 私はMarkdownが好きだ 諸君 私はMarkdownが好きだ 諸君 私はMarkdownが大好きだ 見出しが好きだ 強調が好きだ 斜体が好きだ リンクが好きだ 箇条書きが好きだ 番号付きリストが好きだ コードブロックが好きだ READMEで Wikiで イシューで プルリクで ブログで スライドで コメントで ドキュメントで Emacsで VSCodeで GitHubで ChatGPTで この世界で使われるありとあらゆるマークアップが大好きだ 整然と並んだ空行区切りの段落が文書構造となって思考を整理するのが好きだ 空中高く跳ね上がった見出しシャープが章立てとなってばらばらの論理を暴露した時など心がおどる 三つのバッククォートが漏出するエラーメッセージを記載するのが好きだ 燃えさかるコンフリクトから飛び出してきた差分をフェンス付きコードでコピペした時など胸がすくような気持ちだった ハイフンを揃えた箇条書きの集合が規定の組版を蹂躙するのが好きだ 恐慌状態の行間が、すでに校正済みの段落を何度も何度も折り返して崩していく様など感動すら覚える 敗北主義のタイポ識別子をレビュー欄へ吊し上げていく様などはもうたまらない 泣き叫ぶTODO行が私の振り下ろしたキーとともに金切り声を上げる検索置換にばたばたと薙ぎ倒されるのも最高だ 哀れな雑多実装達が独自拡張で健気にも立ち上がってきたのを Daring Fireballの由緒正しき原典が仕様ごと木端微塵に粉砕した時など絶頂すら覚える 定着した方言の群れにデザイン哲学をめちゃくちゃにされるのが好きだ 必死に守るはずだった伏線が蹂躙され構成が崩れていく様はとてもとても悲しいものだ 長大なセルの分量に押し潰されて表のレイアウトが壊れるのが好きだ 実装差異に追いまわされ害虫の様にHTMLに書き換えられるのは屈辱の極みだ 諸君 私はMarkdownを 地獄の様なMarkdownを望んでいる 諸君 暇つぶしに技術ブログを読む はてなブロガー諸君 君達は一体何を望んでいる? 更なるMarkdown実装を望むか? 情け容赦のない糞の様なMarkdown実装を望むか? 鉄風雷火の限りを尽くしASTを粉砕する嵐の様な記法を望むか? (MD! MD! MD!) よろしい ならばMarkdownだ 我々は渾身の力をこめて今まさに振り降ろさんとするEnterキーだ だがこの暗い闇の底で半世紀もの間堪え続けてきた我々にただのプレビューではもはや足りない!! 緊急マージを!! 一心不乱の緊急マージを!! 我らはわずかに一個リポジトリ 千コミットに満たぬ敗残者に過ぎない だが諸君は一騎当千の古強者だと私は信仰している ならば我らは諸君と私で総チェンジ量100万と1行のプルリクエストとなる 我々を忘却の彼方へと追いやりWYSIWYGの夢に眠りこけている連中を叩き起こそう 髪の毛をつかんで引きずり降ろし眼を開けさせ思い出させよう 連中にポメラの軽さを思い出させてやる 連中にHHKの打鍵の音を思い出させてやる 行頭と行末のはざまには奴らの哲学では思いもよらない簡明さがあることを思い出させてやる 一千行のtableタグでメモリを食い尽くしてやる そうだ あれが我々が待ちに望んだHTML Standardの光だ 私は諸君らを約束通り連れて帰ったぞ あの懐かしの缶詰へ あの懐かしの記法へ (メンテナ殿!メンテナ!代行!代行殿!レビュー責任者殿!) そしてGFMはついに大洋を渡り各実装へと登る 全貢献者各員に伝達 メンテナ命令である さぁ、諸君 エディタを開くぞ
てことで、Markdownはとても良い物なので、微力ながらその普及を図りたい。STGYで採用することはその一環でもある。
Markdownの美点
Markdownは、元々はJohn Gruber氏がPerlで書いたHTML生成ツールの入力フォーマットだ。使いやすいから多くのユーザが使い、似たような書式を扱うツールが次々と表れ、いつの間にかGitHubなどでもサポートされる記法になっていった。特に標準化団体とかはなく、草の根で勝手に広がった記法であり、方言が無数にある。CommonMarkなどの標準化の試みは多くあるが、特に権威のあるものはない。ソフトウェア技術者界隈で事実上の標準的な位置づけになっているのはGitHubで使われているGFM(GitHub Flavored Markup)の仕様である。
Markdownの最も良いところは、書くのが楽なところだ。プレーンテキストとしてドラフトを書いて、そこから最小限の修正で構造化文書に仕上げられる。大抵の場合、「#」「##」「###」で題名や各章の見出しや小見出しをつけて、箇条書きの前に「-」を付けて、表があれば「|」でセルを区切れば完成する。リンクや強調や画像埋め込みも直感的に書ける。
# Re: ゼロから始める断食生活
金がないので断食することになってしまった。
金が無いと食料が変えない。
雑草を食えば良いんじゃないか。スギナとかスベリヒユとか普通に食えるし。でも腹下す可能性が高いから、厳しいかも。戦時中ですら雑草食が広まらなかったのは、人間が雑草を食うのは難しいということを示しているのではないか。

## 美点
断食をすると、::こんなに::良いことがあります。
- お腹が空く
- 代謝と**筋肉**が落ち
- {{不機嫌|メランコリー}}になる
## 周期表
水兵リーベ僕の船、名前があるシップスクラークか。
|H|He|Li|Be|B|C|N|O|F|Ne
|Na|Mg|Al|Si|P|S|Cl|Ar|K|Ca
SNSの投稿で使う場合、ほとんどのユーザはMarkdownなんて知らない。「本文はMarkdown形式で記述します」とヘルプ文書に書いたところで、ピンとこないだろう。そして、ヘルプ文書が存在しても、ほとんどのユーザは読まない。FacebookやTwitterのヘルプ文書は私も読んだことがない。ゆえに、何の説明もしなくても、投稿機能が使える必要がある。
そもそも、ほとんどのユーザは、構造化文書なんて概念は知らない。国語力の低い半分以下の層は、段落という概念すらよく分かってないのが現実だろう。それを前提とすると、以下の要件が出てくる。
- 書いた文字がそのまま表示される。
- 改行はそのまま改行として機能する。
つまり、特殊記法を知らないで普通にプレーンテキストを書けば、そのまま投稿できるということだ。ここで、本家Markdownの仕様と早速の衝突が発生する。本家では、単一の改行は改行として扱わないのだ。これは英語文化圏で、おそらくタイプライターや昔の電子メールの桁数制限の影響で、文中でも適当な桁数で改行を入れて折り返す習慣への対応だろう。ただ、自分で改行する文化は段々薄れてきているので、この仕様の必要性は薄れてきている。日本語などの文中に空白文字を入れない文化圏では、なおさら文中に改行を入れる習慣は薄れてきている。よって、単一の改行を改行として扱う方言を入れることにする。空行は段落区切りになる
書いた文字がそのまま表示されると感じさせるには、通常の文に特殊記法がたまたま現れる確率をできるだけ下げたい。よって、ここでも本家Markdownの書式を改造する。本家だと「*ABC*」でem要素の斜体になるが、それだとコード説明の掛け算や注釈用途の米印の意図のアスタリスクと被るので、こちらでは「::ABC::」にした。strong要素の太字は本家と同じく「**ABC**」だ。メタ文字が二つ並ばないと記法として発動しないようにするのが重要だ。その他、以下のものがサポートされている。

代替案
Markdownの他にも、構造化テキストを書く方法はたくさんある。それぞれのサンプルを見てみよう。
AsciiDoc
私の名前は*中野*です。 * あの<<ihatov.html,イーハトーヴォ>>の透き通った風
AsciiDocは機能が豊富で、見出し・脚注・表・アドモンションなどを素で持つ。AsciiDoctor系ツールでの変換も強力だが、記法がやや多く学習コストは高め。ブログよりは設計書・マニュアル向き。
ReST
私の名前は**中野**です。 - あの`イーハトーヴォ <ihatov.html>`_の透き通った風
Sphinxと相性が良く、Python界隈のドキュメントで広く使われる。インデントや空行など整形規則が厳密で、長文の参照資料には強いが、気軽な投稿には少し堅い。
Org-mode
私の名前は*中野*です。 - あの[[ihatov.html][イーハトーヴォ]]の透き通った風
Emacs文化圏の最強メモ・アウトライナ。TODOや日付、表計算、エクスポートが統合されていて強力。ただしEmacs依存が前提で、一般ユーザにはハードルが高い。
はてな記法
私の名前は<strong>中野</strong>です。 - あの<a href="ihatov.html">イーハトーヴォ</a>の透き通った風
はてなブログで使われている記法。MarkdownとHTMLの折衷のような記法。HTMLに慣れたWeb製作者には使いやすいが、はてな以外で採用する理由はない。
Textile
p. 私の名前は*中野*です。 * あの"イーハトーヴォ":ihatov.html:の透き通った風
要素の種類を行頭に書く記法。Redmine等で使われている。HTMLに似ているが、HTMLとは語彙も記法も違うので、誰にとっても学習コストがかかる。Markdownの源流の一つと言われる。
MediaWiki
私の名前は'''中野'''です。 * あの[ihatov.html イーハトーヴォ]の透き通った風
Wikipediaで使われている記法。HTMLも併用でき、表現力も高いが、テキストとして表示すると煩雑になる。
LaTeX
私の名前は \textbf{中野} です。
\begin{itemize}
\item あの\href{ihatov.html}{イーハトーヴォ}の透き通った風
\end{itemize}組版力は圧倒的で、数式・参考文献管理も無双。ただし書くのが重いし、ビルド環境も必要。SNSの短文や日常投稿には過剰装備。
WYSIWYG批判
「What you see is what you get」というモットーに基づき、編集画面の見た目と最終出力の見た目を同じにするエディタが2000年頃から隆盛して今に至っている。Netscape CommunicatorとかHomepage Builderとかいうソフトがあって、改行を行末にp要素でbr要素を置くことで表現するのが物議を醸していた。構造化文書派とWYSIWYG派の対立が当時から存在した。
構造化文書派の私としては、WYSIWYGという文化があまり好きではない。最終出力である「What you get」はひとつじゃないので、編集画面の見た目と揃えるという概念自体が不合理だと思うのだ。PCに限定しても、ブラウザの種類は様々だし、画面解像度は違うし、画面の色域や輝度は違う。モバイル端末だと、スマホとタブレットがあり、OSが違い、アスペクトやディスプレイ倍率が違う。スマートグラスやスマートウォッチやスクリーンリーダや電子ペーパーといったデバイスもある。印刷するなら、紙のサイズが違うし、組版のルールも様々だ。二段組にするかもしれない。縦書きにするかもしれない。音声合成が発達した今、読み上げは聴覚障害者のためだけじゃなく、運転や料理の途中で使う利便性向上の機能でもある。コンテンツをAIに読み込ませて校正したり別のコンテンツを作ることもある。「What you see」がカバーするのはそのごく一部だ。文書の本質は情報であって、構造であって、見た目はその一面でしかない。特に、STGY上の文書はAIが読むことで価値を増幅する仕掛けであるため、見た目よりも構造が重要となる。
いわゆるITリテラシが低いユーザ層にも分かりやすいUXを提供するためにWYSIWYGエディタがあるというのは分かる。だから、WYSIWYGエディタが存在している事は良いことだと思う。しかし、GUIの使い方を学習するコストと、記法の使い方を学習するコストを比べると、両者がそれほど違うとは思えないのだ。「太字を表現するには、対象のテキストを選択してから、メニューの【太字】を選びます」とヘルプに書くのと「太字は**テキスト**のように表現します」とヘルプに書くのは、むしろ後者の方が難易度が低いように思える。
もっと言えば、SNSの上のテキストで、文書構造なんて気にしないことが多いだろう。多くの場合、ヘッダとか箇条書きとかは使わず、絵文字で装飾するだろう。絵文字文化では、プレーンテキストが表示できるというだけで、WYSIWYGの要件が満足してしまう。つまるところ、WYSIWYGは文書構造を気にする人にはまどろっこしいし、文書構造を気にしない人には無用の長物なので、中途半端な機能とも言える。
WYSIWYGエディタでも段落やヘッダなどの構造を明示するUIになっていれば、構造化文書を編集できる。しかし、構造を明示する要件と見た目を整える要件が頻繁に対立するところにWYSIWYG哲学の限界がある。構造を明示するなら、例えば、H1、H2、H3、太字の段落のそれぞれが、一目で区別できる必要がある。フォントサイズやフォントウェイトやその他の装飾でそれぞれのレンダリングに差異が出るようにする必要がある。H2とH3を一目で区別し、H3と太字の段落を一目で区別できるようになるには、そこそこの慣れが必要だ。その学習コストを下げるためには、各要素の種類を画面上で明示したくなる。しかし、最終出力と異なる表示をすると、それはWYSIWYGではなくなってしまう。構造を分かりやすさを追求し始めると、マークアップに似た表示をするようになり、GUI付きマークアップエディタとも言える存在になってくる。つまるところ、WYSIWYGと構造化というのは二元論ではなく、スペクトラムで捉えるべきだ。想定最終出力の見た目に忠実とは言えない編集画面だが文書構造が分かりやすいWYSIWYGエディタが有っても良いし、文書構造化の制約が緩いが想定した想定最終出力の見た目に近い編集画面のマークアップエディタが有っても良い。
物書きのユースケース
私のように長めの文章をよく書くユーザにとっては、お気に入りのエディタだけで執筆作業がほぼ完結するのは必須だ。私はエディタは専らEmacsを使うが、そこで文書構造も含めて書ききってしまいたい。内容の大枠を考えて、セクションごとに仮の見出しを決めて、地の文を書いて、適宜箇条書きや表を書いてドラフトを完成させる。画像は [image:アーキテクチャ図] とかいったプレースホルダにしておく。そして、読み返して校正しながら見出しや地の文を整える。最後にブログやGitHubに記事データをコピペして、仕上げを行う。画像のプレースホルダの部分にアップロード画像を挿入し、プレビュー画面を見て、OKだったら記事を公開する。作業時間の95%くらいはエディタ上での執筆作業で、アップロード等の作業は5%くらいの時間しか使っていない。となると、効率化すべきなのがエディタ上での執筆作業なのは明らかであり、Markdownはその最善の手段だ。
見出しや箇条書きを表現するのに、GUIって使いやすいだろうか。いや、全くもって使いにくい。GUIだと、見出しやら箇条書きやらを書く度に、キーボードから指を離して、ポインタデバイスで操作しなきゃいけない。その度に思考が中断するか、ノイズで集中力が低まることになる。Markdown等であれば、ホームポジションに指を置いたまま、執筆作業を続けられる。文書構造を変えたい場合でも、検索置換やエディタのマクロを駆使して効率的に作業できる。また、AIに内容をコピペして相談するなり校正させるなりの作業もMarkdown等の方がやりやすい。
GUIによるレイアウト作業で最もムカつくのは、各々のスタイル指定の範囲の切れ目を制御する操作が直感的ではないことだ。とある領域を太字やリンクで装飾したとして、その直後に文字を足した場合に太字やリンクにしたい場合もあるし、したくない場合もある。実際にその操作をしてみた時に所望の結果と違った場合、1文字前や後にカーソルをずらして文字を入力してから不要部分を消すみたいな屈辱的な作業をすることになる。リストの次の行に普通の段落を書きたいのに、改行すると勝手にリストになるからDeleteキーやらShift+Tabやらで元に戻すとか空行を入れるとかいった独自仕様に追従しなきゃならないのも嫌だ。空行の行数で最終出力のレイアウトが変わる場合、校了後に微妙なマージンの違いに気づいてわざわざ修正するのも不毛だ。
ブラウザ上で長時間作業することにはリスクがある。間違ってクローズボタンやバックボタンを押して、編集中の内容を失ってしまうことがよくあるのだ。もしブラウザ上で長時間の作業をするのなら、記事のデータを暗黙的に保存し、履歴管理し、過去の状態を復元できる機能が求められる。しかし、投稿前の記事にはIDがないので、文書の一意性を決めることは難しい。先に投稿してから編集する方法だと、編集途中のドラフトが他のユーザに閲覧されることになる。それを避けるには記事の公開状態の管理が必要になるが、そこまで行くともはやSNSではなくCMSになってしまう。Google DocsがWYSIWYGエディタをサポートできるのは、その基盤であるGoogle Driveが高度なCMSだからだ。WordPressも自身がCMSだからWYSIWYGエディタをサポートできる。翻って、STGYがSNSとしての建付けを維持するなら、長文の執筆やその途上のデータ管理はあくまで各ユーザがエディタ上で行う前提にするのが現実的だ。
テキストベースのマークアップの美点として、例を見るだけ記法が理解できることが挙げられる。Markdownのことを全く知らない人にMarkdownのデータを見せて、「続き書いておいて」と言えば、おそらく何の質問もなく、見様見真似で執筆を引き継げるだろう。URL埋め込みと画像埋め込みの記法は若干の慣れが必要かもしれないが、それも例がひとつずつあれば、だいたい分かるだろう。物書きの知能は概して高いのだから、ヘルプを読まなくても高度な機能を使いこなせるだろう。画像レイアウトなどの細かい仕様もヘルプを読んでもらえればすぐ理解できるはずだ。
業務として記事を執筆する場合、GitやHgなどのバージョン管理システムで記事データを管理することが必要になることもある。その際には、Markdownのようなマークアップを直接書くデータ形式の方が望ましい。WYSIWYGエディタは細かい装飾や空白や改行の存在が隠蔽されるので、予期せぬ変更でdiffが撹乱されることがある。また、Markdownを使うことで構造化文書を書く意識が醸成されるが、適切に構造化されたデータは複数人が同時に作業してもコンフリクトが起きにくい。
Markdownは標準化された規格ではなく、方言が多いが、基本的な構造はどの実装も同じだ。多少の差異があっても、簡単な検索置換で吸収できる。よって、Markdownで記事を書いておけば、データのマイグレーションも容易になる。STGY上でたくさんの記事を書き溜めた人が、自分のブログに記事を載せ替えるというような場合、移行先がMarkdownに対応していればそのまま使えるし、そうでない場合でも、既存のMarkdownツールでHTML等に変換すれば良い。Markdownの仕様が単純なおかげで、データ変換ツールを自前で実装するのも簡単だ。
大手サービスの考察
FacebookやTwitterの投稿はプレーンテキストだが、太字などの装飾をしている人達がいる。彼らは特別なマークアップをしているわけではなく、Unicodeの装飾文字を使っているだけだ。ゆえに、漢字や仮名は装飾できない。特別な文字を使って装飾するという意味では絵文字で装飾しているのと同じだ。STGYでも当然同じ事ができる。とはいえ、いちいち外部サイトを開いて装飾文字への変換をする手間をかけるよりは、Markdownの記法を使った方が楽だろう。
一方、Slack上のメッセージはWYSIWYGで装飾できるようになっている。チャットの内容を装飾するのであれば、WYSIWYGの方が楽だ。いちいちプレビューを確認するなんて面倒をチャットでやりたくない。Slackアプリで書いたメッセージはSlackアプリでのみ表示され、それは即座にもしくは短期間で消費されることが想定される。すなわち、長期的に保管して繰り返し再利用される資料を作ることが目的ではなく、流動的なコミュニケーションを媒介するのが目的である。SNSにおいても、チャット的な短文投稿を主眼に置くならば、WYSIWYGエディタを採用する方が良いかもしれない。しかし、そうであれば、短文主体であるTwitterでなぜWYSIWYGによる装飾機能が導入されていないのか。答えはTwitterの人に聞いてみないとわからないが、私は以下のような理由を推測する。
- UI/UXを単純化したい。
- 実装を単純化したい。
- 装飾以上の構造化をするには文字数が少なすぎる。
- メッセージの構造が複雑になると一覧表示のデザインが乱れる。
- Unicodeの絵文字と装飾文字で十分である。
結局のところ、マークアップとWYSIWYGのどちらが良いかというのは、一概には言えない。そのサービスをどう使ってもらいたいのかという運営者の恣意的な決定に過ぎない。FacebookとTwitterはそもそも文字種以外の装飾機能を備えないが、マークアップではない。SlackはWYSIWYGの装飾機能があり、マークアップではない。他方で、はてなブログやGitHubやWikipediaはマークアップである。それらを踏まえると、マークアップが向いているユースケースの条件が見えてくる。コンテンツが長文になることがあり、ユーザのリテラシが高いことだ。ゆえに、敢えてマークアップをサポートするならば、リテラシが低かったり装飾や構造化に興味がなかったりするユーザに負荷を与えないことと、学習コストをできるだけ下げることが求められる。
プレビューと校正
構造化文書としてデータを仕上げたとしても、プレビューは必要だ。WYSIWYGではないので、プレビューという行為は執筆とは切り離された行為であり、どのビューアを使うかを選択することから始まる。典型的にはHTMLに変換された出力をWebベージとして眺めることだろう。Chrome等の開発ツールを使えば、簡単にモバイルモードにしたり画面解像度を切り替えて、多様なデバイスでの表示をシミュレートすることができる。MacのVoiceOverでスクリーンリーダでの読み上げ具合を試してもいい。
執筆画面とプレビュー画面の行き来が面倒くさいからWYSIWYGエディタの方が好きだ、という人がいるかもしれない。私も昔そうだった。しかし、Markdownでの執筆に慣れてくると、そもそも行き来する頻度が激減する。内容勝負になってくるとレイアウトをほとんど気にしなくなるからだ。プレビューは、マークアップのミスを検出するためだけに行う。例えば見出しを「#」でマークアップすべきところを、はてな記法の「*」にしてしまっていないかとか、コードブロックの```がちゃんと閉じられているかとかを確認するだけだ。
とはいえ、Markdownの執筆に慣れていない人はプレビュー画面との行き来をすることになり、それが学習コストを上げてしまうことは認めねばならない。STGYの運営はMarkdownを普及するための機会でもあるのだから、そのMarkdownの学習コストを下げる努力をしたい。
まずは、GitHubをパクって、投稿フォーム用メニューバーを実装した。Headerの「H1」「H2」「H3」、そして、リスト、引用、コードブロックの構造系ボタンをつけた。さらに、太字、斜体、下線、打ち消し線、インラインコード、マーカー、ルビ、リンクの装飾系ボタンもつけた。それらを押すと、カーソルのある行や選択領域にそれぞれのスタイルが適用される。もう一度押すと解除される。また、ユーザメンションのと既存画像取り込みと新規画像アップロードのアイコンもある。

画像の埋め込み記法を貼り付けて、その行にカーソルがある状態では、メニューバーが画像配置オプション用のものに変わる。レイアウトは左寄せ、グリッド、左フロート、右フロートから選べる。サイズはXS、S、M、L、XLのサイズが選べる。スニペットのアイキャッチ画像フラグも立てられる。レイアウトやサイズは文書構造とは関係ないが、Webブラウザに表示する上でそれらの制御は高確率でしたくなるので、たとえオプションであってもユーザビリティには配慮する。

ただし、これらはおそらく各ユーザが30分も経てば使わなくなるだろう。アイコンを押すよりは、「#」やら「-」やらを入力した方が速いからだ。にも関わらず、なぜそれらを作ったかというと、まずは構造化や装飾ができるということを知ってもらうためだ。ヘルプはほとんどの人が読まないが、投稿フォームはほぼ全員が目にする。そこにさり気なく機能の宣伝が並んでいるということだ。さらに、アイコンがあることで、初心者が感じるであろう、メタ文字を覚えなきゃならないという心理障壁を取り払う効果もある。慣れた人でも、「インラインコードのマークアップて何だっけ?」となることがあるので、チートシートの代わりとしても機能する。
モバイル端末だと表示幅に限りがあるので、ボタンは厳選する。画像系は必須なので残して、H1、H2、リスト、太字、斜体、リンクだけにする。文字入力が面倒なモバイル端末だからこそボタンで支援すべきな気もするが、仕方ない。モバイル端末であまり複雑な構造の文章は書かないだろうと割り切る。

続いて、WYSIWYG勢にさらに対抗すべく、サイドバイサイドの執筆画面を開発した。投稿フォームの下にある「プレビュー」ボタンを押すと、プレビューが表示されるのだが、ウインドウ幅が1000px以上の場合、サイドバイサイドビューが発動する。画面左半分にMarkdownの執筆フォームが表示され、画面右半分にはプレビューが表示される。執筆フォームを変更すればそれはほぼリアルタイムにプレビューに反映される。

実装にはそこそこ工夫を要した。全てのキー入力で更新を行う完全リアルタイムにすると処理負荷が上がりすぎるため、最後にフォームが更新されてから0.1秒内容が変わっていない場合にプレビューを更新するようにしている。0.1秒というのは人間の反応速度の限界と言われ、陸上競技のフライングの判定基準にもなっている。つまり、入力フォームの変化を検出した第三者が即座にプレビューを確認したとしたら、その遅延には気付けない。ただし、入力している本人はもっと敏感であり、プレビューを見ながらタイピングしているならば、その遅延に気づく可能性がある。WYSIWYGエディタで0.1秒の遅延があるなら、小足見てから昇竜レベルの人は苛つくだろうが、マークアップエディタのプレビュー機能としてなら十分に高速だと言える。この遅延によるデバウンス処理と、自作Markdownパーサが高効率であるおかげで、記事の分量が数万字に増えても入力フォームのもたつきが全く起きないようにできた。また、プレビュー側のDOMはダブルバッファリングして、表示のチラツキを完全に抑えている。よって、プレビュー表示による損は無く、全体的な利便性は上がっていると判断する。
実用上重要なのは、プレビューが勝手にスクロールして、執筆フォームで変更した部分が確実に視認できる状態になることだ。文章が長くなって一画面に収まらない場合、この機能がないと、手動でプレビュー画面をスクロールする作業が発生して、それが執筆の思考を乱してしまう。この機能を実装するために自作Markdownパーサに手を入れて、AST(抽象構文木)の各ノードが元のMarkdownの何文字目かつ何行目から生成されているのかを記録するようにした。
スクロールには他にも拘りがある。入力フォームを編集した際には、それによって更新されるか新規に出現した要素が画面に収まるように自動スクロールするようになっている。それがなくても、ユーザ自身がスクロールすれば良い話ではある。しかし、「文書の要素を編集しているのだから、それを表示したいに決まっているだろう。なぜ人間様が自分でスクロール操作をせにゃならんのだ」という不満は当然であり、それは解消しておくべきだ。
さらに、プレビュー側の左端には縦溝があり、そこに各ブロック要素に対応するツマミがある。それを押すと入力フォームが自動スクロールして該当行にカーソルが飛ぶ。カーソル位置が入力欄の上から40%の位置に来るように自動スクロールするのだが、これが50%より小さいのが地味な工夫だ。行頭にカーソルが飛ぶのだが、行頭が40%付近であれば、それを含む段落の中心が画面の中心に来ることが多くなる。そうすると、プレビュー側を見ながら修正点に気づいた時に、修正すべき位置を一瞬で特定できるようになる。ツマミのtitle属性には「Jump to line 234」などと書いてあるので、ツールチップで行番号を見て、ローカルのエディタ側で修正するのも楽だ。さらにさらに、入力フォームでカーソルがある行は薄水色にハイライトされて、かつそれに対応するプレビュー側の要素も薄水色にハイライトされて、どこに視線を置くべきかが無意識に分かるようになっている。これはディスレクシア(読字障害)の人々が使うリーディングトラッカーにヒントを得ている。こういう細かい配慮の積み重ねこそがユーザビリティを決めるのだ。
サイドバイサイドビューは便利なのだが、最終校正と公開後の微修正にしか使わない。95%の時間を自分のエディタ上で過ごす物書きにとっては、STGY側での効率化の恩恵は残り5%の中での改善に過ぎない。つまり、時間あたりの生産性への寄与はあまり大きくない。それでも、5%の作業が面倒であると、精神力(≒やる気)を著しく削られてしまう。知的水準が高いほど、生産性の低い不毛な作業で強いストレスを感じるだろう。ゆえに、モチベーション管理の観点に立つと、5%の面倒を改善するのには5%の枠組み以上の生産性を改善する効果がある。また、既にある記事を公開するか否かを判断する際には公開作業の手間と公開によって得られる便益を天秤にかけることになる。公開によって得られる便益は明らかではないが公開作業の手間は明らかなので、それでもやってみようと思ってもらうためには、手間をできるだけ減らしておきたい。
おまけで、画像アップロード機能を改修して、テキストファイルをアップロードして入力フォーム内に挿入する機能もつけた。複数ファイルの同時アップロードにも対応している。ファイルアップロードがあると、Git等との連携がさらに楽になる。01-introduction.md、02-background.mdなどファイルを分割して管理している場合でも、一気にアップロードしてプレビューや公開ができる。CMSとしての機能は全てGitに任せて、そのフロントエンドとしてSNSが機能するということだ。
ところで、私も含めた構造化文書主義者の一部は、太字や傍線やルビなどの装飾を忌避する傾向がある。構造と修辞で読ませたいという建前がありつつも、装飾が面倒くさいという本音もあるだろう。Markdownで書いていると装飾を忌避する傾向は強化される。Markdownの中にメタ文字を混ぜても、エディタ上で見ている限りではノイズにすぎないからだ。しかし、現代の読者は適切な装飾を求める。技術書でも重要語は太字や文字色で彩られ、小説でもフォントや傍線やルビによる装飾が多様される。ゆえに、適切に装飾を入れるのは生き残るために必要となる。仕上げにサイドバイサイドビューを使うと、文字装飾の心理的障壁が解消できる。挿入したメタ文字による装飾が即座にプレビューに反映されるので、その効果を実感し、学習することができる。
米国のIT企業ではDogfoodingまたはEating your own dog foodというモットーがあり、自社製品を自社で利用することが推奨されている。私はこの言葉が大好きだ。少なくとも自分たちにとっては使いやすいものを作る動機づけが生まれる。もちろん、自分たちにとって使いやすいものが一般ユーザにとって使いやすいものとは限らないのだが、どうしようもない不具合を減らす効果は確実にある。たまに、ITシステムでもそれ以外の商品でも、「お前それ一度でも自分で使ってみたのか?」と製作者を問い詰めたくようなひどい仕様や出来栄えのものがある。それを他山の石として、私は基本的に自分の製品を自分で使い込むことが多い。
今回のプレビュー機能もDogfoodingの過程で実装を決断した。自動スクロール機能も、実際に使いながら欲しくなったので追加した。結果として、汎用Markdownエディタとしてかなり使いやすいものに仕上がったと思う。パーサとレンダラはサブパッケージとして再利用可能なライブラリにしていて、他のプロジェクトでも使って欲しいと思っている。一旦パーサがASTを構築すれば、任意のレンダラを書くのも簡単だ。「このASTをXXX形式に整形するコードを書いて」とAIに頼めば良い。EPUBでもLaTeXでもDocXでも60分くらいの作業で対応できるだろう。Markdownを再び吐かせれば、任意のMarkdown方言へのマイグレーションもできる。
github.com
テーブル対応
本家Markdownでは、「|」で始まって「|」で終わる行はテーブル定義になる。ヘッダのセルと通常セルは、「|----|」の行で区切る。以下がその例だ。
|名前|説明| |----|----| |東京|将軍様のお膝元| |大阪|天下の台所|
STGYでは、テーブルの記法には結構な変更を施した。まず、ヘッダを行で区切る方法を廃止した。行で区切る方法だと、横倒しして1列目にヘッダを集める表現ができない。なので、「|」で始まって「|」で終わる行はヘッダがあろうが無かろうがテーブルになり、「|=名前=|」などとして任意のセルをヘッダに指定できるようにした。つまり、以下のように書けるようになる。明らかに書きやすく、かつ見やすくなっているだろう。
|=名前=|=説明=| |東京|将軍様のお膝元| |大阪|天下の台所|
さらに、列結合、行結合、右寄せ、中寄せも可能にした。それらを総動員した例が以下のものだ。
|=名前=|=説明=|={colspan=2}><人口=|
|東京都|都庁所在地は新宿区。日本の首都。|>>1,426万人|{rowspan=2}都会|
|神奈川県|県庁所在地は横浜市。大阪府より人口が多い。|>>921万人|
|千葉県|県庁所在地は千葉市。ピーナツで有名。|>>628人|{rowspan=2}田舎|
|埼玉県|県庁所在地はさいたま市。特徴は特にない。|>>770人|| 名前 | 説明 | 人口 | |
|---|---|---|---|
| 東京都 | 都庁所在地は新宿区。日本の首都。 | 1,426万人 | 都会 |
| 神奈川県 | 県庁所在地は横浜市。大阪府より人口が多い。 | 921万人 | |
| 千葉県 | 県庁所在地は千葉市。ピーナツで有名。 | 628人 | 田舎 |
| 埼玉県 | 県庁所在地はさいたま市。特徴は特にない。 | 770人 | |
構造化文書を標榜しつつ、なぜテーブルのスタイルを細かく調整できるようにしているのか。理由は2つある。まず、テーブルのスタイルは見た目の問題ではなく、データの論理的な意味を規定するからだ。colspanやrowspanがないと、「説明」というラベルひとつで済ませるべきところをセルごとに「説明1」「説明2」などと書くことになって、煩雑になる。右寄せや中寄せは本来は「数値」「文字列」「ラベル」などのデータ型によって決めるべきものだが、事前にその体系を知ることは不可能なので、仕方なく寄せ方向を直接指定できるようにしている。もう一つの理由は、実用性だ。提案資料や論文を書く際には表は必須で、見やすい表を表現するには結合や寄せ方向の指定は不可欠だ。それらができないと、別のシステムを使って表を作って画像として貼り付けたりリンクを張ったりするようになるだろう。そうすると、記事単体での情報が不完全になり、人間にとってもAIにとってもアクセシビリティが下がってしまう。
右寄せ記法が「>>」で中寄せ記法が「><」なのは、直感的で気に入っている。しかし、結合の「{colspan=2}」「{rowspan=2}」は、ちょっとダサい。それらを「{~2}」「{^2}」とかにすることも考えたが、覚えにく過ぎるので止めた。それほど使用頻度が高くない記法はむしろ長くて分かりやすい方が良い。AIにとっても、データの適切な解釈に必要な情報は記号ではなく自明な文字表現であることが望ましい。「>>」と「><」は単に無視すればよく、「colspan」と「rowspan」は読めば意味がわかる。なお、HTML5において、colspanやrowspanは正式な属性としてサポートされているが、align属性は非推奨となった。よって、colspanとrowspanはそのままHTMLの属性にして、alignの情報はclass属性に "align-right" または "align-center" を指定する仕様にしている。
ヘッダのスタイルについてもこだわりがある。HTMLのデフォルトではth要素は太字で中寄せのスタイルが割り当てられる。つまり、ヘッダは目立つことで区別される。しかし、私はそれが直感的ではないと思っている。表のヘッダは補足情報なので、むしろ目立たないことで区別されるべきだ。また、デフォルトで太字になってしまうと、ヘッダの中で太字にして強調することができなくなる。マークアップで太字を許している以上、ヘッダの区別は太字以外の方法に頼るべきだ。よって、STGYでは、ヘッダはフォントを細く小さくして、背景色をグレーにしている。とはいえ、何が直感的なのかはユーザやコミュニティによって違うだろう。CSSファイル(app/globals.css)をいじるだけで簡単にカスタマイズできるようになっている。
数式対応
本家Markdownには数式に関する特別な記法はないが、GitHubやJupyter Notebookなどのサービスでは、「$」で囲むことでLaTeXの数式記号が使えるようになっている。論文等で数式の記述は必須なので、STGYでも同様の記法をサポートすることにした。ただし、「$」単体だとプレーンテキストでの通常のドルマークとしての利用と衝突するので、「$$」で囲むことにする。例えば「$$E = mc^2$$」とか「$$\int_0^{\sqrt{N}} x^2 \, dx = \lim_{n \to \infty} \sum_{i=1}^{n} f\left( \frac{i \cdot x}{n} \right) \cdot \left( \frac{x}{n} \right)$$」とか書く。

この機能はMathJaxというライブラリを呼び出すことで実現している。AST上では「<math tex="E = mc^2"/>」に相当するノードを構築し、それをHTMLとしてレンダリングする際にSVGのインライン画像に差し替えるのだ。多少重い処理にはなるが、CSR(クライアントサイドレンダリング)で完結させているのでサーバ側の負荷が上がることはない。なお、LaTeXの記法が自由に使えるとスクリプティングの脆弱性が懸念される。そこで、baseとamsにLaTeXモジュールを限定し、かつリンクは全て無効化するサニタイズ処理を行っている。
「SNSで数式なんて書かないよ」と多くの人は言うかもしれない。しかし、「数式が書けないメディアなんて使うに値しない」と思う人も一定数いるのだ。彼らはLaTeXによる数式の記述に慣れているので、学習コストは低い。AIとアルゴリズムについて論じるときにも普通に数式を「$」記法で挟んでくる。テーブルと同様に、この機能がないと画像やリンクで代替されてしまうので、人間と機械のアクセシビリティを確保するためには数式の対応は必須だ。数式をWYSIWYGエディタで書くのはむしろ苦行なので、彼らにとってより直感的であるLaTeX記法を内包できるマークアップ方式の強みがここでも発揮されている。
クライアント側で数式をSVGとして表現すると、人間にとっては見やすいが、AIやスクリーンリーダにとっては困る。APIを使ってMarkdownの方を取得してAIに読ませることは可能だが、アクセシビリティの観点ではそれは望ましくない。そこで、MathMLの非表示要素を埋め込むことにした。SVGにはaria-hidden=trueをつけて、MathMLにはdisplay:hiddenを指定する。そうすると、視覚系UAはSVGを表示し、非視覚系UAはMathMLを読むようになる。LaTeX形式の数式をそのままaria-labelに指定することも一瞬考えたが、LaTeXのコマンドをスクリーンリーダに読ませるのは無意味だ。MathMLならスクリーンリーダにもAIにも都合が良い。
ルビ対応
STGYのMarkdownはルビに対応している「{{小鳥遊|たかなし}}」と入力すると「
元来は読みにくい漢字に振り仮名を付けるためのルビだが、近年はダブルミーニングや説明や二つ名を文面で表現するのに使われる。「
細かい話なのだが、CSSのrubyの実装はかなり特殊だ。ruby要素はdisplay:inlineだが、rb要素はdisplay:ruby-baseで、rt要素はdisplay:ruby-textだ。ruby-baseとruby-textはテキストの並び方向に対して垂直に積み上げて並べられる。ruby-baseは他のインライン要素と同じ基準線で並べられるが、ruby-textは行間に追い出される。ruby-baseとruby-textの幅は双方の大きい方に合わせて拡張され、短い方はjustifyで両端合わせにアラインされる。この両端合わせのアラインメントが重要で、どこからどこまでがルビの対象範囲なのかをユーザが知る手がかりになる。このデフォルトのルールでルビの描写は概してうまくいくのだが、個人的に一点だけ気に入らないところがある。ruby-textが行間に追い出されたせいで、ルビがある行だけ行の高さが微妙に高くなってしまうのだ。これがださい。ruby-textのフォントを小さくしようとしても、ブラウザの最低フォントサイズの制限があるので0.5emより小さくはできない。transform:scale()を使おうとしても、displayがblockかinline-blockじゃないと効かない。displayを変えるとルビとしてのデフォルトのルールが破壊される。結局のところ、ruby-textにmargin-top: -0.8em; margin-bottom: -0.8em として負のマージンを付けることで、行高が変わらないようにした。line-height: 1.6くらいにしておくと、ルビは行間に収まるし、ルビが有っても無くても行間が変わらない。
余談。世界は表音文字と表意文字のミームが覇権を争う場だとみなせるが、現在、表意文字の旗色はすこぶる悪い。ラテン文字もギリシャ文字もキリル文字もアラビア文字も表意文字だ。広く使われている表意文字は漢字だけだが、朝鮮もベトナムも漢字の利用を止めて久しい。中国政府は生産性改善を標榜して簡体字を導入し、表意性を薄めてしまった。残る漢字の継承者である日本語においても、「ゲットする」「チェックする」「キーパーソン」など、表音言語由来の語彙が席巻し始めている。このままだといずれ漢字は絶滅し、表意文字も絶滅する。その視点でルビ文化の発展を見ると、それが表意文字の断末魔の叫びのように感じないだろうか。「
コメント対応
ここで言うコメントとは、Markdownの中には文字列があるのに、パースされるとそれが完全に無視されるもののことだ。HTMLの <!-- comment --> の記法と同じ役割である。本家Markdownにはコメント機能がないし、GitHubでもサポートされていない。無くても運用できると思われているのだろう。コメント機能がなくても、草稿執筆時のメモ書きや校正時の赤ペン入れは、おそらく適当なマークアップを割り当てて行えばよい。
東京の一極集中が進んでいる。現在、東京都の人口は1400万人%%(要確認)%%である。 %%以下は取材メモを見て後で直す%% 香川県民のうどん消費量が多いことは有名だが、糖質の摂取過多で糖尿病になる人も多いとの指摘がある。
これをHTMLにレンダリングすると、要確認というのがハイライトされて表示されるので、後でそれを見ながら修正を入れることになる。しかし、この方法は、公開前にしかできない。CMSであれば公開前の記事を保存してプレビューを見ながら修正することができるが、保存と公開が同義であるSNS上で指摘事項が見えてしまうのは格好悪すぎる。また、公開後にもコメントを残しておきたい場合もある。「この段落は羅生門のP128から引用」「2024年厚労省人口動態統計より」「ここは必ず断定調で書くこと」などのメモを付けておくと、後で編集する際に便利だ。それらは公開しても見えない状態でないと困る。
ということで、コメントに対応する方言を設けることにした。「<[」と「]> 」で挟まれた領域はMarkdownのパース時にコメントとして無視される。また、コメントだけからなる行は、行ごと無視される。行ごと無視するという制御がなぜ必要かというと、改行も含めて削ることで、リストやテーブルや段落の途中でコメント行を挿入しても構造が壊れないようにするためだ。
東京の一極集中が進んでいる。現在、東京都の人口は1400万人<[要確認]>である。 <[以下は取材メモを見て後で直す]> 香川県民のうどん消費量が多いことは有名だが、糖質の摂取過多で糖尿病になる人も多いとの指摘がある。
コメント機能があることで、投稿後の記事をAIに校正させて自動保存するのもやりやすくなる。AIに直接記事を書き換えさせるのではなく、校正内容をコメントとして書き込むように指示して、それを保存するのだ。STGYの全ての操作はAPIが公開されているので、ユーザが望めばそのようなワークフローを自前で作れるし、サービス側でそのような機能を提供しても良い。投稿前に校正するのであればハイライト方式でも良いのだが、投稿後に校正するのであればコメント機能は必須だ。
なお、実装上の注意点として、パース前にコメントを削ってはいけないというのがある。パース前に削るとノードの文字位置や行位置の値がずれるからだ。パースしながら、行を解釈する段階で行コメントを削り、インライン要素を解釈する段階でインラインコメントを削るという段階的な処理が必要になる。あと、セキュリティ上の注意もある。Markdownの解釈はクライアント側で行われるので、Markdown内のコメントもクライアントに送られている。HTMLとしてレンダリングされる際に表示されないというだけで、コメントが含む情報の秘匿性は全く無いということだ。「<[ゴミ映画だがスポンサーの意向で星3つ]>」みたいなコメントを迂闊に書いてはいけない。これはセキュリティホールじゃないかと言われそうだが、逆だ。SNS上に秘密情報を持たないというSTGYのセキュリティポリシーと合致している。
整形済みテキスト
本家Markdownでは、HTMLの<pre>に相当する整形済みテキストは、先頭にタブもしくはスペース4つを置くことで表現する。整形済みテキストが続くブロックで全部それをやらねばならないのは結構面倒くさい。よって、GitHubなどの多くのMarkdown実装では、ブロックを「```」だけの行と「```」だけの行で囲む仕様になっている。STGYでもそれを採用した。整形済みテキストの中で「```」を書きたい場合には、「````」で囲む。バッククォートの数は3つ以上ならいくつでも良い。
```
これは ペンです。
これも ペンです。
```これもGitHubと全く同じ記法だが、整形済みテキストにシンタックスハイライト機能をつけた。各種のプログラミング言語やデータ書式の文法に応じて自動的に文字色を変える機能で、Prismというライブラリを呼び出すことで実現している。シンタックスハイライト機能を有効にするには、開始の区切り文字を「```json」などのようにして、言語名を指定する。「c」「cpp」「javascript」「typescript」「python」「ruby」「sql」「json」「yaml」「html」などがサポートされている。この機能は必須という程ではないが、プログラマを惹きつける上では重要な機能だ。
```cpp
#include <iostream>
int main(int argc, char** argv) {
std::cout << "Hello, World" << std::endl;
return 0;
}
```通常、整形済みテキストは固定幅フォントで表示される。プログラミング言語ではなく、日本語や英語などの自然言語で詩などを書きたい場合には、言語として「natural」を指定する。そうすると、通常の可変幅フォントが使われる。
```natural
Fury said to a mouse,
That he met in the house,
"Let us both go to law: I will prosecute you."
```整形済みテキストの言語名の部分に「:small」「:large」「:bold」「:italic」などの修飾子を書くことができ、「json:small」とか「natural:large:italic」のように言語名と組み合わせて使うこともできる。
```:xsmall o sweet spontaneous earth ``` ```:small o sweet spontaneous earth ``` ```:large o sweet spontaneous earth ``` ```:xlarge o sweet spontaneous earth ``` ```:bold o sweet spontaneous earth ``` ```:italic o sweet spontaneous earth ```
構造化文書と言いながら、シンタックスハイライト表示ができたり、「大きい」「太い」といった見た目の概念が出てきているのは矛盾があると指摘されそうだ。しかし、整形済みテキストは名前の通り整形≒組版を内包している概念なので、一定の視覚的装飾は許容されるし、むしろ視覚的な利便性を提供しないと存在意義が薄れる。紙媒体の小説などでも整形済みテキストを挿入することは広く行われているので、それを率直に表現できることは重要だ。これまた、それができないと画像で代用されてしまってアクセシビリティが下がる恐れがある。
aria-label属性の値に"sql"とか"natural:italic"とかを指定して、非視覚系UAに対してスタイルの読み上げを促すこともできたが、止めた。しかし、それらの情報は文脈で判断できるように地の文を書くべきで、ハイライトやらaria-labelの読み上げやらに頼るべきではない。aria-labelの乱用は鬱陶しいだけだろう。
目次機能
長めの記事では、記事の冒頭に記事内の目次をつけたくなる。自分でリンク付きのリストを書いて目次にすることもできるのだが、面倒過ぎる。記事を更新した際に目次とずれるリスクもある。機械的にできるような作業を人間にやらせると著しくやる気が削がれるので、当然これは機械にやらせるべきだ。そこで、「<!TOC!>」という行を書くだけで、そこに目次が挿入されるようにした。
# トムソーヤの冒険 <!TOC!> ## トムのいたずらと冒険 ... ## ペンキ塗りの出来事 ...
すると、「<!TOC!>」の部分には以下のような目次が挿入される。ヘッダには自動的にIDが振られているので、各項目をクリックすると、ヘッダにページ内ジャンプすることになる。
<ul> <li><a href="h-1">トムのいたずらと冒険</a></li> <li><a href="h-2">ペンキ塗りの出来事</a></li> </ul>
細かい工夫がある。まず、目次を作るにあたって、「<!TOC!>」よりも前に出てきたヘッダは無視される。そうしないと、目次の中に記事自体のタイトルが含まれてしまうからだ。さらに、対象となるヘッダの中で最も高いレベルをリストの既定階層にして、それ以下のヘッダはネストして表示する。つまり、章毎のヘッダをH1で書いている記事であれば、H1が基底でH2やH3が字下げされてぶら下がる形になり、章毎のヘッダをH2で書いている記事であれば、H2が基底でH3が字下げされてぶら下がる形になる。
タグのUI
どんな内容の投稿があるか分からないので、SNSでは事前に作ったカテゴリを記事に付与するUIは現実性がないので、分類の要求にはタグで答えることになる。そのタグをどうやって入力させるかだが、タグ専用の入力フォームを作るのは避けたい。フォームが複数あると初心者が迷うからだ。初心者はタグのことなんて知らなくてよいのだ。でも、慣れてきた人にはタグを使って欲しい。Twitterが「#」でタグを表現する方法を編み出したのはそういう背景があったからだろう。私もそれをパクった。Twitterに慣れている人にとっては、「#」でタグを表現するというは覚えてもらいやすい。
しかし、Markdownにおいて「#」はヘッダを表現するメタ文字なので、タグと被ってしまう。仕方ないので、「文全体における空行を除く最終行が「#」で始まっている場合、その行をタグ定義とみなす」という特殊なルールになった。それをそのまま説明しても分かりにくいので「タグは最後の行に #takoyaki みたいに書いてね」と具体例だけで案内する。「あれ、# はヘッダだから衝突して困るのでは?」とか考えるのはソフトウェアエンジニアだけだろう。
「#nolikes」とか「#noreplies」とかいう特殊タグでイイネや返信を禁止する機能があるのだが、それらは大々的には宣伝せず。ヘルプの片隅にこっそり書くだけにする。その他にも、投稿単位でフラグを立てる機能を足すことがあれば、タグの体裁で指定させることだろう。重要なのは、ほとんどの人が使わないような機能をわざわざ誰もが目にするボタンやフォームにしないことだ。そうしないと、テレビのリモコンみたいな破綻したUIになってしまう。
ボタンが多いリモコンを批判したくせに、投稿フォームのメニューにはいっぱいボタンがあるじゃないか、と言われたら、激痛だ。それに対する弁明としては、入力フォームの上の余白に薄い色で表現することで、心理的負荷をできるだけ下げる努力をしていると言うしかない。PCのファンクションキーように、「それらのボタンは使わなくてもいいんだよ」という印象を抱いてもらえるようにしている。とはいえ、それらのボタンが折衷的で中途半端な存在であることは認めざるを得ない。ただ、Macbookですらファンクションキーは捨てられず、タッチバー化の目論見が失敗に終わったことから考えると、「一部の人だけが使うボタンが端っこにひっそりある」というUIも合理的な気もしてくる。ピアノだって、全員が88鍵を使いこなすわけじゃないけど、配列が論理的であり、使わない鍵盤が邪魔にならない位置にある分には、ユーザビリティの問題にはならない。使わない人には自然に無視され、使う人には役に立つ、という建付けが実現できれば、それは誰も損していないながら誰かが得しているので、パレート改善だと言える。
フォントと段落と字下げ
Markdownの話とはずれるが、一般的なWebブラウザ(Chrome、Safari、Firefox、Edgeなど)で有効なスタイルの話をここでまとめておく。まず、多くのブラウザのデフォルトのフォントサイズは16pxであるが、それはブラウザの設定で変えられる。弱視の人は24pxや32pxにするかもしれないし、視力と認知能力が異常に高い人は12pxや10pxにするかもしれない。そういったユーザの意図を汲み取りたい場合には、フォントサイズを絶対値で設定すべきではない。ルート要素にはフォントの絶対値を指定しないで、それ以外の要素のフォントサイズは全て相対指定(rem等)で指定すべきだ。しかし、そのエンジニアリングコストは非常にに高くなるので、STGYでは、フォントサイズを固定値16pxにした。
とはいえ、弱視の人々を切り捨てているわけではない。一般的なブラウザは表示倍率(zoom)設定を備えていて、それを大きくすればフォントも大きくなる。それでも画面表示が崩れないようにレスポンシブデザインを徹底している。フォントの可変性は諦める代わりに、表示倍率に対しては柔軟なので、識字に関するアクセシビリティは確保できていると考えている。フォントだけを拡大するのとページの倍率を拡大するのでは、画像などのGUIパーツが一緒に拡大されるかどうかという違いがある。実用上はページ倍率を変える方が便利なので、最近のブラウザはページ倍率を変えやすいUIになっている。規定のフォントサイズを16pxに固定すると、emとremが同じ効果になるので、エンジニアリングコストが低くできる。ユーザが損しない中で、開発者が楽になるので、パレート改善だと言える。
STGYの主たる画面であるユーザ一覧画面、ユーザ詳細画面、投稿一覧画面、投稿詳細画面では、主たる領域の幅は最大768pxにしている。Tailwind CSSの「max-w-3xl」という設定である。768px / 16px(=1em) = 48emなので、「m」を最低48個並べられる幅という定義になる。しかし、実際に「m」が入る個数はフォントによって異なるわけで、48という数字に厳密な意味はない。日本語の文字が45文字くらい入ることが多いという経験則を私は持っていて、それが私にとっては最も読みやすい幅だ。それより狭いと窮屈な感じがして、それより広いと視線が迷いがちになる。768ピクセルというと、HD解像度(1920×1080)でも余裕があり、2025年現在のノートPCで一般的なWQHD(2560x1440)とかだと、ページ倍率150%(768*1.5=1152)にしても、画面に2つ横並びにできることになる。画面解像度に応じてページ倍率を適宜変えてもらうことで、文字の読みやすさも画像の見やすさも一定水準に達すると目論んでいる。
とにもかくにも、投稿記事の本文において、日本語で45文字の幅で地の文が描写されるというのが、以後の画面設計の指針になる。それを基準とすると、行高(line-height)は1.6が望ましい。あくまで私の主管だが、1.6より低いと窮屈な印象になり、高いと間延びした印象になる。多くのブラウザのデフォルトの1.2は明らかに低すぎるし、それだとルビが行間に収まらない。リストや引用の行高は1.5にし、整形済みテキストの行高は1.4にするなどの微妙な調整もしている。これは私が多数の文章を読む中で最適と思っている設定である。段落間のマージンは1.1ex(≒0.55em)にしている。そうすると、段落内改行と比べて明白に開きがあるので段落区切りとして視認できつつ、間延びしないでスクロール量を低減できる。ヘッダの垂直マージンは、1.1ex * 1.05 / fontSize という式で設定していて、どのレベルのヘッダでも、段落区切りよりほんのちょっと大きいけど間延びしない高さになっている。構造化文書の主たる視覚モーダルとしては、地の文とヘッダの視認性の良さこそが命である。
ここで、段落とは何かということを改めて考えてみたい。文とは、述語とそれに紐づく主語の組だ。接続詞などを使って連結できるとはいえ、一つの文だけで言いたいことをまとめられるわけではなく、無理にそうするべきでもない。段落は、複数の文を意味的にまとめた単位であり、その段落だけ切り取っても、言いたいことがだいたい伝わるようになっている。読者は、段落を読解の基本単位と捉えることが多く、基本的には一つの段落は一息で読む。ゆえに、段落の区切りを明示することは、構造化文書が果たす最も基本的かつ重要な役割である。
段落の区切りを明示する方法は、たくさんある。古くから、英語などのヨーロッパの言語では、段落の始めで4文字分くらいの字下げ(インデント)によって段落区切りを示していた。インデントを置く場合には、段落の間には空行を置かないのが基本だ。一方で、日本やその他の東アジアの縦書き文化圏では、字下げなど特にせずに、行頭から文が始まれば段落であるという扱いであった。その方式だと、折り返しの都合でたまたま文頭が行頭に来たのか、段落の始めだから文頭が行頭に来たのかは、判然としないことになる。しかし、内容でだいたい察せるので、それで問題になることもなかった。ただし、日本においては、明治期に欧文に習って段落の始めに字下げをするという風習が導入され、学校教育では今でも段落の冒頭では1文字文の字下げをするように指導されている。
さて、コンピュータ上で書くデジタル文書においては、欧米でも東アジアでもその他の地域でも、字下げによって段落区切りを示す風習は衰退しつつある。代わりに、上下のマージンによって段落区切りを示すのだ。CNNもBBCもAssociated PressもJapan Timesも、段落に字下げを使っていない。私の観測範囲のほとんどのWebサイトはそうだ。ここで、私は迷った。段落の始めは字下げをしないと減点される教育を受けてきたので、たとえマージンが有っても、なんとなく字下げをしたくなってしまうのだ。実際、そう思っている人も一定数居るようで、だからこそGoogle DocsにもMicrosoft Wordにも自動字下げ機能がある。紙媒体の新聞(読売、朝日、毎日、産経など)のWebサイトでは、各段落の冒頭に全角空白を置くことで字下げしている。欧文由来の字下げ文化が、欧米ではほぼ絶滅したのに、日本の旧メディアでだけ生き残っているというのは興味深い。この現状を考えると、SNSの投稿のデフォルトのスタイルとしては、字下げを行わない方が良いだろう。p { line-height: 1.6; margin: 1.1ex 0; } というスタイルが現状で最善ということだ。各ユーザがどうしても字下げしたい場合には、全角空白を使ってもらおう。
モバイル対応
Markdownと直接の関係はないが、UI改修のついでに、モバイル端末での見栄えも調整した。投稿一覧画面、ユーザ一覧画面、ユーザ詳細画面のそれぞれでは、タブを切り替えることで一覧の対象となるデータの種類を切り替えられるようになっているのだが、タブ表示は横幅を取るので、モバイルの狭い画面だとタブを並べきれないのだ。PCのブラウザで表示を確認しながら開発すると起きがちな問題である。レスポンシブデザインなので、多少の幅の増減は問題ないのだが、モバイルはめちゃくちゃ狭いので対応できない。そこで、Tailwind CSSの画面幅セレクタ機能を使って、各所に最適化を施した。余白を削ることから始め、ラベルを短くしたり、scaleXで幅だけ縮小したりの工夫をした。それでも駄目なら、使用頻度が低いアイコンを削ることまでした。UA毎に機能性を変えるのは望ましくないのだが、適切に表示できないのでは仕方がない。
![]() | ![]() | ![]() |
苦労の甲斐があって、そこそこ見やすいUIに仕上がったと思う。画像は小さめに表示して、タップすると拡大表示できるようにした。画像が画面全体を締めると、スクロールしないと本文が読み進められなくなるからだ。せっかくの構造化文書なので、本文を読みやすくすることに注力した。
カジュアルユーザ→パワーユーザ→インフルエンサーのピラミッド
SNSにおいては、カジュアルユーザもパワーユーザも大切にする必要がある。典型的なカジュアルユーザは、主にSNS上のコンテンツを読むことに魅力を感じて訪問する。自分で記事を書くこともあるが、内輪ウケや挨拶レベルの情報交換以上の価値を見出していない。彼らは自分と同等のカジュアルユーザと気軽なコミュニケーションをする一方、パワーユーザが投稿する記事も読みたいと思っている。多くのユーザに注目されるパワーユーザはインフルエンサーと呼ばれる。インフルエンサーが居ればカジュアルユーザも集まり、それがモチベーションとなってインフルエンサーが居着くようになる。この好循環を獲得できるかどうかが、サービス成功の鍵を握る。
パワーユーザの全てがインフルエンサーになるわけではないが、一定の頻度と分量で記事を投稿するパワーユーザでないとインフルエンサーにはなれない。ユーザの全てがパワーユーザになるわけではないが、まずはカジュアルユーザとして居着いてもらわないとパワーユーザにはならない。よって、カジュアルユーザの快適性を上げることが必要だ。それには、カジュアルユーザ同士のコミュニケーションを促進するだけでは不十分で、インフルエンサーの面白い記事が目に触れやすいようにする仕組みが必要である。Twitterのリポスト(リツイート)機能はその典型だ。STGYではまだリポスト機能をつけていないが、いずれ実装することになるだろう。それ以前に、そもそも面白い記事が存在しなくては意味がない。よって、記事を気持ちよく執筆して投稿できる仕組みが不可欠だ。
結論はこうなる。カジュアルユーザが居着いてくれるように、挨拶やちょっとした呟きを快適に書ける必要がある。カジュアルユーザがパワーユーザになれるように、やや高度な構造の文書も快適に書ける必要がある。そして、クリエイターとかインフルエンサーとか呼ばれるような人たちに、その知性と感性を存分に表現できる場として選んでもらえるように、競合に優る表現力と生産性の投稿機能が存在する必要がある。ボタン等の利用頻度を数える単純なユーザ行動分析で各種機能の重要性を測ると、サービスやユーザコミュニティにとって本当に何が大切なのかを見失う可能性がある。SNSでは、数は少ないパワーユーザもしっかり支える必要がある。Markdownの採用だけでその条件が満たせるわけではないが、有力な一手であると私は考える。
まとめ
STGYのユーザプロファイルと投稿記事の本文の書式としてMarkdown形式を採用した理由は、全ての習熟度のユーザに使いやすい形式だからだ。何も知らない人がプレーンテキストとして書いても良いし、慣れてきたらヘッダと太字だけ使って、物書きレベルになると構造化文書として使える。マルチモーダルなUAが一般化してきた昨今、WYSIWYGという概念は破綻しつつある。よって、Markdownに任意のプレビューを組み合わせるというUI設計は当世風だと言えよう。それより何より、私は構造文書が好きなのだ。そして、構造化文書を表現できるマークアップは各種あるが、表現力と簡潔さのバランスが取れたMarkdownが最善だと思う。
SNS上で長文の随筆やら論文やら小説やらを書く奴は居ないだろと突っ込まれるかもしれない。しかし、このSNSはTwitterやFacebookのような汎用SNSを狙っているわけじゃない。企業単位で使ってほしいし、大学の学部単位とかで使ってほしいし、物書きの同人サークルで使ってほしい。閉じたコミュニティにおけるより濃い知的交流を支援するには、執筆活動の生産性を上げることは大きな利点になる。私はMarkdownが好きである以上に、職業人や趣味人として何かを作り上げている人達が好きだ。彼ら彼女らの役に立つものを作りたいのだ。


