作業中に気づいたことを、その場で短く書き残したいときがあります。1つの判断や、小さな修正だけなら、長文記事の構成には合いません。
別の投稿サービスへ分けるのではなく、自分のブログに「ショート」という短い投稿欄を作りました。同じサイトなら、デザインとタグを記事と共有しながら、見せ方だけを分けられます。
この記事では、長文記事とショートを同じHugoサイトへ載せるため、表示方法をどう分けたかを書きます。対象は、投稿種別、一覧内の共有URL、追加投稿の表示、共通タグの4点です。確認したのはHugo v0.164.0(2026年7月時点)です。
「Hugo移行記」のうち、記事とショートの公開画面を扱う記事です。先行記事を読まなくても、この記事だけで分かるように書いています。
まず全体像
保存場所と表示種別を分けた
Hugoのセクションは、基本的に content/ 直下のフォルダで分かれます。このブログでは、記事を content/posts/<年>/、ショートを content/shorts/<年>/ に置きました。
ショートのfront matter(投稿冒頭の設定欄)には、表示種別を示す type: "shorts" を書いています。
---
title: "ショートを、一覧の流れを残したまま共有できるURLにした"
date: 2026-07-29T09:00:00+09:00
slug: "short-list-anchor-urls"
type: "shorts"
tag: ["Hugo", "UI設計"]
icon: "🔗"
---
type は、どのテンプレートで表示するかを選ぶための値です。公開後のショートは保存場所だけでも判別できますが、下書きでは事情が変わります。
ここでのテンプレートは、投稿データからページのHTMLを作るファイルです。front matterの slug は、URLに使う識別名を表します。
このブログは、未公開の投稿を content/drafts/ に置きます。下書き中のショートは content/drafts/shorts/ にあるため、保存場所だけを見ると記事の下書きと同じ drafts セクションです。
そこで、一覧を作るテンプレートでは Type も見ています。
{{ $articlePages := where
(where site.RegularPages "Section" "in" (slice "posts" "drafts"))
"Type" "ne" "shorts"
}}
記事欄には、posts または drafts にあり、表示種別が shorts ではない投稿を出します。ショート欄には、保存場所にかかわらず Type が shorts の投稿だけを出します。
保存場所は公開状態、type は表示方法を担当します。この分け方なら、下書き確認でも公開後と同じショート用のカードを使えます。
共有URLはショート一覧の中を指す
Hugoは、ショートにも日付とslugを使った個別ページを生成します。
/shorts/<年>/<月>/<日>/<slug>/
ただし、カードの選択とコピーボタンで共有するのは個別ページではありません。ショート一覧の中にあるカードの位置を、URL末尾のアンカーで指します。
/shorts/#short-<固有ID>
カードのHTMLでは、同じ固有IDを id と共有URLの両方へ使っています。
<article
id="short-{{ .File.UniqueID }}"
data-short-url="{{ "shorts/" | relURL }}#short-{{ .File.UniqueID }}">
.File.UniqueID は、Hugoが投稿ファイルから作る固有IDです。HTMLの id は、一覧内でカードの位置を特定するために使います。
カードを選ぶと、ブラウザで動くJavaScriptが画面を移動せずにアドレスバーのURLを更新します。直接そのURLを開いたときは、ブラウザが該当カードまで移動し、JavaScriptが選択枠を付けます。コピーボタンも同じ一覧内アンカーを返します。
個別ページをなくしたわけではありません。Hugoは個別ページを生成したまま、カード選択とコピーボタンから使う共有URLだけを一覧へ向けています。共有された1件を読んだあと、そのまま前後のショートへ移れることを優先しました。
追加投稿はHTMLコメントで区切る
同じ話題に進展や訂正があったときは、元の文章を消さず、同じショートへ追加投稿を足します。
区切りには <!--thread--> というHTMLコメントを使っています。
最初の投稿本文。
<!--thread-->
追加投稿の本文。
ショート一覧のテンプレートは、この文字列でMarkdownを分割します。最初の投稿は常に表示し、それ以外の投稿は「スレッドを開く」の中へ並べます。個別ページでは、すべての投稿を最初から表示します。
Hugoのショートコードを使わなかったのは、本文へHugo専用の呼び出しを入れないためです。別のツールへ移る場合は同じ分割処理が必要ですが、区切り文字と本文はMarkdownファイルに残ります。
タグは記事とショートで共有する
長文記事とショートは、同じ tag を使います。たとえば Hugo タグのページには、Hugoについて書いた記事とショートの両方が集まります。
同じ一覧へ混ぜて並べるのではなく、上部の「記事」「ショート」で表示を切り替えます。
/tag/hugo/?type=posts
/tag/hugo/?type=shorts
テンプレートは各項目へ、記事かショートかを表す posts または shorts の値を付けます。JavaScriptはURL末尾の type を読み、選ばれた側だけを表示します。
記事にはカテゴリとシリーズもありますが、ショートはタグだけです。短い投稿へ分類を増やさず、同じ話題を追う入口だけを記事と共有しています。
実装で確認したこと
下書きと未来日付を含めてビルドし、次の4点を確認しました。
content/drafts/shorts/の投稿が、記事欄ではなくショート欄へ出る- ショートカードの
id、選択時のURL、コピーボタンのURLが同じアンカーを使う <!--thread-->より後の本文が、一覧では追加投稿として開閉できる形になる- タグ一覧の各項目に記事またはショートの種別が付き、切り替えリンクが生成される
保存場所、表示方法、共有URL、追加投稿の区切りを別々にしたため、共有URLを変えても投稿ファイルの置き場所は変えずに済みます。
まとめ
長文記事とショートを同居させるため、保存場所だけに判定を任せず、type: "shorts" で表示方法を分けました。共有URLは一覧内アンカーへ向け、追加投稿は <!--thread--> で区切り、タグだけを記事と共有しています。
短い投稿を別のサービスへ分けず、自分のサイトでは長文記事を個別ページ、ショートを一覧カードで読める形にしました。