4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Flexboxで「1つのセルに複数の色バー」を実装する ── 検索しても出てこなかった解決策

4
Last updated at Posted at 2026-03-02

はじめに

業務で「日ごとの工数を一覧表示する機能」を作っていたとき、1つのテーブルセルの中に、複数の工程を色分けして横並びで表示するという要件が出ました。

完成イメージはこんな感じです:

完成イメージ

  • 月によって工程の数が 1個〜5個 と変わる
  • でも常に セルの横幅いっぱい に色で埋めたい
  • 工程ごとに色が違う

一見シンプルに見えるこの要件、意外と苦戦しました。


最初に困ったこと:「何て検索すればいいかわからない」

正直、これが一番つらかったです。

試した検索キーワード(❌ ハズレ)

検索キーワード 結果
「ガントチャート CSS」 Chart.js などのライブラリ記事ばかり
「セル内 カラーバー CSS」 プログレスバー(1色)の情報
「複数色 横並び CSS」 グラデーションの話
「テーブル セル 色分け」 セル背景色を1色で塗る話

「1つのセルの中に、可変個数の色付きブロックを横並びにする」 という概念に、名前がついていないんですよね。

たどり着いたキーワード(✅ ヒット)

  • 「flex-grow 均等幅」
  • 「Flexbox 子要素 可変個数」

ここでやっと flex-grow: 1 という解決策にたどり着きました。

ちなみに、近い概念としては「Stacked Bar(積み上げバー)」や「Segmented Bar」と呼ばれるものがありますが、ライブラリを使わず DOM 要素だけで実現する情報は少なかったです。


解決策:HTML + CSS

HTML

<td class="month-cell">
  <div class="bar-container">
    <div class="bar phase-a"></div>   <!-- 工程A -->
    <div class="bar phase-b"></div>   <!-- 工程B -->
    <div class="bar phase-c"></div>   <!-- 工程C -->
  </div>
</td>

CSS

/* セルの内側余白をゼロにする */
.month-cell {
    padding: 0;
}

/* Flexbox コンテナ */
.bar-container {
    display: flex;      /* 子要素を横並びにする */
    gap: 0;             /* 子要素間の隙間なし */
    height: 30px;
    width: 100%;
}

/* 各工程バー */
.bar {
    flex-grow: 1;       /* 存在する工程で均等に幅を分割 */
    height: 100%;
}

/* 工程ごとの色 */
.bar.phase-a { background-color: #ffe44e; }                    /* 黄色 */
.bar.phase-b { background-color: #b0ec40; }                    /* 黄緑 */
.bar.phase-c { background-color: rgba(104, 218, 155, 0.85); }  /* ミント */
.bar.phase-d { background-color: rgba(134, 224, 247, 0.89); }  /* 水色 */
.bar.phase-e { background-color: rgba(94, 140, 201, 0.90); }   /* 青 */

たったこれだけで、工程数に応じて自動的にセル全幅を埋めてくれます。


なぜこれで動くのか

display: flex; — 横に並べる

display: flex を親要素に指定すると、子要素が自動的に横並びになります。

display: flex の効果

flex-grow: 1; — 均等に幅を分ける

flex-grow: 1「余ったスペースを均等に分け合え」 という指示です。

flex-grow: 1 の効果

固定幅(width: 33% など)を使わなくていいのがポイントです。
工程が何個あっても自動で均等割りしてくれます。


隙間をなくす3つの CSS 設定

きれいに色が並ぶためには、余白を徹底的にゼロにする必要があります。

CSS 設定 対象 何の余白か
padding: 0 セル(<td> セルの枠と中身の間の余白
gap: 0 コンテナ(.bar-container 色バー同士の間の余白
width: 100% コンテナ セル幅いっぱいに広がる

⚠️ 注意:padding: 0 は必ず明示的に書こう

「padding を設定しなければ余白はつかないでしょ?」と思うかもしれませんが、ブラウザにはデフォルトスタイルがあります。

だから、明示的に padding: 0 を書いてリセットする必要があります。

.month-cell {
    padding: 0 !important;  /* 確実にリセット */
}

JavaScript で動的に生成する

実際の画面では、API から取得したデータに基づいてバーを動的に生成します。

受験スケジュールを例にすると、こんな JSON が返ってくるイメージです:

[
  { "month": "2026-04", "phase": "基礎",  "hours": 80 },
  { "month": "2026-05", "phase": "基礎",  "hours": 40 },
  { "month": "2026-05", "phase": "応用",  "hours": 60 },
  { "month": "2026-06", "phase": "応用",  "hours": 50 },
  { "month": "2026-06", "phase": "演習",  "hours": 30 }
]

これを描画する JavaScript:

// フェーズ名 → CSSクラス名の変換
function getPhaseClass(phaseName) {
    const map = {
        '基礎': 'basic',
        '応用': 'applied',
        '演習': 'exercise',
        '模試': 'mock',
        '本番': 'exam'
    };
    return map[phaseName] || '';
}

// 1つの月セルのHTMLを生成
function renderMonthCell(effortList) {
    if (!effortList || effortList.length === 0) {
        return '<td class="month-cell"></td>';  // 空セル
    }

    let html = '<td class="month-cell"><div class="bar-container">';

    effortList.forEach(effort => {
        const phaseClass = getPhaseClass(effort.phase);
        html += `<div class="bar ${phaseClass}" style="flex-grow: 1"></div>`;
    });

    html += '</div></td>';
    return html;
}

ポイント: effortList の要素数がいくつでも、flex-grow: 1 のおかげで自動的に均等幅になります。ループで <div> を追加するだけで OK。


まとめ

使った CSS はたった3つ

display: flex;     /* 横に並べる */
flex-grow: 1;      /* 均等幅にする */
padding: 0;        /* 余白をなくす */

苦戦した原因

  1. 検索キーワードがわからなかった — 「1セルに可変個数の色バー」に名前がない
  2. 固定幅(%指定)で実装しようとした — 科目数が変わるたびに計算が必要で破綻
  3. デフォルトの余白に気づかなかった — ブラウザやフレームワークが勝手に padding を付けていた

ライブラリなしで、CSS 20行以下で実現できます。 同じ要件で困っている方の参考になれば幸いです。

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?