Help us understand the problem. What is going on with this article?

Vue Fes Japan 2019 公式サイトから学ぶ CSS コーディングの知見

この記事は CSS Advent Calendar 2019 の 20日目の記事です。

Vue Fes Japan 2019 が開催中止になってしまい、大変残念だったのですが... :cry:
(私は Vue.js 日本ユーザーグループのコアスタッフで、今回は Web サイト制作班として少しコミットしていたのでした)

先日公式サイトのソースコードが無事公開されました :tada:
そこで、Web サイト制作で得た CSS の知見がとてもためになったので、いくつかご紹介していきたいと思います。

Vue Fes Japan 2019 公式サイト

公式サイト: https://vuefes.jp/2019/
GitHub: https://github.com/vuejs-jp/vuefes-2019

2019 の公式サイトも、2018 の公式サイトと同様に、Nuxt.js の静的ファイルの生成機能を使って作成しています。

CSS の構成について

このように、「グローバルな CSS」と「閉じられた CSS(Scoped CSS)」で構成されています。

ちなみにこのプロジェクトでは UI フレームワークや CSS フレームワークは使っていません。

コーディングするときにとても嬉しかったポイント

Web サイトデザイン主担当の沖さん(@448jp)が、Web サイトの仕様をドキュメント化して共有してくれました。

スクリーンショット 2019-12-18 5.04.40.png

これがとても詳細まで定義されており、ブレークポイントごとの余白や、フォント・色などを CSS プロパティで指定してくださったおかげで、悩まずにすばやく実装することができました。

つよい... :muscle:

私は普段デザインカンプをもらってコーディングをするとき、ブレークポイント付近のデザインをエスパーしてコーディングしたり、仕様を自分で決めたりしていたのですが、そうするとデザイナーさんと齟齬が生まれたり手戻りが発生したりして、開発に余計な時間がかかってしまうことがあります。

沖さんのようなデザイナーがいる環境というのは、なかなか恵まれていると思うのですが、Web サイトをデザインする人は詳細な仕様を明文化することで、実装側がとても助かるということを知ってもらえると良いなと思いました :pray:

CSS コーディングの知見

グローバルな CSS の設計について

CSS の各レイヤーをディレクトリやファイルごとに分類することで、どんな意味を持った CSS をどこに配置するか、共同開発する際にメンバーと認識が合うようになります。

  • foundation
    • colors.scss ... 色の変数
    • reset.scss ... normalize.css によってブラウザごとの差異を整えた後に、さらにリセットしたいブラウザのデフォルトのスタイル
    • typography.scss ... タイポグラフィのスタイル
    • variables.scss ... 共通化して使える変数
  • main.scss ... 各 SCSS ファイルを import しているファイル
  • media_queries.scss ... メディアクエリによって要素を表示させるか否かを制御できるクラス
  • utilities.scss ... 各画面で共通して使えるクラス

また、foundation 配下の CSS を開発初期の段階で固めておくことで、CSS フレームワークを使わずとも統一感のとれた CSS を書いていくことができます。

ブレークポイントの名称は sp pc ではなく sm md lg を使う

私は今まで、ブレークポイントの切り替えで使う変数名の表記には sp pc を使っていたのですが、この 2パターンだと中間層のサイズのブレークポイントを書きたい際に困ることがありました。

ブレークポイントの名前をサイズの名前にすると、中間層のサイズも柔軟に表すことができるようになるのでオススメです。

https://github.com/vuejs-jp/vuefes-2019/blob/master/src/assets/stylesheets/foundation/variables.scss#L1-L4

$layout-breakpoint--is-small: 768px !default;
$layout-breakpoint--is-small-up: 769px !default;
$layout-breakpoint--is-medium: 980px !default;
$layout-breakpoint--is-medium-up: 981px !default;

sm (モバイル)サイズの要素の指定を相対指定にする

モバイル端末の違いによって、文字やコンテンツの幅が大きく変わってしまう問題については、サイズを相対指定(vw)にすることで解決しています。

スクリーンショット 2019-12-18 5.47.43.png

スクリーンショット 2019-12-18 5.48.07.png

文字やコンテンツの幅を相対指定にすることで、iPad と iPhone SE というような画面幅が違う端末でも、画崩れを起こさずに表現することができます。

ちなみにデスクトップサイズ以上の文字については、固定で指定しています(さすがにラップトップと大きいサイズのモニターでは幅が違いすぎるため)

計算が簡単なカードリストレイアウトの実装方法

SPONSORS セクションでは、スポンサープランごとに 1列に並ぶカードの幅を変える必要がありました。

  • ゴールドは 1列 4カード、シルバーは 1列 5カード... というように並ぶ
  • それぞれ 20px のガター(余白)がついている

スクリーンショット 2019-12-18 6.44.43.png

当初、これを実装するために考えていたこととしては、

  • スポンサープランごとのカードの幅を計算する
  • カードの margin-rightmargin-bottom に 20px を設定する
  • 右端に来る n 番目のカードは、 margin-right: 0; を設定する
    • n 番目の n の値は、スポンサープランごとに変わる

というようなことを書こうとしましたが、計算と実装が複雑になるため、別の方法をとることにしました。

計算が簡単になる方法として、ネガティブマージンと calc() を使うやり方があります。

template
    <ul
      v-for="sponsorPlan in sponsorPlansHavingSponsors"
      :key="sponsorPlan.plan"
    >
      <li class="sponsor-group" :class="sponsorPlan.plan">
        <h3 class="sponsor-plan">
          {{ sponsorPlan.name }}
        </h3>

        <ul>
          <li
            v-for="sponsor in sponsorsByPlan(sponsorPlan.plan)"
            :key="sponsor.sys.id"
            class="sponsor"
          >
            <!-- ... -->
          </li>
        </ul>
      </li>
    </ul>
scss
.sponsor-group {
  ul {
    display: flex; // flexbox で実装する
    flex-wrap: wrap; // アイテムがはみ出したときに折り返すようにする
    justify-content: center; // 中央揃えにする
    width: calc(100% + 20px); // 💡幅を左右のガター分プラスする
    margin: -10px; // 💡ネガティブマージンを使って余白を広めにとる
  }
  .sponsor {
    margin: 10px; // 💡ガターの半分の幅を指定する(要素が隣り合うとガターの幅になる)
    width: calc((100% / 5) - 20px); // 普通サイズ(シルバー)の Sponsor バナーの横幅
  }
}
.sponsor-group.bronze {
  .sponsor {
    width: calc((100% / 6) - 20px); // ブロンズのバナーのときの横幅
  }
}
.sponsor-group.gold,
.sponsor-group.special {
  .sponsor {
    width: calc((100% / 4) - 20px); // ゴールド、スペシャルのバナーのときの横幅
  }
}

まず .sponsor-group にネガティブマージンを使って、ガターの幅分だけ要素の幅を広めに指定します。

次に、カードの上下左右にガター分の margin を指定します(このときガターの半分の幅を指定することで、カードが隣り合うとガターの幅になります)

そして、カードの幅を calc() で計算して、flexbox で要素を並べると、簡単にカードリストが出来上がります。

ちなみにカードの幅の calc((100% / 5) - 20px); という部分は、

(sponsor-group の幅 / 1列に入るカードの数) - ガターの幅

という計算式になります。

こうするとことで、 1列に入るカードの数 を変更すればカードの幅が変わるので、とても計算が簡単になります。

vuefes-2019/TheSponsorListSection.vue at master · vuejs-jp/vuefes-2019

↑のコードは TheSponsorListSection の簡略版ですが、コードだけではネガティブマージンをとっているあたりが分かりにくいと思うので、CodePen を用意しました。

See the Pen CSS coding for card list layout by rry (@ryamakuchi) on CodePen.

https://codepen.io/ryamakuchi/pen/LYExRpa

  • group
    • ネガティブマージンを width を使って、全体的にガターの幅分を広めにとる
  • card
    • 上下左右にガターをつけて、calc() で幅ぴったりにする

当初考えていた、左側と下にガターをつける方法と比べると、右端に来る n 番目のカードのスタイルの上書きをするということがなくなるため、計算が簡単になります。

補足:ちなみに calc() は、IE 10 / IE 11 では一部うまく機能しない場合もあるため、実装するときは気をつけてください。

まとめ

CSS の設計をきちんと行うことで、フレームワークを使うことなく、メンテナンスしやすい&共同開発しやすいサイト作成ができました。

もし CSS / UI フレームワークを使うことを検討しているのであれば、

create-nuxt-app で利用できる UI フレームワークを比較する - Qiita

も、あわせてご覧いただければ幸いです。

メリークリスマス! :christmas_tree:

rry
リリィは typo から生まれました。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away