CSSがわからないので詰まったところをメモ
使用するサイト
100 Days CSS
100 Days CSS というサイトを見つけた。これはCSSの問題を集めたサイトで、毎日1つのコードを書き、それを100日間続けようというもの。ちょうど100個の練習問題があるから面白そうなのを解いていく。
テンプレート
HTMLとCSSは以下のテンプレートを使う。frame
クラスのdiv
の中に書き込んでいく。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./style.css">
<title>Document</title>
</head>
<body>
<div class="frame">
// ここに書く
</div>
</div>
</body>
</html>
@import url(https://fonts.googleapis.com/css?family=Open+Sans:700,300);
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.frame {
position: absolute;
top: 50%;
left: 50%;
width: 400px;
height: 400px;
margin-top: -200px;
margin-left: -200px;
border-radius: 2px;
box-shadow: 4px 8px 16px 0 rgba(0,0,0,0.1);
overflow: hidden;
background: #fff;
color: #333;
font-family: 'Open Sans', Helvetica, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
1. キーボードを作るとき陥ったミス
完成図
疑問点
- 文字が縦並びになっている
- 文字は左づめされている
できてしまったもの
コード
コード
<div class="keyboard">
<div class="keyboard-row">
<div>A</div>
<div>B</div>
<div>C</div>
<div>D</div>
<div>E</div>
<div>F</div>
<div>G</div>
<div>H</div>
<div>I</div>
<div>J</div>
</div>
<div class="keyboard-row">
<div>K</div>
<div>L</div>
<div>M</div>
<div>N</div>
<div>O</div>
<div>P</div>
<div>Q</div>
<div>R</div>
<div>S</div>
<div>T</div>
</div>
<div class="keyboard-row">
<div>U</div>
<div>V</div>
<div>W</div>
<div>X</div>
<div>Y</div>
<div>Z</div>
</div>
<div class="keyboard-row">
<div>0</div>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
</div>
</div>
.keyboard {
background-color: #666;
border-top: 2px solid;
width: 100%;
height: 45%;
display: grid;
grid-template-rows: repeat(4, 1fr);
}
原因
なぜアルファベットが縦並びになったかというと、div
がブロック要素だからだ。ブロック要素は常に新しい行から始まるような挙動をする。コードではアルファベットを全てdiv
で囲んでいるため縦並びになったように見えたのだ。なので、ここではアルファベットが縦に並んでいると表現するより、ブロック要素を書き並べたのでデフォルトの挙動の通り全てが改行されて表示されている、と見るのが正確だ。
次にブロック要素の横幅、縦幅について書く。ブロック要素はサイズを指定しない場合、横幅は親要素の長さいっぱいに広がり、縦幅は子要素の高さいっぱいに広がる。ブロック要素は1つの塊として意味を持つ。divはグループ化、pは段落、h1は見出しのようにレイアウトとしての役割を持つ。HTML/CSSは元は文書を書くためのフォーマットだ。Wordで書く文章を思い出してみるといい。ブロック要素は1ページ目のタイトルをイメージしよう。改行するのは当たり前だ。仮にタイトルのすぐ隣の文字に本文が並ぶと読みにくい。改行されるのだから横幅は親要素の長さいっぱいに広がるのも自然だ。仮にブロック要素の横幅が子要素の長さだとすると、元の行の横がスカスカになってしまう。縦幅が子要素の高さいっぱいになるのは自然だ。なぜならタイトル欄には必ずタイトルの文字が入り、文字の高さだけ確保できれば縦幅としては十分だからだ。
HTMLは見えない四角形をイメージすべきで、四角形が横幅いっぱいに、縦はなるべく少なく配置されている。これがメンタルモデルだ。
すると文字が左づめされているのも自然に思えてくる。というかdivも左に詰められていたのだ。htmlは左から右、上から下が基本だから中の文字も左から始まっている。
ちなみにアルファベットのdiv
にボーダーを引いたら挙動がわかりやすい。このようにdivは横いっぱいに広がり改行されている様子がはっきりわかる。下のコードを追記すればいい。
.keyboard-row {
> div {
background-color: aqua;
border: #333 1px solid;
}
}
day70
2x2のマスを作るとき
こう書くのではなく
.calendar {
display: grid;
grid-template-areas:
"fri satu"
"sun mon";
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
}
こう書く
.calendar {
display: grid;
grid-template: repeat(2, auto) / repeat(2, auto);
}
grid-template
はgrid-template-rows
とgrid-template-columns
とgrid-template-area
を組み合わたショートハンド。ただし今回はgrid-area
を使ったエリア分けを使ってないので、同じコードを長く書けば次のようになる。
.calendar {
display: grid;
grid-template-rows: repeat(2, auto);
grid-template-columns: repeat(2, auto);
}
grid-template
はp.135のような書き方がフル活用したもの。ただしcolumnとrowの省略としても使える。
place-content
とplace-item
の違い
place-content
はグリッドの
個別でtext-align:center
を使わなくてもplace-item:center
を使うことで中央揃えにできる。グリッドから孫要素を中央揃えにできる。text-item:center
はグリッドの子要素を真ん中にできる
ここで使ったコンテンツ、アイテムという言葉はCSS Grid で用いられる用語。勝手に子要素、孫要素と言い換えないこと。用語を使って理解すべき内容。
実験してみる
place-content
のみ
place-content:center
のみを記述した場合は以下の画像のようになる。コンテンツは縦横中央揃えになっているが、コンテンツの横幅は2アイテムspan
の最大横幅に合わせている。他方のspan
もコンテンツの最大横幅と同じ広さになっていることが分かる。これは、親をgridにしていると子要素のdisplay
は自動的にgrid-item
に変わるからだ。grid-item
の横幅はgrid-template-*
など親のグリッドで指定される。なのでspan
だからインライン要素だ、と即断してはいけない。ちなみに、孫要素以降のdisplay
はgrid
による影響を受けないので、デフォルトのdisplay
値のままだ。
コード
.grid-item {
display: grid;
place-content: center;
/* place-items: center; */
> span {
border: 2px black solid;
}
}
place-content
とplace-item
の両方
今度はアイテムの横幅が文字幅に合わせて最小化された。place-items:center
は
justify-items: center;
align-items: center;
のショートハンドだ。なのでなぜこうなるかはjustify-items
プロパティとalign-items
プロパティの両方の挙動を知る必要がありそう。これについては本を読もう。
継承について
プロパティに値は親から子へ受け継がれるものと、受け継がれないものがある。これをプロパティの継承という。例えばcolor
プロパティは子に受け継がれる。しかしborder
プロパティで指定した値は子に受け継がれることはない。プロパティによっては継承されるものと継承されないものがあるので大まかに押さえておくのが立つ初心者のステップ。把握はしてなくとも、継承の概念さえ知っていれば何も指定してないのに色が変わってしまったときに驚く必要はなくなる。
要素の配置は各要素の設定や相互関係ではなく間隔で制御します。、グリッドを介してコントロールします。サイズや間隔も、グリッドの行列のサイズと感覚で制御します。
p82
この説明は腑に落ちた。今までは 要素の配置をmargin
、float
、position
で設定してきたがグリッドを介して制御することになる。サイズや間隔もtext-align
、width
、margin
で行ってきたこともグリッドを介して制御する。これは新しい考え方だから慣れなきゃいけない。
上の練習問題ではplace-content
とplace-item
でコンテンツとアイテムを中央揃えにしたが、これはグリッド的に正しいらしい。
display: grid
を適用した要素がグリッドコンテナとなり、グリッドを構成する
グリッドコンテナ直下の子要素がグリッドアイテムとして扱われ、グリッドに配置される
p.86
こう書いてあった。「グリッドコンテナとなる」「グリッドアイテムとして扱われる」というのはとても曖昧だ。何か特定のプロパティ値が変わるのだろうか。とはいえ別に何かの値が変わるとかではないのだろう。gridで作られたサイト見つけたら確認してみたい。
既定では、ブロックレベル要素のコンテンツは、それを包含する親要素の利用可能なインライン空間を満たし、そのコンテンツを収めるためにブロック方向へ成長します。インラインレベル要素のサイズは、そのコンテンツのサイズだけです。 width や height を、 display プロパティが既定で inline である要素、例えば <img> に設定しても、 display 値は inline のままです。
こんな解説文を見た。カレンダーのところで詰まったときに欠けていた知識は、全てこの文章に含まれている。ブロック要素かインライン要素かによってwidth
とhegiht
のデフォルトの大きさは変わってくる。そのルールがこれ。
ブロック方向とは垂直方向を表し、インライン空間?とは水平方向を表しているのだと思う。インラインとは in-line、つまり行の中という意味だ。行は横に広がっていくものなので、インラインも水平方向のことを意味してる。
displayのマルチキーワードについて
マルチキーワード構文では、1つ目の値として「外から見たその要素自身のフローレイアウト内での役割(どのようにレイアウトされるか)」と、2つ目の値として「要素内で使用するレイアウトモデル」を指定します。
p.95
display
をマルチキーワードは次のように書ける
display: <アウター・ディスプレイタイプ> <インナー・ディスプレイタイプ>
アウター・ディスプレイタイプに指定できるもの
- block
- inline
- run-in
など
インナー・ディスプレイタイプに指定できるもの
- flow
- flex
- grid
この観点はなかった。要素は入れ子状になっているので、ある要素は外から見たときの役割と内から見たときの役割を気にする必要がある。
「grid
はフローレイアウトと違う」というのに違和感を感じていたが解決した。grid
レイアウトは万能層に見えるが、全てのレイアウトをグリッドで作成するわけではない。body
タグにdisplay: grid
を書くわけではない。となるとグリッドレイアウトはフローレイアウトで無理矢理作っていたUIを書き換えることができるだけで、ブロックやインラインはどこかで使われる。
ちなみに
display: grid
をマルチキーワードで書くと display: block grid
となる。
display: block
をマルチキーワードで書くとdisplay: block flow
となる。
ブロックやインラインの概念は依然として残り、フローレイアウトも残っている。名残などではなく、ブロックもインラインもフローレイアウトもいまなお健在である。
デフォルトの挙動を知らねば
標準の位置揃えは「normal」に設定され、アイテムが縦横比を持つかどうかによって処理が変わります。「縦横比を持つもの」として扱われるのは画像や
aspect-ratio
で縦横比を指定したアイテムです。
<h2>
で構成した.item1
は縦横比を持たないため、標準では「stretch」で処理され、配置先のトラックに合わせたサイズにして配置されます。
<img>
は画像で縦横比を持つため、標準では「start」で処理され、オリジナルのサイズでトラックの左上に揃えて配置されます。
p.156
と書いてあった。やはり気にするべきはデフォルトの挙動。デフォルトの挙動を知らなきゃ何が起きているのかわからない。
他には gridではデフォルトでgrid-auto-flow: row
となっている。
fr は柔軟
fr と autoの違い
本質的には「残ったスペースでの割合」を決めるもの
grid-template-columns: 1fr 3fr;
これは残ったスペースから横幅を25%、75%に設定するもの。だが柔軟に対応する。
grid-template-columns: 25% 75%;
このように数値を直接入力するのは良くない。例えばpaddingやgapを設定すると横幅は100%を超えてしまいオーバーフローが発生する。オーバーフローにより、スクロールバーが現れる。このように%で直接数値を設定すると思った通りに動かないことがある。
しかしfr
単位で入力した場合、paddingを差し引いて残ったスペースから25%と75%の横幅を計算する。なのでCSSが崩れることはない。fr
は残ったスペースからサイズの割合を振り分けるので変更に強いプロパティなのだ。なお、fr
は1桁の数字という制限はない。細かい比率を設定したければ次のように書くこともできる。
grid-template-columns: 42fr 33fr 25fr
ガターサイズも自動で差し引くらしい。
他にもfr
は他の単位とも組み合わせることができる。60% 1fr 2fr
とか100px 1fr 1fr
みたいに。
あとはgrid-template-areas
で.
と記述しておくと指定した箇所は空白にすることができる。
justify-content とalign-content
アイテムのサイズがコンテナーのサイズより小さくなるときについて考える。アイテムのサイズをpx
などの固定単位で定義したとき、アイテムのサイズがコンテナーのサイズを下回ることがある。こんなときはアイテムが思ったように配置されないことがある。そこでアイテムを整列させることができるプロパティがjustify-content
とalign-content
だ。justify-content
は横幅を整列させるもので、align-content
は縦幅を整列させるもの。
grid-auto-columns
を使う
カラム数がわからないときはgrid-template-columns
は明示的にグリッドを定義するプロパティなのでグリッド数が分かってるときに使う。grid-auto-columns
を使えば横並びになるアイテムの数が動的に変化するような場合でも自動的に配置される。
グリッドのコンテナを変えるタイミング
グリッドの線を引いたとき、ピッタリ収まらないコンテンツをコンテナにする
これは右にある黒いブロックが赤の点線に収まってない例。上の指針に従って、黒のブロックを.container-inner
と名付けてコンテナにしている。
カラム数を決める
use the smallest common multiple of the maximum number of columns required for the different screen sizes.
うまく解釈できず何を描いてるのかわからない