無限スクロールを作るとき、JavaScriptの処理だけに注目しがちですが、実際にはHTMLとCSSの設計がとても重要です。
見た目の土台が整っていないと、投稿を追加したときにレイアウトが崩れたり、スクロール中に読みにくくなったりします。
この記事では、無限スクロールの土台になるSNS風フィードUIを、HTMLとCSSの観点からわかりやすく解説します。
中央にフィードを配置し、投稿カードを並べ、画像枠やローダーを整えることで、実用的な一覧画面の基本形を作れます。
SNS風フィードUIの基本構造
SNS風フィードUIは、縦方向に投稿が並ぶレイアウトです。
基本的には、次の要素で構成します。
- 全体を包むアプリ用の外枠
- 上部に固定されるヘッダー
- 投稿を追加するフィードエリア
- 投稿カード
- 読み込み状態を表示するローダー
HTMLの基本形は次のようになります。
<div class="app">
<header class="header">
<h1>SNS風フィード</h1>
</header>
<main id="feed" class="feed"></main>
<div id="loader" class="loader">
<div class="spinner"></div>
<span>読み込み中...</span>
</div>
</div>
#feed に投稿カードを追加していきます。
#loader は無限スクロールの読み込み位置として使います。
全体の幅を決める
SNS風フィードでは、横幅を広げすぎないことが大切です。
PC画面いっぱいに投稿が広がると、視線移動が大きくなり読みにくくなります。
そこで、中央に細めのカラムを作ります。
body {
margin: 0;
background: #f5f7f9;
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: #0f1419;
}
.app {
max-width: 600px;
min-height: 100vh;
margin: 0 auto;
background: #ffffff;
border-left: 1px solid #e6ecf0;
border-right: 1px solid #e6ecf0;
}
max-width: 600px を指定することで、PCでも読みやすい幅になります。
margin: 0 auto によって、画面中央に配置されます。
min-height: 100vh は、投稿が少ない状態でも画面の高さを確保するための指定です。
固定ヘッダーを作る
無限スクロールでは、ページが長くなりやすいです。
そのため、上部にヘッダーを固定しておくと、現在どの画面を見ているのかがわかりやすくなります。
.header {
position: sticky;
top: 0;
z-index: 10;
padding: 16px;
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(12px);
border-bottom: 1px solid #e6ecf0;
}
.header h1 {
margin: 0;
font-size: 20px;
}
position: sticky を使うと、通常はページ内に配置され、スクロールして上端に到達すると固定されます。
完全な固定表示にする position: fixed よりも扱いやすく、フィードUIに向いています。
投稿カードをFlexboxで作る
投稿カードは、左にアバター、右に本文を配置する構成にします。
HTMLの例は次の通りです。
<article class="post">
<div class="avatar">A</div>
<div class="post-body">
<div class="post-meta">
<span class="name">Aoi</span>
<span class="handle">@aoi</span>
<span class="time">3分前</span>
</div>
<p class="post-text">
今日は無限スクロールのUIを作っています。
</p>
</div>
</article>
CSSでは、Flexboxを使って横並びにします。
.post {
display: flex;
gap: 12px;
padding: 16px;
border-bottom: 1px solid #e6ecf0;
cursor: pointer;
transition: background 0.15s ease;
}
.post:hover {
background: #f7f9f9;
}
.avatar {
flex: 0 0 44px;
width: 44px;
height: 44px;
border-radius: 50%;
display: grid;
place-items: center;
background: #1d9bf0;
color: #ffffff;
font-weight: 700;
}
.post-body {
flex: 1;
min-width: 0;
}
ここで重要なのが min-width: 0 です。
Flexboxの中では、長い文字列があると本文エリアが横にはみ出すことがあります。
min-width: 0 を入れておくと、親要素の幅に収まりやすくなります。
投稿者情報を整える
投稿者名、ID、時間は横並びで表示します。
ただし、スマートフォンでは横幅が狭くなるため、折り返しできるようにします。
.post-meta {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 6px;
margin-bottom: 6px;
font-size: 14px;
}
.name {
font-weight: 700;
}
.handle,
.time {
color: #536471;
}
.post-text {
margin: 0 0 12px;
line-height: 1.7;
font-size: 15px;
}
flex-wrap: wrap を指定しておくと、名前やIDが長くても自然に折り返されます。
小さな指定ですが、スマホ対応ではかなり重要です。
画像枠を安定させる
投稿に画像がある場合は、画像枠の高さを先に確保しておくことが大切です。
画像の読み込み後に高さが変わると、スクロール位置がズレてしまうからです。
<div class="post-image"></div>
.post-image {
width: 100%;
aspect-ratio: 16 / 10;
margin-top: 10px;
border-radius: 16px;
overflow: hidden;
background: linear-gradient(135deg, #8ec5fc, #e0c3fc);
}
aspect-ratio: 16 / 10 を指定すると、横幅に対して一定の比率で高さが決まります。
実際の画像を使う場合も、画像の表示領域を先に確保しておくと、レイアウトのガタつきを防げます。
アクションエリアを作る
SNS風の見た目にするなら、返信、リポスト、いいね、閲覧数のようなアクションエリアを入れると雰囲気が出ます。
<div class="actions">
<button type="button">返信 <span>12</span></button>
<button type="button">リポスト <span>5</span></button>
<button type="button">いいね <span>48</span></button>
</div>
.actions {
display: flex;
justify-content: space-between;
gap: 8px;
max-width: 420px;
margin-top: 10px;
}
.actions button {
border: none;
background: transparent;
color: #536471;
font-size: 13px;
cursor: pointer;
padding: 4px 6px;
border-radius: 999px;
}
.actions button:hover {
background: #e8f5fd;
color: #1d9bf0;
}
本番では、クリックできる要素は div ではなく button で作るのがおすすめです。
キーボード操作やアクセシビリティの面で扱いやすくなります。
ローダーを作る
無限スクロールでは、読み込み中であることをユーザーに伝える必要があります。
何も表示されないと、動いているのか止まっているのかわかりません。
.loader {
text-align: center;
padding: 24px;
color: #536471;
font-size: 14px;
}
.spinner {
width: 28px;
height: 28px;
margin: 0 auto 8px;
border: 3px solid #e6ecf0;
border-top-color: #1d9bf0;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
スピナーがあることで、次のコンテンツを読み込んでいることが伝わります。
通信が遅い場合でも、ユーザーに安心感を与えられます。
スマートフォン対応を入れる
スマートフォンでは、左右の枠線や余白を少し調整すると見やすくなります。
@media (max-width: 640px) {
.app {
max-width: none;
border-left: none;
border-right: none;
}
.post {
padding: 14px;
}
.avatar {
flex-basis: 40px;
width: 40px;
height: 40px;
}
}
画面幅が狭い場合は、フィードを画面いっぱいに広げます。
投稿の余白やアバターサイズも少し小さくすると、スマートフォンでも読みやすくなります。
まとめ
無限スクロールの見た目を作るときは、JavaScriptより先にHTMLとCSSの土台を整えることが大切です。
- 中央カラムを作る
- 固定ヘッダーを作る
- 投稿カードをFlexboxで並べる
- 本文エリアに
min-width: 0を入れる - 画像枠に
aspect-ratioを指定する - ローダーで読み込み状態を伝える
この基本を押さえるだけで、SNS風の読みやすいフィードUIを作れます。
次の段階では、JavaScriptで投稿カードを動的に生成し、画面へ追加する処理を組み合わせていきます。
