HTMLとCSSでSNS風フィードUIを作る方法|無限スクロールの見た目設計を解説

無限スクロールを作るとき、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で投稿カードを動的に生成し、画面へ追加する処理を組み合わせていきます。