タイムライン実装で学んだSCSS設計の重要性

はじめに

お久しぶりです。みんみんです。
10月の上旬、GMOインターネットグループと大学との産学連携を紹介するランディングページの制作案件に携わりました。
このプロジェクトは、企業と大学の関係性を可視化し、採用活動や共同研究の実績を効果的に伝えることを目的としております。
今回は京都大学 x GMOインターネットグループの特設サイトを例に、実装過程で直面した技術的な課題と、その解決策について共有します。
特に、動的コンテンツを扱うタイムライン実装において学んだSCSS設計の重要性についてお話しします。

流れとして

デザインを見て最初に思ったこと

デザインデータを確認した際、特に目を引いたのが「NEWS & TOPICS」セクションのタイムラインデザインでした。
縦線で各項目が繋がり、日付の横には丸いマーカーが配置されている、非常に見やすく美しいデザインです。
しかし、コーディングの観点から見ると、「この縦線と丸をどうやって実装するか」が最初の課題でした。

実装プロセス

まず、タイムラインのHTML構造を見てみます。
今回はPHPで動的にデータを生成する仕様になっています。

データ定義(sections-data.php)

// NEWS & TOPICS
$historyList = [
    [
        'date' => '2025年10月16日',
        'datetime' => '2025-10-16',
        'title' => '京都大学経営管理大学院のビジネスセミナー2025に登壇',
        'title_url' => 'https://www.gsm.kyoto-u.ac.jp/event/57329/',
        'content' => 'GMOインターネットグループ熊谷正寿代表取締役会長兼社長・グループ代表が、企業のリアルやキャリア形成、テクノロジーが社会に果たす役割などをテーマに講演。',
        'images' => ['history_01.jpg']
    ],
    [
        'date' => '2025年5月30日',
        'datetime' => '2025-05-30',
        'title' => '未来技術を語る“京大ミートアップ”共催',
        'title_url' => 'https://developers.gmo.jp/events/55485/',
        'content' => '京都大学の研究者・学生・GMOのエンジニアが集い、技術・キャリア・研究テーマを共有する交流イベントを開催しています。知識の共有とネットワーキングを通じて、新しい研究やアイデアの種を育む 産学連携“の実践の場です。',
        'images' => ['history_02.jpg']
    ],
    [
        'date' => '2024年4月1日',
        'datetime' => '2024-04-01',
        'title' => '「新卒年収710万プログラム」第1期生が入社',
        'title_url' => 'https://developers.gmo.jp/cultures/43374/',
        'content' => '高度な技術力を持つ新卒人材の積極採用を開始。京都大学大学院情報学研究科博士課程修了の学生が入社。',
        'images' => ['history_03.jpg']
    ],
    [
        'date' => '2024年2月12日',
        'datetime' => '2024-02-12',
        'title' => '第2回 BEST SDGs AWARD for University 開催',
        'title_url' => 'https://eco.kyoto-u.ac.jp/?p=9373',
        'content' => '全国55団体が参加し、京都大学学生団体「エコ~るど京大」のキャンパス生きもの紹介プロジェクト「京大!バイオスクープ」がGMO INTERNET GROUP賞を受賞。',
        'images' => ['history_04_1.jpg', 'history_04_2.jpg', 'history_04_3.png']
    ],
    [
        'date' => '2023年10月30日',
        'datetime' => '2023-10-30',
        'title' => '京都大学 首藤研究室のリニューアルを寄付により応援',
        'title_url' => 'https://group.gmo/news/article/8646/',
        'content' => '学術情報メディアセンター社会情報解析基盤研究部門大規模データ活用基盤研究分野、首藤一幸教授と共に、オープニングセレモニーを開催。',
        'images' => ['history_05_1.jpg', 'history_05_2.jpg', 'history_05_3.jpg', 'history_05_4.jpg']
    ],
];

HTML出力部分(index.php)

HTML出力

この構造のポイントは:

  • 配列でデータ管理 – 新しい項目の追加が容易
  • 条件分岐 – リンクの有無、画像の有無に柔軟に対応
  • セマンティックHTML –
  • BEM記法 – クラス名が階層的で理解しやすい

最初のアプローチ:全体に対するbefore疑似要素

私が最初に考えたのは以下のような実装方法でした:

  • 日付の前に::before疑似要素で丸を作成
  • タイムライン全体(.historyTimeline)に対して::beforeで縦線を配置し、高さを調整
/* 最初の実装イメージ */
.historyTimeline {
  position: relative;

  &::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0;
    height: 100%;
    width: 2px;
    background: #ccc;
  }
}

&_date {
  &::before {
    content: '';
    /* 丸の実装 */
  }
}

直面した問題

最初はうまく動作していましたが、画面表示のように、以下の問題が発生しました:

タイムライン修正前
  • 記事の追加や削除のたびに調整が必要
    PHPの配列に項目を追加すると、縦線の高さが合わなくなる
  • テキスト量の変動に対応できない
    コンテンツの文章が長くなると、レイアウトが崩れる
  • メディアクエリが5つ以上必要になり、保守性が低下
    レスポンシブ対応で画面サイズごとに高さを再調整

つまり、静的な高さ指定では柔軟性に欠けるという根本的な問題がありました。

解決策:各子要素に対する疑似要素の活用

チームの先輩に相談したところ、以下のようなアドバイスをいただきました:

全体(.historyTimeline)に対してではなく、各子要素(.historyTimeline_item)に対して::beforeと::afterを使ってみてはどうか」

実際に試してみると、驚くほどうまくいきました!


/* 改善後の実装 */
.historyTimeline {
  list-style: none;
  padding: 0;

  &_item {
    position: relative;
    padding-left: 50px;
    padding-bottom: 40px;

    /* 各アイテムごとに縦線を引く */
    &::before {
      content: '';
      position: absolute;
      left: 10px;
      top: 0;
      bottom: 0; /* 自動的に高さが調整される! */
      width: 2px;
      background: #e0e0e0;
    }

    /* 最後の項目は縦線を表示しない */
    &:last-child::before {
      display: none;
    }
  }

  /* 丸マーカー */
  &_date {
    position: relative;
    display: block;
    margin-bottom: 10px;
    font-weight: bold;

    &::before {
      content: '';
      position: absolute;
      left: -45px;
      top: 5px;
      width: 16px;
      height: 16px;
      border-radius: 50%;
      background: #fff;
      border: 3px solid #0066cc;
      z-index: 1;
    }
  }

  &_content {
    background: #f9f9f9;
    padding: 20px;
    border-radius: 8px;
  }

  &_title {
    margin-bottom: 10px;
    font-size: 18px;

    a {
      color: #0066cc;
      text-decoration: none;

      &:hover {
        text-decoration: underline;
      }
    }
  }

  &_text {
    line-height: 1.8;
    margin-bottom: 15px;
  }

  &_images {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;

    img {
      max-width: 200px;
      height: auto;
      border-radius: 4px;
    }
  }
}

実際の画面上はこのような感じでした。

タイムライン

この実装の利点

  • 柔軟性の向上
    PHPの配列に項目を追加しても、自動的に対応
    コンテンツ量が変わっても高さの手動調整が不要
  • 保守性の改善
    メディアクエリの数を大幅に削減
    SCSSのネスト構造でコードがシンプルで理解しやすい
  • 拡張性
    新しい項目の追加は配列に追加するだけ
    デザイン変更への対応がスムーズ
  • 動的コンテンツに強い
    PHPで生成される動的なコンテンツに完全対応
    CMSとの連携も容易

前後の差異を載せておきます。

beforeafter

学んだこと

この経験から、以下の重要なポイントを学びました:

  • SCSS設計は「どこに疑似要素を配置するか」が重要
    親要素 vs 子要素の選択が、柔軟性を大きく左右する
    動的コンテンツでは特に子要素ベースの設計が有効
  • 相対的な値の活用
    height: 100%ではなくbottom: 0を使うことで、動的な高さに対応
  • PHPとSCSSの連携
    HTMLの構造とSCSSの設計は密接に関係している
    柔軟なデータ構造が、柔軟なスタイリングを可能にする
  • チームメンバーへの相談の重要性
    壁にぶつかったら、早めに相談することで効率的な解決策が見つかる

まとめ

デザインが美しく見えるからといって、実装も単純とは限りません。
今回のタイムライン実装を通じて、SCSS設計における疑似要素の配置戦略と動的コンテンツへの対応の重要性を実感しました。
正直、最初はこのタイムラインデザインを見て「これくらいならすぐできるでしょ」と思ってました。
でも実際に手を動かし始めたら、想像以上に奥が深くて驚きました。

特に疑似要素の使い方が難しかったです。
::before::afterで線を引くのは簡単そうに見えるのですが、コンテンツの量が変わったときにどう対応するか、レスポンシブでどう調整するか、そういう細かいところで結構つまずきました。
デザインモックでは完璧なのに、実際のデータを入れると崩れる…よくあることですね。

SCSS設計も考えさせられました。後から修正することを考えると、変数名とかmixinの作り方とか、ちゃんと設計しないと後で苦労するなと思いました。ネストも深くなりすぎないように気をつけました。
結局、「見た目がシンプル=実装も簡単」ではないのですね。
むしろシンプルに見せるための工夫が裏側にたくさん必要で、そこがフロントエンドの面白さだなと改めて思いました。

この記事を気に入ったら