Astroの光線のサムネイル。

pubDate: 2024-06-15

author: sakakibara

astro

公開学習

後退

コミュニティ

CSSの基本

悪いCSSとは

CSSは普通に書いていると、どんどんと複雑になっていく。 しばらく経つと、どこを変更したらどこに影響がでるのかわからなくなり、その上、多くのセレクタが氾濫してしまう。 良いCSSを書くことは難しい。
そこで、悪いCSSを避けることを考える。

HTMLの構造に依存するCSS

<div>
<h1>
<p>This is a sentence</p>
</h1>
</div>
div h1 p {
color: red;
}

これが

<div>
<h2>
<p>This is a sentence</p>
</h2>
</div>

になったらCSSを書き直さなければならなくなる。 対策として

<div class="entry">
<h2 class="entry__title">
<p>This is a sentence</p>
</h2>
</div>
.entry__title {
color: red;
}

のようにする。

なるべく

div h1 p ul li a {
color: red;
}

のようなHTMLの構造に依存しているCSSは避けるべきである。

この点から、セレクタの連なりは長くなりすぎない方が良いだろう。

取り消しのルールが多いCSS

次のようなスタイルがあるとする。

.title {
border-bottom: 1px solid #000;
padding: 10px;
}

しばらくはこれで良かったが、そのうち、border-bottomを消したくなったとする。 すると次のようなCSSを書くだろう。

.no_border {
border-bottom: none;
padding-bottom: 0;
}
<h2 class="title norborder">This is a title</h2>

これが取り消しルールである。例外とも言える。

対策として、例外的なルールとそれまでのルールの共通部分を抜き出して、 それまでのルールに追加するルールを作成する。

.title {
margin-bottom: 10px;
font-size: 2em;
}
.headline {
padding-bottom: 10px;
border-bottom: 1px solid #000;
}
<h2 class="title headline">This is a title</h2>

共通部分を抜き出すという点からは一つのスタイルのプロパティの数は少なく、小粒であり、しかも共通部分を抜き出すという点からスタイルそのものの数も少なくなるべきだろう。

マジックナンバーが多いCSS

言わずもがな、マジックナンバーは避けるべきである。

対策として, 計算と継承をする。 これが、

.intoduction {
line-height: 27px;
font-size: 18px;
}
.lead {
line-height: 54px;
font-size: 36px;
}

こうなる。

.intoduction {
line-height: 1.5;
font-size: 18px;
}
.lead {
font-size: 36px;
}

一つ目はline-heightがfont-sizeの1.5倍であることを利用して、font-sizeが変わっても見た目がline-heightの見た目が変わらないようにしている。 二つ目はline-heightが継承されるため、line-heightを指定しなくても良い。 実は、フォント系のプロパティ(font-size, color, line-height)などのプロパティはこの要素に継承される。 また、

line-height: 1.5;

ではなく、

line-height: 1.5em;

としてしまうと、

.lead {
# line-height: 27px; 本当は36 * 1.5 = 54pxが欲しいが、18 * 1.5 = 27pxになってしまう
font-size: 36px;
}

計算された値が適用されてしまうので注意が必要である。 まとめると

モバイルファースト

レスポンシブwebデザインの考え方の一つで、モバイルファーストという考え方がある。 これはレスポンシブ対応のwebページを作る際に、まずはスマートフォンサイズのページを作り、次にタブレットサイズ、PC用とだんだんと大きな画面に対応していくという考え方である。

これはスマートフォンの利用者が増加してきたことから、モバイルサイズの画面により優先して注力すべきだという考え方である。

Mobile First

normalize CSS

CSSはブラウザによってデフォルトでスタイルが異なる。 それらを一旦リセットして、すべてのブラウザで同じスタイルを適用するためにnormalize.cssを使う。 normalize.css

<link rel="stylesheet" href="../node_modules/normalize.css/normalize.css">

CSSのセレクタ

CSSは以下のようにセレクタとプロパティを使ってスタイルを適用する。

selector {
property: value;
}

CSSには数百のプロパティがあるが、基本的なものを以下に示す。

id selector

特定のタグに固有の一意の識別子をつける。

<p id="interesting">This is interesting.</p>
p {
color: red;
}
#interesting {
color: blue;
}

のように、idセレクタは#で指定する。 <p id="interesting">pタグが適用されるが、CSSは後段の設定が優先されるため、color: blue;が適用される。

class selector

特定のタグをクラスに振り分ける。

<p class="important">This is important.</p>
p {
color: red;
}
.important {
color: yellow;
}

idセレクタと似ているがクラスは複数個所で指定できる。 importantクラスのように, クラスは.で指定する。 <p class="important">pタグが適用されるが、CSSは後段の設定が優先されるため、color: yellow;が適用される。

li selector

ulolの中にあるliタグを指定する。 ulolにはlist-style-typeプロパティがある。これはリストのマーカーの形を指定する。

<ul>
<li>item 1</li>
<li>item 2</li>
</ul>
ul {
display: flex;
list-style-type: none;
justify-content: space-between;
width: 30%
}

ヘッダーなどで使用する場合にdisplay: flex; justify-content: space-betweenを指定することが多い。

a selector

aタグはリンクを指定する。

<ul>
<li><a href="https://www.google.com">Google</a></li>
<li><a href="#">hoge</a></li>
</ul>
a {
color: inherit;
text-decoration: none;
}
a: hover {
color: red;
text-decoration: underline;
}

color: inherit;は親要素の色を継承する。 text-decoration: none;は下線を消す。 a: hoverはマウスが乗った時のスタイルを指定する。 :hoverは疑似クラスと呼ばれるセレクタに追加するキーワードであり、選択された要素の状態を指す。

また、<a href="#">はnull linkと呼ばれ、何もリンク先が指定されていないリンクを指す。

擬似クラス

:hover以外にもかなり多くの疑似クラスがある。 それらはいくつのグループに分けられる。

属性

<a href="https://www.google.com" target="_blank">Google</a>
a[target="_blank"] {
color: blue;
}

aタグでかつtarget="_blank"の属性を持つものにcolor: blue;を適用する。

結合子

<p>This is a paragraph.</p>
<div>
<p>This is a first paragraph.</p>
<section>
<p>This is a second paragraph.</p>
</section>
</div>
<p>This is a four paragraph.</p>
div p {
color: red;
}

これはdivタグの中にあるpタグにcolor: red;を適用する。 これはdivの下にあるpタグにどこまでも再帰的に適用される。 これを子孫結合子という。

div > p {
color: blue;
}

これはdivタグの直下にあるpタグにcolor: blue;を適用する。 これはdivの直下のみにあるpタグにのみ適用される。 これを子結合子という。

div + p {
color: green;
}

これはdivタグの次に並ぶpタグにcolor: green;を適用する。 これは入れ子ではなく、divの次に隣接するpタグにのみ適用される。 これを隣接兄弟結合子という。

div ~ p {
color: yellow;
}

これはdivタグの後ろ(直後でなくても良い)にpタグがある場合にcolor: yellow;が適用される。 これは後続兄弟結合子という。

box model

webページの各要素はすべてが矩形の領域で構成されている。 この矩形の領域をboxと呼び、boxの組み合わせによってきれいなwebページが作られる。

まず、内容を格納するcontentがあり、 borderがある。 borderの内側がpaddingで外側がmarginである。

Diagram

このboxにはdisplayプロパティがあり、以下のように分類される。 これには書字方向(writing-mode)が関係している。 書字方向は縦書きと横書きがある。 日本語などは横書きであるが、アラビア語などは縦書きである。 boxが積まれる方向をフロー方向と呼ぶ。 boxがblockの場合、フロー方向は書字方向と垂直になる。 また、フロー方向を主軸、垂直方向を交差軸と呼ぶ。

box系プロパティ: それ自体の振る舞いを変える

displayプロパティ説明
block要素は書字方向いっぱいに広がる。結果、書字方向とは垂直に積まれる。
inline要素は書字方向に積まれる。
inline-block要素は書字方向に積まれるが、block要素のように幅や高さを指定できる。
none要素は非表示になる。

つまり、パラグラフに割り当てて考えればblockは段落を、inlineは単語に該当する。

整形系(コンテキスト)プロパティ: その子の振る舞いを変える

displayプロパティ説明
flexその子のフロー方向を制御する。
gridその子はグリッド上に割り当てられる。

たとえば、pタグはFireFoxのデフォルトでは display: block;となっている。

flex

子を敷き詰める効果がある。 flexを指定すると、何も指定がなければフロー方向が書字方向(水平)になる。

縦積みになっている状態で flexを横積みにすると、各boxの横のスペースを検知し、それを埋めるように横に積む。

横積みになっている状態で flexを縦積みにすると、各boxの縦のスペースを検知し、それを埋めるように縦に積む。

property values description
flex-direction フロー方向の指定 row(子を列に並べる, 水平方向)
column(子を行に並べる、垂直方向)
property values description
justify-content 主軸方向に沿って内部アイテムどうしの間隔を配分する start
center
space-between
space-around
align-content 交差軸方向に沿って内部アイテムどうしの間隔を配分する。これはflexが折り返し設定され複数行にまたがっている時にしか有効ではない。折り返された複数行におけるjustify-contentのようなもの start
center
space-between
space-around
justify-items 軸上のアイテムの"配置"を制御する strech
center
start, end
align-items 交差軸上のアイテムの"配置"を制御する strech
center
start, end
まず、`justify-content`でどっちの軸に沿ってにboxがあるかを確認してから`align-items`でその交差軸上での配置を考えるとわかりやすい。
property values description
flex-basis flexアイテムのサイズの初期値を設定する。 大きさはcontent-boxが設定される 30px
flex-grow flex-grow係数を設定する。空き領域の分だけ伸長する。flex-grow指定されていないアイテムは伸長されない。flex-grow指定されているアイテムはその合計に対する比に応じて伸長する 0
flex-shurink flex-growの反対。縮小する 0
flex flex-grow flex-shurink flex-basisの一括設定 1 1 50px

grid

gridはその名の通り、グリッド上に要素を配置することができる。 gridで囲む要素をグリッドコンテナ、その中に配置される要素をグリッドアイテムと呼ぶ。 最も簡単な方法は以下の通り

.container {
display: grid;
girid-template: 1fr 3fr 1fr / 1fr 2fr 1fr 1fr;
}

グリッドコンテナのプロパティは以下の通り。 グリッドをどのように配置するかを指定する。

個々のグリッドアイテムがどのグリッドに割り当てられるかを指定する。

個々のグリッドアイテムのレスポンシブな配置を指定する。

以上のショートハンドが以下。

box-sizing

boxの大きさをboxモデルのどこまで含めるか、boxモデルの何をsizingの対象とするのか、を指定するプロパティとしてbox-sizingがある。

box自体の大きさはcontent + padding + borderで構成される。

div {
width: 10rem;
padding: 1rem;
}

デフォルトではbox-sizingはcontent-boxである。
この場合、sizing(width: 10rem)により、div自体の幅は10rem + 1rem + 1rem = 12remとなる。

box-sizingをborder-boxにすると、 div自体の幅は10remとなる。

一般的にはborder-boxを使うことが良しとされる。

注意すべき点として、box-sizing: content-box; は親要素がbox-sizing: border-box; である場合、親要素のpaddingが子要素の幅に含まれないことがある。

div {
box-sizing: border-box;
width: 10rem;
}
p {
box-sizing: content-box;
width: 100%;
padding: 1rem;
}
<div>
<p>text</p>
</div>

width:100%の意味は親要素のbox-sizingに対して100%となることを意味する。 親要素(div)のbox-sizingはborder-boxであり、borderのサイズは10remとなり、boxのサイズは10remとなる。
これに対して、子要素(p)のbox-sizingはcontent-boxであり、contentの大きさは親要素の100%なのでcontentの幅が10remとなる。よって, paddingを含むとboxの大きさは12remとなる。結果、子要素は親要素の幅を超えてしまう。