こんにちは!2ちゃんねる互換掲示板システム「 つゔぁいちゃんねる(2ch.biz) 」の開発録、第48回です。
前回(第47回)では、ルーム名の二重同期パイプラインとIndexedDB v2へのローカル保存により、愛着の湧くコミュニティ体験を実現しました。
機能が充実し、いよいよスマートフォンからの利用者がPCを上回る勢いで増加する中、モバイルUIにおける 「最後の大物レイアウト問題」 が浮上しました。
「スマホの画面幅(375px〜400px前後)で、 右側の参加者リスト(ニックネームサイドバー)をどう表示すべきか? 」
PCと同じように横並びにすると本文が1行あたり数文字しか入らず、完全にUIが破綻する。しかし、スマホだからといって参加者リストを完全に消してしまうと、 「今誰がいるのか分からない」「荒らしのキックやホスト権限の移譲ができない」 という致命傷に繋がります。
本稿では、画面の表示領域を100%本文に明け渡しつつ、ワンタップでメンバー確認と管理操作を行える 「ドロワー式トグルボタン」 の実装を解説します!
1. モバイルにおける「サイドバーのジレンマ」
デスクトップ版のXChatスタイルでは、左にメッセージログ、右に参加者一覧が並ぶ2ペイン構成が非常に便利でした。
しかし、画面幅が400px未満のスマートフォンで同じことをやろうとすると、以下のような地獄絵図になります。
かといって、メディアクエリで display: none; にして消し去ってしまうと、モバイルユーザーは「誰がこの部屋にいるのか」を知る術を失い、第32回で作った「👑 ホスト移譲(なすりつけ)」や「× キック」のボタンも押せなくなってしまいます。
私たちが目指したのは、 「通常時は画面の横幅を 100% メッセージログに使い、見たい時だけスッと上から引き出せるトグルUI」 でした。
2. 解決策:リアルタイム人数バッジ付き「👥 参加者」トグルボタン
画面を圧迫しない最も自然な場所として、私たちは上部のトピックバー内に 「👥 参加者 (人数)」ボタン(#p2p-toggle-peers-btn) を組み込みました。
3. 実装の全貌
(1) トピックバーのマークアップ
トピックバーの右側アクション群の中に、人数の動的バッジを内包したボタンを新設しました。
<div class="p2p-xchat-topic-bar">
<div class="p2p-topic-left">
<span class="p2p-topic-channel">#</span>
<span class="p2p-topic-text" id="p2p-topic-text">名称未設定ルーム</span>
</div>
<div class="p2p-topic-right">
<!-- ★新設: モバイル向け参加者トグルボタン -->
<button type="button" id="p2p-toggle-peers-btn" class="btn btn-sm btn-outline p2p-btn-peers-toggle">
👥 <span id="p2p-mobile-peers-count">1</span>
</button>
<!-- その他のボタン (設定、退室等) -->
</div>
</div>
(2) リアルタイム人数カウントの連動
ピアが入室・退室するたびに、WebRTCのピアマップから総人数を計算し、ボタンの数値をリアルタイムに更新します。
/**
* 参加者一覧の更新とバッジ同期
*/
function handlePeersUpdate() {
// 既存の参加者リストDOM再描画...
renderNicknameList();
// ★モバイルボタンのバッジ数値を更新 (自分自身 + 接続ピア数)
const countEl = document.getElementById('p2p-mobile-peers-count');
if (countEl) {
const totalPeers = 1 + Object.keys(activePeers).length;
countEl.textContent = totalPeers;
}
}
/**
* トグルボタンのクリックハンドラ
*/
document.getElementById('p2p-toggle-peers-btn').addEventListener('click', () => {
const sidebar = document.getElementById('p2p-sidebar');
if (!sidebar) return;
// 開閉クラスをトグル
sidebar.classList.toggle('p2p-sidebar-shown');
});
(3) モバイルCSSとスライドダウンアニメーション
デスクトップでは右側に固定表示し、モバイル(max-width: 768px)では絶対配置のアコーディオン・ドロワーへと切り替えます。
/* デスクトップ表示: 右側に常時表示 */
.p2p-xchat-sidebar {
width: 200px;
border-left: 1px solid var(--border-color, #d0d7de);
background: var(--bg-secondary, #f6f8fa);
}
/* ★モバイル最適化 (768px以下) */
@media (max-width: 768px) {
/* PC用リサイズスプリッターは非表示 */
.p2p-sidebar-resizer {
display: none !important;
}
/* 通常時は非表示(スライド格納状態) */
.p2p-xchat-sidebar {
display: none;
position: absolute;
top: 80px; /* ヘッダー + トピックバーの直下 */
left: 0;
right: 0;
width: 100% !important;
max-height: 180px; /* メッセージを完全に隠さない絶妙な高さ */
overflow-y: auto;
border-left: none;
border-bottom: 2px solid var(--border-color, #0969da);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
z-index: 20;
}
/* トグル展開時: スルッとスライドダウン */
.p2p-xchat-sidebar.p2p-sidebar-shown {
display: block;
animation: p2pSlideDown 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
}
@keyframes p2pSlideDown {
from {
opacity: 0;
transform: translateY(-8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
[!TIP]
ドロワーの最大高さをmax-height: 180px;に抑えておくことで、参加者リストを開いた状態でも下側に最新メッセージがチラ見えし、チャットの流れを見失わないように工夫しています。
4. 自動テストと実機操作の検証
自動テストスクリプトおよび iPhone Safari 実機で検証を行いました。
-
開閉アニメーションの滑らかさ :
-
transform: translateYを使用しているため、GPU支援により60fpsで吸い付くようにヌルヌル開閉することを確認。
-
-
人数カウントの即時連動 :
- 別のブラウザが入室した瞬間、ボタンのバッジが「👥 1」から「👥 2」へ瞬時に切り替わることを確認。
-
管理操作の完全性 :
- モバイル画面上でもドロワーを展開することで、「👑 ホスト移譲」や「× キック」のボタンが問題なくタップ可能であることを実証。
5. まとめと次回予告
参加者リストをドロワー式トグルメニューへと昇華させたことで、スマートフォンの限られた画面幅の中で「メッセージの圧倒的な読みやすさ」と「管理操作の完全性」を両立させることができました。
UIの完成度がいよいよ極限に達したP2Pチャットですが、アクセス集中テスト(多人数同時接続テスト)を実施していたチームから、 「非常に厄介な通信バグ」 が報告されました。
「10人以上のユーザーが一斉に部屋に入ろうとすると、 何人かのブラウザが『接続中…』のまま固まって部屋に入れない! 」
「コンソールを見ると、WebRTCのOfferとAnswerが同時に飛び交って衝突(Glare)している!」
WebRTCの分散接続における最大の難関「シグナリング状態の競合」。
次回は、 【第049回】「部屋に入れない」謎のフリーズを追え!シグナリング状態の競合解消とコネクションリトライ をお届けします。お楽しみに!
本番サービス : https://2ch.biz/