コメントスレッド
アバター付きのコメント一覧。返信は1段ネストして表示。ハートの「いいね」はタップで数が増減し、返信ボタンで簡易入力欄が開いて返信を追加できる。
プレビュー
クリック
操作クリック/タップで動きます。
仕様書
- 向く場面
- 記事・投稿へのコメント欄
- 返信を 1 段ネストで見せる会話
- いいねで反応を集める UGC
- 避ける場面
- 多段ネストが要る掲示板
- リアルタイム性が要るチャット
- 構成要素
- アバター
- 名前と時刻
- 本文
- いいねボタン
- 返信ボタン
- 返信入力欄
- 持っている状態
- 通常
- ホバー
- 押下中
- キーボード
Tab でいいね→返信→(開いた入力欄→送信)へ。Enter/Space で実行、入力欄は Enter で送信。返信後は返信ボタンへフォーカスが戻る
- 支援技術
いいねは aria-pressed+隠しテキスト「いいね」+件数。返信ボタンは aria-expanded+aria-controls で入力欄と結び、開くとフォーカスが移る。ハートは aria-hidden。reduced-motion で遷移停止
- 動き
ハート押下で 1.25 倍 150ms。ボタン背景 120ms
デザインの要点
- 返信は 1 段だけネストし、左に 2px の線を引く。2 段以上は狭い幅で本文が細くなり読めない
- 返信のアバターは 28px に落として親(34px)と区別する。同じ大きさだと親子が並列に見える
- いいねは data-base の元の数に自分の 1 を足し引きする。押すたびに増え続ける実装は信用を失う
- 返信欄は押した位置の直下に開き、開いた瞬間に入力欄へフォーカスする。ページ末尾の共通欄では文脈が切れる
コード(コピーして使えます)
<div class="thread" id="thread">
<div class="comment">
<span class="avatar" style="background:linear-gradient(135deg,#2b50c7,#7fa4ff)" aria-hidden="true">あ</span>
<div class="c-body">
<div class="c-head"><span class="c-name">あかり</span><span class="c-time">2時間前</span></div>
<p class="c-text">この記事すごく参考になりました!続きも楽しみにしています。</p>
<div class="c-actions">
<button class="like-btn" type="button" aria-pressed="false" data-base="12">
<svg class="heart" width="14" height="14" viewBox="0 0 14 14" aria-hidden="true"><path d="M7 12S1.5 8.5 1.5 4.8A2.8 2.8 0 017 3.2a2.8 2.8 0 015.5 1.6C12.5 8.5 7 12 7 12z" stroke-width="1.3"/></svg>
<span class="c-sr">いいね </span><span class="like-count">12</span>
</button>
<button class="reply-btn" type="button" data-reply aria-expanded="false" aria-controls="reply-box-1">返信</button>
</div>
<div class="replies">
<div class="comment reply">
<span class="avatar" style="background:linear-gradient(135deg,#2a7a45,#2b50c7)" aria-hidden="true">け</span>
<div class="c-body">
<div class="c-head"><span class="c-name">けんと</span><span class="c-time">1時間前</span></div>
<p class="c-text">同じく!次回も期待してます。</p>
<div class="c-actions">
<button class="like-btn" type="button" aria-pressed="false" data-base="3">
<svg class="heart" width="14" height="14" viewBox="0 0 14 14" aria-hidden="true"><path d="M7 12S1.5 8.5 1.5 4.8A2.8 2.8 0 017 3.2a2.8 2.8 0 015.5 1.6C12.5 8.5 7 12 7 12z" stroke-width="1.3"/></svg>
<span class="c-sr">いいね </span><span class="like-count">3</span>
</button>
</div>
</div>
</div>
</div>
<form class="reply-box" id="reply-box-1" hidden>
<input type="text" placeholder="返信を書く" aria-label="あかりへの返信" autocomplete="off"/>
<button type="submit">送信</button>
</form>
</div>
</div>
<div class="comment">
<span class="avatar" style="background:linear-gradient(135deg,#b8860b,#e6dcc7)" aria-hidden="true">ゆ</span>
<div class="c-body">
<div class="c-head"><span class="c-name">ゆうな</span><span class="c-time">45分前</span></div>
<p class="c-text">はじめて知りました。さっそく試してみます🙌</p>
<div class="c-actions">
<button class="like-btn" type="button" aria-pressed="false" data-base="5">
<svg class="heart" width="14" height="14" viewBox="0 0 14 14" aria-hidden="true"><path d="M7 12S1.5 8.5 1.5 4.8A2.8 2.8 0 017 3.2a2.8 2.8 0 015.5 1.6C12.5 8.5 7 12 7 12z" stroke-width="1.3"/></svg>
<span class="c-sr">いいね </span><span class="like-count">5</span>
</button>
<button class="reply-btn" type="button" data-reply aria-expanded="false" aria-controls="reply-box-2">返信</button>
</div>
<div class="replies"></div>
<form class="reply-box" id="reply-box-2" hidden>
<input type="text" placeholder="返信を書く" aria-label="ゆうなへの返信" autocomplete="off"/>
<button type="submit">送信</button>
</form>
</div>
</div>
</div>