CSSを書くときに気をつけたい基本的なtips
CSSをレビューしていたりすると、お?これは、、、みたいなことがちょいちょいあります👀
例えばfigma等からコピペしてもってきたコードなんかもあると思いますが、よく見る気をつけたほうが良さそうなtipsをいかに列挙していきたいと思います💪
■ line-height
line-height
というのはなかなかの曲者です。こいつのせいで意図しない動きをしたりする場面があります👀
値に単位を含めるな問題
MDNを見ても書かれていますが、line-height
の値においては単位をつけないことが推奨されています👀
.hoge {
line-height: 1.5; /* OK */
line-height: 150%; /* NG */
}
理由としては、line-heightに単位をつけると、px
等の場合はその値に、%
等の場合はそのコンテキストの一意の相対値に決まってしまうからです。
単位を付与しないことで、例えば文中に16px
と24px
の指定が混在していたとしてもよしなにline-height
を算出してくれるようになります🙆🏻♂️
imgとかに変な隙間生まれるなー問題
line-height
が全体にあたっているときなどに、inline-block
要素にも影響が出ます。よくあるのはimg
の下部に変な隙間が出る問題です。
img
にdisplay: block
を当てると解決します。
全体にline-height: 1;
を当てちゃう
僕はよくこれをやっています。
body {
line-height: 1;
}
なんとなく今まで制作をしてきて、line-height
が全体にあたっていてメリットを感じたことがないからです。
なにか隙間が出たりとか、そもそも、各コンポーネントでline-height
が異なってしまうとか、、、
であれば、必要なところで個別で当ててやったほうが早いよね、みたいな動機です🚂
■ width
widthなんにでも書いちゃう問題
これはちょいちょい見ることもあるかと思うんですが、何にでもwidth: 100%
があたっている場合があります👀
実際、それで問題になることはそこまで多くないんですが、display: block;
の場合すでにwidth: 100%;
です。
display: flex;
等の場合もそうです。
逆に指定したほうがいい場合もあります。
思いつく限り以下に列挙してみました
- 要素の幅が決まっている場合
-
display: table
の場合- 内部のコンテンツによってしまうので、もし100%にするなら
width
を指定する必要があります
- 内部のコンテンツによってしまうので、もし100%にするなら
-
display: table-cell;
の場合- どのくらいの割合なのかを%で指定するなどしてあげたほうが崩れなくてすみます
- flexの子要素の場合
- 中のサイズに依ってしまうので、指定してあげる必要がある場合の方が多いイメージです
-
position
がabsolute
またはfixed
の場合- 中のサイズに依ってしまうので、必要であれば指定しましょう
■ display
display: block
なんにでも書いちゃう問題
いろんなものにdisplay: block;
が与えられているのを見たことがあるかもしれません。
多くの場合ブロックレベル要素はdisplay: block;
が初期値です(tableなんかは違いますが)。
なので、再度当てる必要はありません。
また、position: absolute
またはposition: fixed
が指定された要素は、display: block
になります。
これは出典が見当たらなかったですが、例えばchromeでspan
にposition: absolute
をかけてデベロッパーツールでcomputed欄を確認すると、display
がblock
になることが確認できると思います。
なので、これらのposition
が指定されている場合には、別途display: block
を指定する必要はありません。
■ z-index
なんか当たらない問題
z-index
で大きい値を当てているにも関わらず何故か思ったように動かない🤔
みたいなことは多くの人が経験があるかと思います🍙
結果、よくわからないけど、大きい数字を当てたりすることになるのですが、z-index
の仕組みを知るとおそらくそこまで大きな数字が必要でないことがわかると思います🙆🏻♂️
■ 重ね合わせコンテキストを理解する
z-index
はそもそも重ね合わせコンテキストがない状態では効きません。
以上のリンクを読むとわかると思いますが、例えばposition
が初期値static
の状態ではz-index
をいくら大きな値にしたとしても効くことはありません。
z-index
が効くようにするには重ね合わせコンテキストが生成されるスタイルがあたっている必要があります(例えばposition: relative
なんかがお手軽です)。
そして、z-indexの比較はコンテキスト内での比較となります。
<style>
div {
position: relative;
}
</style>
<div id="hoge" style="z-index: 1">
<div id="hoge-child" style="z-index: 100"></div>
</div>
<div id="fuga" style="z-index: 2">
<div id="fuga-child" style="z-index: 50"></div>
</div>
これだと、#fuga
> hoge
なので、その子要素のz-index
がどうであろうと、#fuga-child
> #hoge-child
になります。
なお、デフォルトではあとに記述された要素のほうが、重ね順は上になります。
また、何も設定しないときの値は0
で負の数を指定することで重ね順をマイナスにすることも可能です。
■ 最初以外、などのいい感じの指定の仕方
最初だけ、最後だけはmargin
を当てたくない、みたいな需要はよくあると思います🍣
そういうわけでそういうときによく使うやつを書いておきます。
li + li
<style>
li + li {
margin-top: 8px;
}
</style>
<ul>
<li>当たらない</li>
<li>hoge</li>
<li>hoge</li>
<li>hoge</li>
</ul>
例えばli
を複数持つul
があったとした場合、これは最初のli
以外にスタイルが当たることになります。
+
は隣接兄弟結合子というらしいですが、hoge + fuga
だと、前にhoge
があるfuga
という指定になります。
この例で行くと、最初のli
は前にli
がないためこの指定からは外れ、最初以外となるわけです。
:not(:first-child), :not(:last-child)
:not()
は直感的な名前でいいですね。
よく使うのは :not(:first-child)
や:not(:last-child)
あたりです。
今はgrid
があるので、そういう機会はないかもしれませんが、例えば、display: flex;
で3こずつで折り返す要素を作ったときに、
- 最後の3個以外は
margin-bottom
を当てたい - 3n個目の要素以外には
margin-right
を当てたい
みたいなことがあったとします。その場合は、
<style>
.list {
list-style: none;
display: flex;
flex-flow: row wrap;
}
.list > li {
width: 30%;
height: 100px;
background-color: red;
}
.list > li:not(:nth-child(3n)) {
margin-right: 5%;
}
.list > li:not(:nth-last-child(-n + 3)) {
margin-bottom: 16px;
}
</style>
<ul class="list">
<li>テスト</li>
<li>テスト</li>
<li>margin-right当たらない</li>
<li>テスト</li>
<li>テスト</li>
<li>margin-right当たらない</li>
<li>marign-bottom当たらない</li>
<li>marign-bottom当たらない</li>
<li>margin-right, marign-bottom当たらない</li>
</ul>
のようにすることができます🙆🏻♂️
■ > でコンテキストを絞る
例えばul.list > li
みたいなDOMがあったとき、li
にいちいちクラスをつけるのがめんどくさい、みたいなことはよくある話です💀
そんなとき、愚直に
.list li {
padding: 8px;
}
みたいにすると、例えば以下のようなときに問題になります。
<ul class="list">
<li></li>
<li>
<ul>
<li></li>
</ul>
</li>
</ul>
まぁ当たり前な話ではあるんですが、web制作の文脈ではなく、アプリケーションのコンポーネントを考えたときに、このli
がchildren
を受け取る要な場合、children
は何が入ってくるか知ることができません。
そういうわけで>
をつけることで直接の子のみに絞ってしまいましょう。
.list > li {
padding: 8px;
}
■ クラスつけるのだるいよね、みたいなとき
例えば、ある程度深いところの要素にスタイルをつけるとき、クラス名をつけるのがだるい、みたいなこともよくあります。
例えばBEMなんかだと、.block__element__element
くらいまで来て、あー次のelementを書くのはちょっとやだなーみたいなことがあります。
そういうときは子結合子で要素を取得してしまうのもありだと思いますが、あるいは僕は_
付きのクラス名を付与して使うみたいなことをやっています。
<div class="profile">
<div class="profile__content">
<div class="profile__content_detail">
<div class="_age">60歳</div>
<p class="_text">HELLO</p>
</div>
</div>
</div>
このとき、_
付きのclassを使う場合は以下のようなルールを設けています
- 必ず、親要素の子孫(または子)結合子とともに使用される
- 一階層以上のネストを持たない
- 必ず子を把握できる(childrenなどを入れない)
これは単純にルールの問題なので、単純にこんな風にしているという紹介でした🙏
■ メディアクエリでいい感じの書き方
スマホとPCでそれぞれ違う値を設定するみたいなことがあると思います。
SCSS、またはemotion等を使っている場合、そんなときにこのような書き方をすると見通しが良くなる場合があります。
例はemotionです。
const Hoge = styled.div`
background-color: red;
@media (max-width: 767px) {
padding: 8px 16px;
}
@media (min-width: 768px) {
padding: 16px 24px;
}
`;
max-width: 767px
はスマホ用、min-width: 768px
はPC用です。
本当は変数にこのあたりを入れてわかりやすくしてやるとより良いと思います。
このようにして書くことで、各要素のスマホとのときの値とPCのときの値がすぐに分かるようになります。
また、この書き方のポイントは共通のものと各メディアクエリのものを分けて書くことです。
メディアクエリ間で打ち消しを行わないように書くことで、各デバイスごとのスタイルを変更する場合への心理的な障壁が下がります。
// 良くない例
// これくらいの量だと把握は可能だが、数が増えてきた場合、
// どのプロパティが関連しているかわからなくなってくるので明示的に分けてあげたほうが理解しやすい
const Hoge = styled.div`
background-color: red;
padding: 16px 24px;
@media (max-width: 767px) {
padding: 8px 16px;
}
`;
ただ、ヘッダーのグローバルナビなどでそもそもPCとSPで全くデザインが違うような場合があります。
こういう場合はまるっきり分けて書いてしまったほうが見通しが良い場合もあります。
const spNavStyle = css`
@media (max-width: 767px) {
& > .nav {
padding: 8px 16px;
...
}
}
`;
const pcNavStyle = css`
@media (min-width: 768px) {
& > ..nav {
padding: 16px 24px;
...
}
}
`;
SCSSの例
SCSSだと、こんなmixinを作ると
// media queries
@mixin max-screen($break-point) {
@media (max-width: $break-point) {
@content;
}
}
@mixin min-screen($break-point) {
@media (min-width: $break-point) {
@content;
}
}
@mixin screen($break-point-min, $break-point-max) {
@media (min-width: $break-point-min) and (max-width: $break-point-max) {
@content;
}
}
このように使えます
.hoge {
@include max-screen(767px) {
padding: 8px 16px;
}
@include min-screen(768px) {
padding: 16px 24px;
}
}
そういうわけで
基本的なtipsが多かったですが、CSSは破綻しやすいものでもあるので、少しずつ気をつけられたらと思います🧠
また思いついたら追記します🛹
Discussion