8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Qiita株式会社Advent Calendar 2023

Day 7

実例 Qiitaのcssで余白を書くときのルール 後編

Last updated at Posted at 2023-12-06

これはなに?

この記事は下記の記事の後編になります。

cssで余白を付ける方法はたくさんあります。
一定のルールがないと、あっちではmarginで、こっちではpaddingで、方向も色々で…と崩壊し始めてしまいます。

Qiitaでもルールは特別設けられていませんでした。
2020年頃から、ルールを設定し始めました。

10年以上続くサービスですので、全適応を一度にするのではなく、新しく作ったコンポーネントや変更を加えるときに、徐々に対応していきました。

個人的にはどのようなルールであっても、開発に関わるメンバーの合意が取れたルールは必要だと思います。

この記事はQiitaでの事例を紹介したいと思います。
絶対これが最高!というものではなく、こんなルールで作っているサービスもあるんだと知っていただければ幸いです。

Qiitaのcssガイドラインには「marginは、要素が追加される方向にあわせてつける」という文が含まれています。
後編では、その理由と、例外的に使う例を紹介したいと思います。

対象読者

  • デザイナー
  • スタイルのコーディングをするエンジニア
  • 記事を書くときにスタイルをいじることがある人

「余白は追加される方につける」を基準にしたい

冒頭でも述べましたが、Qiitaのcssガイドラインには「marginは、要素が追加される方向にあわせてつける」という文が含まれています。

今回は理由として二点紹介します。

  • 末尾の要素の存在が任意である場合が多い
  • 隣接セレクターを使った場合分けがしやすい

末尾の要素の存在が任意である場合が多いため

Webでは重要な要素(ユーザーに見てほしい情報)ほど先に出すことが多いと思います。
ということは、あとから出てくる要素は任意になって、表示される場合とされない場合があり得ます。

私も最初このルールを理解するときに下記の記事を参考にさせていただきました。
カードのレイアウトを例に解説していらっしゃいます。

Qiitaの事例 「記事ページ」

Qiitaの事例としては、この記事を書いた時点では記事ページに直したい要素が存在しています。
次の要素との余白をとるためにmargin-bottom をつけているけれど次の要素が存在していない状態です。

Qiitaの記事ページの一番下
スクリーンショット 2023-12-05 23.38.55.png

Qiitaではemotionを使って、CSS in JS で実装しているので、class名がランダムな文字列に書き出されていますが、contentBlockStyle というコンポーネントに margin-bottom: 24px; がついています。
そのため一番最後の要素は、下に要素が追加されないのに余分な余白がついている状態です。

この事例は下記のように処理できます。

const contentBlockStyle = css({
  //その他のスタイル省略
  '&:last-child': {
    marginBottom: 0,
    //その他のスタイル省略
  },
})

ですが、そもそも自分自身(この場合contentBlockStyle)が表示されるときに margin-top: 24px; を持っていれば、このような処理も不要になります。
なので、書き方としては下記が好ましいと考えています。

const contentBlockStyle = css({
  marginTop: 24,
  //その他のスタイル省略
})

React component化していく中で、他の要素によって余白がコントロールされるよりも、自分自身で管理している方がコードの可読性は良いだろうと私は思います。

自分で書いておいてツッコミますが…

:last-childじゃないけど、:first-childで最初の要素の余白指定を打ち消すことがあると思います。
先程の記事の例を、リファクタリングするなら下記の書き方になると思います。

//Wrapする要素

const containerStyle =css({
  //その他のスタイル省略
  padding: '24px 24px 0';
})
//Wrapする要素に対して一つ階層が下の要素

const contentBlockStyle = css({
  //その他のスタイル省略
  'label:not(:first-child)': {
    marginTop: 24;
    //その他のスタイル省略
  },
})

こうなると、手間は一緒では?と疑問に思ったあなたは鋭いです。

でもよく考えてください。
:not(:first-child) にすると、最初の要素以外に「 追加 」する書き方です。
:last-childでは、最後の要素から「 削除 」する書き方です。

必要なときに「 追加 」される方が、ブラウザのInspectorの見通しも良いです。
削除 」する書き方にした場合、打ち消したはずのものをまたどこかで上書きする可能性もあります。
そうなるとコードが複雑化していってしまいます。
ですから、Qiitaでは好ましくないとしています。

ただコーディングルールでは縛ってはいません。
:last-childが必要になることもあると思うからです。

隣接セレクターを使った場合分けがしやすい

Qiitaのコードでよくあるパターン

Qiitaで一番隣接セレクターが登場する場面はリストのように、同じものが並ぶときだと思います。
Internet Explorerのサポートが終了してから、 FlexboxやGrid layoutで gap の指定をすることも増えていますが、まだまだ使う場面は残っています。

scssで書くとこのような感じです。

.list {
  //その他のスタイル省略
  '& + &' {
    margin-top: 32px;
    padding-top: 32px;
    //その他のスタイル省略
  }
}
例:Qiita Jobs Plusの一覧ページ

この例だと若干最初の理由も包括している部分がありますが、同じ要素が隣接する場合のみborder,margin,paddingを追加して管理しています。

特定の組み合わせの場合だけ余白を変えたいパターン

他の例としては、記事ページ(Qiita、Team、Qiita Jobs Plusなど)で編集者が任意で要素を組み替える場所だと、特定の組み合わせの場合だけmarginを変更したいこともあります。

Qiitaの実例ではありませんが、下記のようなパターンが想定されます。

例:地のテキストは、段落が変わったら24pxの余白。h2と隣接するときだけ余白を16pxに縮めたい。

p {
  margin-top: 24px;
}

h2 + p {
  margin-top: 16px;
}

隣接セレクタは「Aの隣のBに対して宣言する」という表現になる以上、AとBとの間の余白を設定するためにはmargin-topを使うしかありません。
h2でmargin-bottomを管理している場合、広げるならなんとかなると思いますが縮めたい場合、pタグ側ではなくh2タグ側のmargin-bottomを打ち消すのは難しいです。

例外と注意の紹介

[例外]量がコントロールできず、かつ折り返しが発生する要素

例:Flexboxでタグの並びを実装して、flex-wrap: wrap; で画面幅に応じて折返しさせたい時

タグがいっぱい並ぶようなUI

ここまでの余白のルールを踏まえてスタイルを当てるなら、下記のように書くと思います。

.tagContainer {
  display: flex;
  flex-wrap: wrap;
  //他のスタイル省略 
}

.tag {
  & + & {
    margin-left: 8px;
    margin-top: 8px;
    //他のスタイル省略 
  }
}

こうすると、

  • 1段目に不要なmargin-topが生まれるのでBAD :x:
  • 2段めが生まれたときに、2段めの最初のタグに不要なmargin-leftができてしまうのでBAD :x:

なので、例外的にこうしていました。

.tagContainer {
  display: flex;
  flex-wrap: wrap;
 //他のスタイル省略 
}

.tag {
  & + & {
    margin-right: 8px;
    margin-bottom: 8px;
    //他のスタイル省略 
  }
}

しかし、Internet Explorerのサポートが切れた今なら gap で処理できます。

.tagContainer {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
 //他のスタイル省略 
}

[注意]任意要素が先に表示される

「余白は追加される方につける」のルールに則っていると別に例外ではないのですが、「margin-top,margin-leftで管理する」みたいな覚え方をしているとハマりやすいので「注意」として開発チームには共有しています。
ここでいう「任意」とは、「なくても成立する」、「ない場合がある」ものを指します。

例:任意(なくても成立する)のアイコンが文頭にくるとき

ユーザーが行動条件を満たしたときにチェックアイコンが表示されるUI

テキストの方に margin-left をもたせると、文字組みがずれてしまいます。
隣接セレクタなどで、アイコンがある場合margin-leftをつけることも可能ですが、それよりは任意の要素のチェックマークがmargin-rightを持つほうが、コードがシンプルになります。

:x: テキストがmargin-leftを持っている :white_check_mark: アイコンがmargin-rightを持っている
センタリングがずれてしまう 任意のもので調整できる

まとめ

  • 余白は追加される方につける
    • 末尾の要素の存在が任意である場合が多いため
    • 隣接セレクターを使った場合分けがしやすいため
  • [例外]量がコントロールできず、かつ折り返しが発生する要素はmargin-rightmargin-bottomを使う
  • [注意]任意要素が先に表示される場合は、margin-rightを使う

この記事が誰かのお役に立てると幸いです。

参考

8
0
1

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
8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?