| @ブログ

ダークモードとライトモードの切り替えをグローバルナビゲーション(上の方の半透明の白い領域)から簡単に行えるようにした(これまではこのサイトについてのページで切り替える必要があった)。デフォルトは OS の設定準拠で、 OS がダークモードであればダークモードに、ライトモードであればライトモードで表示される。手動でテーマを切り替えると Cookie に設定値を保存する。機能と見た目は MDN Web Docs を参考にした。

CSS がぐちゃぐちゃなのでかなり難儀した( 3 年前にも同じことを書いている)。ダークモードとライトモードの切り替えなんて自分しかしていないと思うがかなり満足度の高い休日プログラミングだった。

| @ブログ

最初にブログを作ったときからウェブサイトのタイトル(やロゴ画像)が h1 で、記事タイトルが h2 という見出しレベルで HTML を書いていた。しかし最近では、記事パーマリンクのページではサイトのタイトルなどには見出しレベルを設定せず、記事タイトルに h1 を当てている場合が多いようだ。なのでこのサイトでも記事タイトルを h1 とするように変えた。本文中の見出しレベルも h3 スタートだったのを h2 スタートに変えた。

伝統的なブログはインデックスページと記事パーマリンクページで HTML テンプレートを共通化している。なのでインデックスページに記事一覧を表示して h1 タグが並ぶとまずいということで記事タイトルは h2 から、という作りになってるような気がする。このサイトはインデックスページとパーマリンクページでのテンプレート共有化をほぼほぼやめたので、インデックスページとパーマリンクページで記事タイトルの見出しレベルを柔軟に変更している。

サイトの作り手からするとウェブサイトのタイトルこそが最も重要な要素でタイトルロゴなどを h1 でマークアップしたくなるのだが、読み手は Twitter やはてブから飛んできて刹那的に記事を消費し、インデックスページなんかには見向きもせずに去って行くだけだ。個別記事のタイトルこそ重要なのだ。

追記

r7kamura さんからこういうコメントをもらってこういう風に返信した。

HTML5 が出てきたとき、個人的には何かめんどくさいなぁとしか思ってなかったし、世間は Flash を置き換える近未来技術みたいな評価をしていたと思う。しかし、 <header> タグや <article> タグによって、 HTML の構造化と文書の構造化を分離できるようになったのがセマンティックWeb的なメリットだということに気がついた。つまり <h1> などの見出しルールは <article> タグの中で守られていればよいのだ。

ということに HTML5 が死んでから気がついた。

| @技術/プログラミング

Archives ページでチャートのカテゴリー選択とセレクトボックスのカテゴリー選択が連動していなかったのを統合して連動するようにした。以前、やり方がわからなくてチャートのカテゴリーのレジェンドをクリックしたときにクリックされたカテゴリーをチャートから非表示にしつつ色をグレーアウトさせるのもできるようになった。どのカテゴリーの記事をいつ頃どのくらい書いていたかがわかるようになってめっちゃ便利。

Archives ページは React で作っていて、チャートとセレクトボックスでそれぞれに別々にカテゴリー一覧を API から取得していたのを一本化し、非表示とするカテゴリーも同じ state として管理するようにした。こういうのがサクッとしかも高速にできて React は便利。 jQuery でやるのは大変だった。

| @ブログ

Composing HEY World

メールを送るだけでブログを書ける HEY World はとても体験が良い。入力しなければならないのはタイトルと本文だけ。カテゴリーやタグを選んだり、公開時の URL を選んだり、日付を設定したりできない。しかしそのせいで内容に集中できる。

ブログは万年筆のように書き味が大事だと思う。 HEY のメール作成画面は飛び抜けて良いわけではないが、ほどほどに良い。残念ながらこのブログの投稿欄よりも良いのは確実。別のエディターで下書きして貼り付ける手間がなく、いきなり書いて Send ボタンを押すだけでブログを公開できるのはとにかく便利。下書きはメールの下書きとして保存すればよく、出来上がったら world@hey.com に対してメールを送信する。ブログを書きたいけど管理画面にログインするのが面倒くさいとか、小さなフォーム入力欄で文章を書くのがかったるいというような、ブログを書くための障害をあらかた取り除いている。

メールはスパムによって程度の低い通信手段にされてしまったが、メールによって情報発信をする手法は見直されて良いと思う。昔はモブログという概念があって、ガラケーからメールでブログ投稿できる機能を備えてるブログサービスがあった。このブログにもメール投稿の機能を付けてみたいと思った。

| @WWW

朝の月

Twitter のスレッド機能で、投稿前の下書き段階からスレッド状態で長い文章を推敲しながら書くことができることを最近知った。推敲して長い文章を書けるのならブログを書く必要がないのではないか。これを知って自分は、 Twitter はブログの息の根を止めようとしているのだなと感じた。

スレッドで長めの文章を下書き状態で書きためている様子

スレッドの誕生

スレッドは 2017 年にリリースされていた。

確かにこの頃から長文を連投で投稿する IT 社長みたいなのをよく目にするようになった気がする。「フロハ」とか「ガバリ」とか「making coffee」とか書いてた頃の Twitter とは異世界になってしまった。

リリースノートによると、ユーザーが自分のツイートにリプライを書いて長い文章を書いている使い方に着目し、それをしやすくする機能としてスレッドを開発したようだ。長い文章を書けるようになったことで、それまで誰とも競合せず独自の市場( Jaiku など同種の競合はいたがプラットフォームが持つ強力なネットワーク効果で蹴散らしてしまった)にいた Twitter がブログの世界に進出してきたのだ。

ブログの衰退

トラックバック

ブログでのコミュニケーションはとても衰退してしまった。いまでは信じられないかも知れないが、昔はブログにコメント欄やトラックバック欄があった。コメントはともかくトラックバックって何だと思う人はいるかもしれない。むかしのブログでは、誰か他の人の記事を参照して記事を書いたときにトラックバックする、という文化が存在した。

トラックバックのない世界

例えば A さんがうどんについての記事を書いていたとする。その記事を参照しながら B さんがそばについての記事を書いた。このとき、 B さんの記事から A さんの記事に対してリンクを張ることは可能だが、先に作成された A さんの記事から B さんの記事にリンクを作成することはできない。 A さんは自分の記事が B さんから言及されていることに気づくこともできない。関連した話題や言及されていることに A さんおよび A さんのブログの読者が気づくことができないのだ。

トラックバックの正しい使い方

この問題を解決するのがトラックバックという仕組みで、 B さんのそばの記事から A さんのうどんの記事に対してトラックバックを送ることで、 A さんの記事内に B さんの記事へのリンクが表示される。 A さんは自分のブログに言及されていることを知ることができるし、 A さんのブログの読者は関連記事として B さんが書いたそばについての記事があることを知ることができる。

トラックバックボム

迷惑トラックバック

この仕組みは節度のある人だけがブログをやっていた時期には良かったのだが、徐々に相手の記事に言及することなく、自分のサイトへの誘導のためにトラックバックを送信する不届き者が出てくるようになった。 A さんのうどんの記事に B さんのそばの記事がトラックバックを送るのはまだわかるとして、 C さんが書いたバイクについての記事からトラックバックが届くとなると、全く話題に関連性はないし、バイクの記事から A さんのブログにリンクすることもないだろう。

こういうネチケット違反をする人だけではなく、最終的にはアフィリエイト目的で相手のブログと全く関係ない記事なのにトラックバックを送信するスパマーによって悪用されるようになり、トラックバックという文化は廃れてしまった。

議論の場となる Twitter

トラックバックが死ぬことで、ブログ上で議論するということがしづらくなった。 A さんのうどん記事に対して B さんがそばこそ至高という記事を書き、トラックバックを送った上で議論を挑むことができたのが、トラックバックがないのでネットの端っこでかみつくだけか、 A さんのブログのコメント欄に登場して議論をふっかけるしかない。しかしコメント欄もトラックバックと同じように衰退した。スパムのせいだ。静的サイトジェネレーターで生成されるブログではトラックバックはもちろんのことコメント欄も存在しない。ブログは議論の場として機能しなくなってしまった。

Twitter が流行ったからブログが廃れたという意見はかつてよく目にした。しかし Twitter が流行ったからというより、コメントやトラックバックという文化がスパマーによって破壊されてしまい、 Twitter の手を借りるまでもなくブログは勝手に死んでいったのだ。 A さんのうどん記事について「そばこそ至高」と言いたい人は、 Twitter で言及するしかなくなってしまった。この流れを加速させて、そもそも A さんも Twitter でうどんの話をするようにしたくて、 Twitter はスレッドを機能化することにしたのだろう。

コンテンツとの出会いの場としての Twitter

多くの人にとって、コンテンツとの出会いの場がポータルサイトやまとめサイトから、個々人のタイムラインに変わりつつある。みんなで同じ記事を見るのではなく、それぞれの小さなサークルの中でコンテンツを共有し合う感じだ。

いま、記事がバズったときのナンバーワンの流入元は Twitter だ。以前だったらはてブだったけど、はてブでホッテントリに入るよりも SNS でバズることの方がアクセスが集まりやすい。

はてブは一人にブックマークされただけではあまりアクセスが来ることはなく、矢継ぎ早に数人からブックマークされてホッテントリに入らないとバズれない。しかもホッテントリに入ったところではてブからのアクセスは精々 1 日で途絶えてしまう。みんなで一つのホッテントリを見てるので次々に新しい話題が出てきて、一つの記事がはてブのネットワーク内にとどまれる時間が短い。

一方で Twitter は、一人がシェアしてくれただけで割とアクセスがあり、フォロワーが沢山いるインフルエンサーによってシェアされるとあっという間に大量の流入をもたらしてくれる。しかもユーザーはそれぞれバラバラのタイムラインを見ているので、バズったときにネットワーク上にコンテンツが滞留する時間が長い。 Twitter 自体がタイムラインを単純な時系列順にせず複雑化させているし、一つの記事を別々の人がシェアすることや、リツイートの仕組みによって何度も人の目に触れさせることが可能になっている。おかげで一度バズると一週間くらいは流入を提供してくれる。

スレッドの最大の狙いは外部への離脱の抑制のはずで、これまでブログ記事や動画など、外部のコンテンツを参照する側だった Twitter が、スレッドによって長くまとまった分量のコンテンツをプラットフォーム内に持てるようになり、外に対してトラフィックを流すのではなく、プラットフォーム内にユーザーのアテンションをとどめておけるようになった。コンテンツとの出会いも消費も Twitter 内部で完結させたい、というのが Twitter の意図なはずだ。

コンテンツの発見も消費もタイムラインで

タイムラインの滞在時間を最大化し、一つでも多くの広告を見てもらうことが Twitter のビジネスモデルにとって重要なはずだから、スレッドによるブログ殺しでバズの矛先を外部のブログではなく Twitter の内部とし、一人たりとも Twitter の外に逃したくないのだろう。

かつて日常について呟く場所だった Twitter が、日常についての短い文章に加え、長めの論説調の文章も有するメディアに変容しようとしているのだろう。プレースホルダーが "What are you doing?" から "What's happening?" に変わったのと同じ事情がそこにはある。

日常の出来事をブログに書く意義

こんにち、日記のような軽いブログ記事を見かける頻度がとんと落ちている。昔はもっとみんなライトにブログを書いていた。しかしそういうライトなブログは Twitter や Instagram などの SNS に飲み込まれてしまった。いまブログといえば、ある程度の分量のある熱のこもった記事か(暇な素人による社会時評とか)、芸能人のアメブロか、アフィリエイトか、プロが書いた商業的な記事しかない。普通の個人が書いた軽い記事を公開しづらい雰囲気が醸成されつつある。

ヒトデさんが年末にこういう記事を書いていた。

#100DaysToOffload もこの考え方に通じるところがある。難しく考えずに、気軽にアウトプットすればよい。

この感覚はとても重要で、いま我々は努めて軽いブログ記事を書くようにしないと、商業メディアや Twitter に飲み込まれて個人の簡便な意思表明がしづらい流れが固定化されてしまう。その日食べたもののことでも、その日見たテレビのことでも、その日読んだ本のことでも、その日遊んだゲームのことでも、何でもいいから SNS 以外の場所にも書くことが大事なのだ。 #100DaysToOffload のハッシュタグを付けて Twitter に何かを投稿するのは一見矛盾しているようで、 Twitter に過集中しつつあるインターネットのアテンションを再び個人ブログに取り戻そうという取り組みでもある。

なので皆さん、スレッドのご利用はほどほどにして、ブログを書きましょう

| @ブログ

iPad を持っていないので確認していなかったのだけど、タブレットなど狭めの横幅のブラウザーでこのサイトのインデックスページを見ると残念な感じになっていたのでいい感じに調整した。横幅 1113px 以上だと past-entries セクションが 3 カラム表示になり、 1112px 以下だと 2 カラム表示に、 640px 以下だと 1 カラム表示になるようにした。これまでは 640px 以下のときの 1 カラム表示対応しかなくて、横幅が狭いブラウザーで見たときに悲惨なことになっていた。

デスクトップ表示

タブレット表示

スマートフォン表示

その他、フッターの人気記事表示を変更した。インデックスページに最近の人気記事とはてブでホッテントリ入りした記事を表示するようにしたので、同じコンテンツがフッターにあるのは無駄だと感じた。かわりにフッターには今日と昨日の人気記事を表示するようにした。

今日の人気記事と昨日の人気記事

よく読まれる記事の傾向はその日その日で結構違う。新しい記事を書くと当然その記事にアクセスが集まるのだけど、しばらく何も書いていないと意外な記事がアクセスを集めてたりして発見がある。例えば最近では Flickr の有料化についての記事がアクセスを集めていたが、 Google Photos の有料化が発表されたからだった。いっぱい記事を書いておくと、自分のブログへのアクセス傾向から世の中の動きが確認できて便利だ。

| @ブログ

インデックスページをいじって各カテゴリーの最新記事 4 件を配置するようにしてみた。最近の個人サイト復興ブームでみなさんインデックスページを工夫されているのを見ていて真似したくなってやった。

カテゴリーごとに最新記事 4 件を表示

昔ながらのブログだとインデックスページというのは最新の記事 10 件くらいが表示されていて、「次へ」を押すと古い記事が出てくるという構成になっている。以前のこのブログもそうだった。

しかし自分自身が他人のブログで「次へ」を押して次々に記事を読んでいくということをやった記憶がほとんどない。自分のブログでだって何か目的があって特定のキーワードで検索したあとに引っかかった記事を読むという感じなので、時系列に本文とセットで記事が 10 件ずつ表示される UI というのは意味をなしていないと思った。そもそもインデックスという名称なのに最近の記事数件しか表示していないのはおかしい。インデックスというからにはすべての記事の目次になるべきだ。

このブログはカテゴリーがあるので、サイトマップを作るとするとこんな感じになると思う。

+----------+        +------------+        +-----------+
|          |        |            |        |           |
|   Blog   +---+--->+  Category  +------->+   Entry   |
|          |   |    |            |        |           |
+----------+   |    +------------+        +-----------+
               |
               |
               |    +------------+        +-----------+
               |    |            |        |           |
               +--->+  Category  +---+--->+   Entry   |
                    |            |   |    |           |
                    +------------+   |    +-----------+
                                     |
                                     |
                                     |    +-----------+
                                     |    |           |
                                     +--->+   Entry   |
                                     |    |           |
                                     |    +-----------+
                                     |
                                     |
                                     |    +-----------+
                                     |    |           |
                                     +--->+   Entry   |
                                          |           |
                                          +-----------+

第一階層がインデックスページで、第二階層がカテゴリートップ、そして各記事がある。なのでインデックスページは二階層目の一覧ページになっているのが望ましいはずだ。しかし伝統的なブログはカテゴリーという記事をまとめる概念がありつつも、インデックスページから各記事ページへ直接遷移するのが主な導線だった。常に最新の記事が時系列順に並んでいるだけでは味気ないし、常連の読者ではないコンテキストを知らない訪問者には不親切だろう。

しかも SNS の隆盛で個人のブログのインデックスページが参照される機会というのはとんとなくなってしまった。個人が書いたブログ記事は SNS 経由で読まれ、個別記事だけが読まれる。インデックスページやトップページが読まれることはほとんどない。 SNS でシェアされている URL をクリックして個別記事を読んで、それ以上そのブログのほかの記事を読むことなく離脱してしまう。前後のコンテキストは無視して、一つのコンテンツだけがつまみ食いされてしまう。そんな流れにあらがいたいと思った。

これまで関連記事を記事下に表示するなどやってきたが、気に入っていくつか記事を読んで「ホーム」( = インデックスページ)を訪れたユーザーがもう少しブログを深掘りしてみたくなるようにインデックスページを各カテゴリーの最新記事一覧とするようにしてみた。このブログは現在カテゴリーが 13 個あるので、それぞれから 4 件ずつ記事を取得すると 52 記事になる。全カテゴリーからまんべんなく 4 記事ずつ取得して表示するのは簡単なようで結構難しい。普通の SQL ではできない。 OR マッパーではまず無理だろう。

いろいろ調べてみた結果、 MySQL では GROUP_CONCAT というのが使えそうだった。以下のような SQL を書いた。

select entries.id
from entries
inner join (
  select
    category_id,
    GROUP_CONCAT(id order by created_at desc) as entry_ids,
    max(created_at) as last_created_at
  from entries
  where entries.draft = false
  group by category_id
) as grouped_entries
on grouped_entries.category_id = entries.category_id
and FIND_IN_SET(id, entry_ids) between 1 and 4
order by last_created_at desc, entries.id desc;

GROUP_CONCATFIND_IN_SET という関数を組み合わせることで、各カテゴリーから作成日の降順に記事を 4 件ずつ取得できた。このクエリでは記事 id のみ取得して、もう一回 DB に記事を取得するクエリを ActiveRecord で投げる。 ActiveRecord でクエリを組み立てるときは N+1 が起こらないように関連テーブルを JOIN する。

query = <<~SQL
  select entries.id
  from entries
  inner join (
    select
      category_id,
      group_concat(id order by created_at desc) as entry_ids,
      max(created_at) as last_created_at
    from entries
    where entries.draft = false
    group by category_id
  ) as grouped_entries
    on grouped_entries.category_id = entries.category_id
    and find_in_set(id, entry_ids) between 1 and 4
  inner join categories on categories.id = entries.category_id
  order by last_created_at desc, entries.id desc;
SQL
entry_ids = ActiveRecord::Base.connection.select_all(query).rows.flatten
entries = Entry.includes(:category, :user, :tags, :comments).where(id: entry_ids)

PostgreSQL のときに最初に取得した entry_ids の並び順通りに結果が受け取れるかは怪しいが、 MySQL の場合は一回目のクエリで取得した id 順に各レコードが ActiveRecord のクエリ結果として取得できた。あとはこれをカテゴリーごとにグルーピングして View でよろしくやれば良い。

なお各カテゴリーはカテゴリー内の最新の記事の作成日で降順ソートするようにしている。例えば現在のインデックスページの最下部には音楽カテゴリーがあるが、これは音楽についての記事を最後に書いたのが一年以上前だからだ。もしいま音楽の記事を書けば音楽カテゴリーがトップに浮上するようになっている。

見た目に関しては各カテゴリーの記事最新一件は大きなサイズで表示している。最も最近書かれた記事なのでより多く人の目に付いた方がよいだろうという考えだ。またすべての記事にサムネイルというか、アイキャッチ画像を表示するようにした。画像がない記事に関してはデフォルトのサイトアイコン画像を表示するようにしている。やっぱり視覚的に情報を捉えられるのは重要だ。画像がごちゃごちゃ表示されるのを嫌う人もいるかもしれないが、テキストだけでは人間の認知というのはどうしても追いつかない。

あわせて今回、インデックスページの冒頭部にこのサイトについての説明文を載せることにした。ながしまきょうさんr7kamura さんがやっているののパクりだ。伝統的なブログのインデックスページは初めて訪れた人のことを無視しすぎていたと思う。そのブログ自体について説明するページがあるブログは少ない。最初の記事でブログを始めた経緯みたいなことが書かれたきり、そのブログは何なのか、誰が書いているのかが書かれることは希だ。きちんとブログについての説明ページと著者についての説明ページがあっても、左右のサイドバーやトップのナビゲーションの端っこに押し込まれて見られることはない。これではいけないだろう。というわけでインデックスページの一番目立つ位置にブログと自分自身の簡単な紹介を入れた。

インデックスページトップに紹介文を表示

ブログはなぜ衰退したかを考えてみると、 Facebook や Twitter の隆盛はあるにせよ、ブログ自体に初めて訪れた人に読まれるための工夫が欠けていたのだと思う。誰も自分のブログの継続率を計測したりコホート分析したりはしない。読者が前後の記事を読んでいることを前提に書かれた記事やサイト構成では初めて訪れた人はどうやっても離脱してしまう。特に書き手が芸能人でもない一般人の場合はなおさらだ。誰も RSS フィードを購読していないし、ほとんどの読者は初めて訪れる人なのだから、そういう人たちが読んでブログのテーマや著者の人となりが分かる構成にしていかなければならないのだと思う。でないと SNS でたまにバズったときだけ読んでもらえる、ソーシャルメディアの肥やしにしかならない。

この新しいインデックスページが正解なのかどうかは分からないが、ブログ衰退の流れにあらがっていきたい。