Open15

CSSがわからないので詰まったところをメモ

ひげひげ

使用するサイト

100 Days CSS
https://100dayscss.com/

100 Days CSS というサイトを見つけた。これはCSSの問題を集めたサイトで、毎日1つのコードを書き、それを100日間続けようというもの。ちょうど100個の練習問題があるから面白そうなのを解いていく。

テンプレート

HTMLとCSSは以下のテンプレートを使う。frameクラスのdivの中に書き込んでいく。

index.html
<!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>

style.css
@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. キーボードを作るとき陥ったミス

完成図


https://100dayscss.com/days/71/

疑問点

  • 文字が縦並びになっている
  • 文字は左づめされている

できてしまったもの

コード

コード
html
    <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>
css
.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は横いっぱいに広がり改行されている様子がはっきりわかる。下のコードを追記すればいい。

css
.keyboard-row {
  > div {
    background-color: aqua;
    border: #333 1px solid;
  }
}

ひげひげ

day70

2x2のマスを作るとき

こう書くのではなく

css
.calendar {
  display: grid;
  grid-template-areas: 
  "fri satu"
  "sun mon";
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
}

こう書く

css
.calendar {
  display: grid;
  grid-template: repeat(2, auto) / repeat(2, auto); 
}

grid-templategrid-template-rowsgrid-template-columnsgrid-template-areaを組み合わたショートハンド。ただし今回はgrid-areaを使ったエリア分けを使ってないので、同じコードを長く書けば次のようになる。

css
.calendar {
  display: grid;
  grid-template-rows: repeat(2, auto);
  grid-template-columns: repeat(2, auto);
}

grid-templateはp.135のような書き方がフル活用したもの。ただしcolumnとrowの省略としても使える。

ひげひげ

place-contentplace-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だからインライン要素だ、と即断してはいけない。ちなみに、孫要素以降のdisplaygridによる影響を受けないので、デフォルトのdisplay値のままだ。

コード
css
.grid-item {
  display: grid;
  place-content: center;
  /* place-items: center; */
  > span {
    border: 2px black solid;
  }
}

place-contentplace-itemの両方

今度はアイテムの横幅が文字幅に合わせて最小化された。place-items:center

css
justify-items: center;
align-items: center;

のショートハンドだ。なのでなぜこうなるかはjustify-itemsプロパティとalign-itemsプロパティの両方の挙動を知る必要がありそう。これについては本を読もう。

ひげひげ

継承について

プロパティに値は親から子へ受け継がれるものと、受け継がれないものがある。これをプロパティの継承という。例えばcolorプロパティは子に受け継がれる。しかしborderプロパティで指定した値は子に受け継がれることはない。プロパティによっては継承されるものと継承されないものがあるので大まかに押さえておくのが立つ初心者のステップ。把握はしてなくとも、継承の概念さえ知っていれば何も指定してないのに色が変わってしまったときに驚く必要はなくなる。

https://developer.mozilla.org/ja/docs/Web/CSS/Inheritance

ひげひげ

要素の配置は各要素の設定や相互関係ではなく間隔で制御します。、グリッドを介してコントロールします。サイズや間隔も、グリッドの行列のサイズと感覚で制御します。
p82

この説明は腑に落ちた。今までは 要素の配置をmarginfloatpositionで設定してきたがグリッドを介して制御することになる。サイズや間隔もtext-alignwidthmarginで行ってきたこともグリッドを介して制御する。これは新しい考え方だから慣れなきゃいけない。

上の練習問題ではplace-contentplace-itemでコンテンツとアイテムを中央揃えにしたが、これはグリッド的に正しいらしい。

ひげひげ

display: gridを適用した要素がグリッドコンテナとなり、グリッドを構成する
グリッドコンテナ直下の子要素がグリッドアイテムとして扱われ、グリッドに配置される
p.86

こう書いてあった。「グリッドコンテナとなる」「グリッドアイテムとして扱われる」というのはとても曖昧だ。何か特定のプロパティ値が変わるのだろうか。とはいえ別に何かの値が変わるとかではないのだろう。gridで作られたサイト見つけたら確認してみたい。

ひげひげ

既定では、ブロックレベル要素のコンテンツは、それを包含する親要素の利用可能なインライン空間を満たし、そのコンテンツを収めるためにブロック方向へ成長します。インラインレベル要素のサイズは、そのコンテンツのサイズだけです。 width や height を、 display プロパティが既定で inline である要素、例えば <img> に設定しても、 display 値は inline のままです。

https://developer.mozilla.org/ja/docs/Learn/CSS/CSS_layout/Normal_Flow#要素は既定でどのようにレイアウトされるか

こんな解説文を見た。カレンダーのところで詰まったときに欠けていた知識は、全てこの文章に含まれている。ブロック要素かインライン要素かによってwidthhegihtのデフォルトの大きさは変わってくる。そのルールがこれ。

ブロック方向とは垂直方向を表し、インライン空間?とは水平方向を表しているのだと思う。インラインとは 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の違い
https://kumonosublog.com/coding/css/grid_layout_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桁の数字という制限はない。細かい比率を設定したければ次のように書くこともできる。

css
grid-template-columns: 42fr 33fr 25fr

ガターサイズも自動で差し引くらしい。
https://css-tricks.com/snippets/css/complete-guide-grid/#aa-special-units-functions

他にもfrは他の単位とも組み合わせることができる。60% 1fr 2frとか100px 1fr 1frみたいに。
あとはgrid-template-areas.と記述しておくと指定した箇所は空白にすることができる。
https://www.hongkiat.com/blog/css-grid-layout-fr-unit/

ひげひげ

justify-content とalign-content

https://css-tricks.com/snippets/css/complete-guide-grid/#aa-justify-content

アイテムのサイズがコンテナーのサイズより小さくなるときについて考える。アイテムのサイズをpxなどの固定単位で定義したとき、アイテムのサイズがコンテナーのサイズを下回ることがある。こんなときはアイテムが思ったように配置されないことがある。そこでアイテムを整列させることができるプロパティがjustify-contentalign-contentだ。justify-contentは横幅を整列させるもので、align-contentは縦幅を整列させるもの。

ひげひげ

カラム数がわからないときはgrid-auto-columnsを使う

grid-template-columnsは明示的にグリッドを定義するプロパティなのでグリッド数が分かってるときに使う。grid-auto-columnsを使えば横並びになるアイテムの数が動的に変化するような場合でも自動的に配置される。