レイアウトロジックとメンタルモデル.

この章ではcssのメンタルモデルを紹介します。

メンタルモデルとは頭の中にある「ああなったらこうなる」といった「行動のイメージ」を表現したものである

メンタルモデル[wiki]

メンタルモデルを構築する事はとても大切な事です。

例えばボールを投げた時、放物線を描いて着地します。

人間はそのボールがどこに落ちるかをある程度予想できますが、それは、その時に微積分を用いて計算して予想しているからではないですよね。

経験からこのぐらいの強さ、勢いがあればこの辺に着地するというメンタルモデルがあるからです。

メンタルモデルのないコンピュータはボールの着地点を予想するために微積分の計算が必要となります。

もし、予想するロジック以外の要素が含まれた時、(例えば、風が少し吹いたなど)コンピュータはエラーを吐き出します。

これと同じで、cssのメンタルモデルが無ければ、あなたはコンピュータのように、「数式が無いとできません」「やった事ないのでわかりません」という人間になってしまいます。

是非、メンタルモデルをゲットして、このデザイン作った事ないけど、こんな感じで行けるっしょという感覚を掴んでください。

目次

組み込み宣言と継承

基本的にCSSの目的は、webサイトのコンテンツの外観とレイアウトを制御できるようにすることです。

全く何もない所から始めるわけではなく、まずはHTMLタグが存在します。

そしてHTMLタグにいはくつかのスタイルが初めから組み込まれています。

たとえば、Chromeに組み込まれている<a>タグのスタイルは次のとおりです。

a {
  color: -webkit-link;
  cursor: pointer;
  text-decoration: underline;
}

これら、デフォルトでついているスタイルはユーザーエージェントスタイルシートといいます。

各ブラウザには、このような基本スタイルが記載された独自のスタイルシートが含まれています。コンテンツの見た目はブラウザ間で非常に異なって見えます。

その問題を解決するためにリセットcssを使用し、デフォルトのユーザーエージェントスタイルの多くを取り除きます。

リセットcss

リセットcssにはいくつかの種類がありますが主に2種類に分けられます。

  • すべてのcssを消したい場合 → desltye.css
  • デフォルトのスタイルを活かしつつ、差分を失くしたい → Normalize.css

上記の中でもおすすめなのは全てのcssを打ち消すdesltye.cssです。

css設計や、より柔軟なコーディングをする場合にデフォルトのスタイルが残っているとどうしても邪魔になってしまうのですべてのスタイルを消して、0から制作する方が楽になります。

それぞれこちらからコードを確認できますので、ダウンロードして読み込むかコピペで使用してください。

[git]desltye.css

[git]Normalize.css

Chromeのソースコード

ユーザーエージェントのスタイルシートについて詳しく知りたい場合は、ソースコードからChromeブラウザの完全なスタイルシートを見る事が可能です。

カスケード

こちらのcssを見てください。

<style>
  p {
    font-weight: bold;
    color: red;
  }
  .paragraph{
    color: green;
  }
</style>
<p class="paragraph">
  Hello world
</p>

上記のcssでは同じhtml要素に対して2つのルールを適応しました。

これを実行してみるとpタグセレクタのルールからfont-weightを受け継ぎ、paragraphクラスセレクタのルールにてcolorが上書きされ「Hello World」は緑の太字になります。

この例は、ブラウザのカスケードアルゴリズムが機能していることを示しています。

どの宣言が適応されるかはセレクタの具体性と優先度を計算して判断されます。

詳細度

cssセレクターには詳細度というものがあり、セレクターそれぞれで詳細度が異なります。

詳細度はセレクターの戦闘力と言ってもいいでしょう。

同じ宣言があった場合、戦闘力の高いルールの宣言が勝負に勝ち、スタイルとして適応されるというわけです。

セレクターは複数組み合わせて記載する事が可能です。

複数のセレクターを組み合わせた場合、フュージョンしたのと同じです。

それぞれの戦闘力が足しあわされて、最終的に最終的に戦闘力が高いものがスタイルとして適応されます。

詳細度の計算方法

詳細度にはセレクターの種類ごとに点数が決まっており、複数組わせたセレクターの場合はその点数の合計値を計算します。

点数
要素型セレクターh1, p, div などのタグ名1
クラスセレクター.example, .hoge, .class などのclass名10
ID セレクター #example, #hoge, #class などのid名 100
全称セレクター・結合子*, +, >, ~, ||影響無し

例えば以下の場合、「テキスト1」の色は何色になるでしょうか?

#example {
  color: green;
}

h1 > .example {
  color: red;
}

<h1>
  <p class="example" id="example">テキスト1</p>
</h1>

詳細度を計算しみましょう。

初めのルールはidセレクターを使用しています。ですので点数は100点です。

2つ目のルールは要素型セレクターとクラスセレクターを使用しています。

ですので1 + 10 = 11です。

100と11では100の方が強いのでこの場合は初めのルールが適応され、テキスト1の色は緑になります。

もう一つ以下の場合はどうでしょうか。

.example {
  color: green;
}

.example {
  color: red;
}

<h1>
  <p class="example">テキスト2</p>
</h1>

まったく同じルールが存在します。

この場合、cssは後に書かれた方を優先しますのでテキスト2の色は赤色になります。

!important

詳細度が高くなりすぎてしまい、スタイルを上書きしたくても上書きしてくれない場合はどうすればよいでしょうか。

解決策の1つとして!importantがあります。

h1 .example #example {
  color: black !important;
}

これは必ずこのスタイルと適応させるという意味になります。

詳細度を無視し、必ずこのスタイルが適応されます。

ですがこれは良くない解決策です。

最終手段として考えておきましょう。

スタイルの自然のカスケードを破壊するためデバッグがかなり難しくなります。

詳細度は気にしなくてよい&対策

詳細度の計算はかなりややこしいです。

例えば以下はどちらのスタイルが適応されるかすぐにわかりますでしょうか?

.form > button#submit
#about-page button:last-of-type

これはかなりの難題です。

さらにはcssを組んでいるともっと組み合わせの多いものや、何万行ものcssが出てきます。

これらすべての詳細度を覚え、毎回計算しながら対応する事は時間の無駄です。

詳細度については概要を頭の中で把握するだけで十分です。

cssは全てがグローバルですので、class名が被ると値を上書いてしまいます。

すべての要素に異なる名前をつけ、それが被らないように把握しておく事はサイトが大きくなればなるほど困難になってきますので絶対に上書き問題や、意図しない個所へのスタイルの反映が起こります。

ではどのようにして詳細度とスタイルの上書き問題とそのデバックを解決するのでしょうか。

この問題はcss設計という形で多くの解決策があります。

css設計については別の章で解説いたします。

コンテンツの方向について

Webは、相互にリンクされたドキュメントを表示するために構築されました。

初めは学者どうしが論文を共有する仕組みとして制作され、デザインよりもテキストベースでのコミュニケーションでした。

多くのCSSの仕組みと用語は、テキストベース・印刷の世界から受け継がれています。

これを知っておく事で今まで疑問だった「なぜ!」を理解する事が可能となります。

原点に立ち戻り、テキストベースで考えます。

テキストが書かれた紙

多くの言語は左から右へ進みます。

つまり、単語は左から右に並べて配置されます。

単語1つ1つを括ったブロックの鎖

そして、個々の単語は見出しや段落のようにブロックに結合されます。

その単語の鎖でできた文章がブロック

言い換えると、多くの言語のテキストドキュメントには「垂直」と「水平」の2つの方向があります。

  1. ページは垂直方向のブロックで構成される
  2. ブロックは水平方向の単語で構成される

CSSは、このシステムに基づいて方向性を構築します。

block方向(垂直)とinline方向(水平)がです。

display: block;やdisplay: inline;という宣言を見た事があるかと思いますがここからきています。

論理プロパティ

「組み込み宣言と継承」でブラウザに初めから設定されているスタイルについて学習しました。

chromeのpタグに記載されている組み込み宣言は以下になります。

p {
  display: block;
  margin-block-start: 1em;
  margin-block-end: 1em;
  margin-inline-start: 0px;
  margin-inline-end: 0px;
}

cssを少し経験した事があるかたは、違和感を覚えるのではないでしょうか?

margin-block-startやmargin-block-endなどです。

margin-leftなどではなく、margin-block-start?と思うかもしれません。

これらのプロパティは基本的な4つの方向である、

  • margin-left
  • margin-right
  • margin-bottom
  • margin-right

に値します。

margin-blockは縦方向を意味します。

「コンテンツの方向」で2つの方向があり、blockは縦軸だと述べました。

そしてstartとはその名の通り、初めの位置です。

ですので、margin-block-startは「縦方向の初め」という意味になり、margin-topと同じとなります。

このように考えると以下のようになりますね。

  • margin-block-start => 縦方向の初め => margin-top
  • margin-inline-end => 横方向の終わり => margin-right
  • margin-block-end => 縦方向の終わり => margin-bottom
  • margin-inline-start => 横方向の初め => margin-left

ですがなぜこれらを使用するのでしょうか。

それは全ての言語が左から右、上から下とは限らないからです。

例えばアラビア語は昔の日本のように、右から左に流れる言語です。

margin-leftを使用してしまうと、アラビア語ではmarginの位置が逆になり、意図しないレイアウトになってしまうかもしれません。

margin-blockやmargin-inlineを使用しようする事でこの問題を解決する事がで来ます。そしてこれらは論理プロパティと言います。

マージンだけではなく、padding、border、overflowの論理的なバリエーションもあります。

詳しくは以下ドキュメントが参考になります。

CSS Logical Properties and Values[MDN]

これは理解する事が難しいですし、言語対応など限定的なものになるので通常は論理プロパティについては意識する必要はありません。

頭の片隅にとどめて置く程度で良いです。

ではなぜピックアップしたかと言うと、コンテンツの方向についての理解を深めるためです。

The Box Model(ボックスモデル)

web上に表示しているコンテンツは全てボックスモデルで構成されています。

ボックスモデルは非常に重要な概念ですので人に説明できるレベルまで理解しておきましょう。

デベロップツールを開き要素>スタイル欄を一番下までスクロールすると出てきます。

ボックスモデルは内側からcontent < padding < border < marginとなっています。

ボックスモデルを理解するためによく用いられる例えは、コートを着た2人の人間です。

  • contentはその人の骨格です。コンテンツが多ければ多いほど骨太の大きな体になります。
  • paddingはその人の脂肪です。paddingが多ければ多いほど見た目が大きくなります。
  • borderはその人が来ているコートです。コートの色や厚みにより見た目が変わります。
  • marginはその人のパーソナルスペースです。パーソナルスペース内に他の人は入ってほしくないので、marginを持つ要素は他の要素と距離ができます。

padding,border,marginにはそれぞれtop,right,bottom,leftの4つの方向があります。

論理プロパティで行ったblock-startなどを思い出してください。

それぞれ4つの方向の値を個別に指定する事ができ、以下のようなルールの構文となっています。

  • ○○-top
  • ○○-right
  • ○○-bottom
  • ○○-left

そしてこれら4つのプロパティを短縮して記載する事が可能です。

  • padding: top right bottom left;
  • margin: 10pxx 15px 20px 25px;

省略して一行にした場合、駆らなずtopと起点とし、時計周りで値が適応されます。

毎回時計をイメージするとわかりやすいですね。

0時が起点となり、3時、6時、9時と進みます。

padding(パディング)

パディングについて考える時に「皮下脂肪」ととらえると理解しやすいです。

要素にパディングをセットして、背景色を赤にしてみます。

.content {
  padding: 16px;
  background-color: red;
}

すると上の画像のようにpadding部分まで赤色になります。

これはpaddingが皮下脂肪のように要素の内側についている事を表しています。

paddingのユニット

paddingで主に使用されるユニットは以下です。

  • px
  • em
  • rem
  • %

ここで注意すべきは%を使用して高さを指定した時の動きになります。

横幅を指定した時は直観どうり親要素の横幅の○○%という値になります。

例えば親要素の横幅が300pxなら子要素のpadding-left: 50%;は150pxです。

<style>
.parent {
  width: 300px;
}

.child {
  padding-left: 50%; // 要素の横幅が150pxになる。
}
</style>

<div class="parent">
  <div class="child">
  </div>
</div>

一方で高さとなるpadding-topに50%を当てると直観と反します。

高さなので親要素の高さの○○%となりそうですが、そうではなく、親要素の横幅の○○%となります。

これはアスペクト比を保つために便利に機能します。

省略系の書き方

padding, marginは値を省略して記載する事が可能です。

padding-1 {
  padding: 10px 15px 20px 25px;
}

padding-2 {
  padding: 10px 20px;
}

padding-3 {
 padding: 10px 15px 20px;
}

【padding-1{padding: 10px 15px 20px 25px;}】

4分割で記載した場合は、topを起点に時計周りに値が適応されます。

【padding-2{padding: 10px 20px;}】

2分割で記載した場合は初めの値が上下、後の値が左右の値となります。

【padding-3{padding: 10px 15px 20px;}】

3つ分割して記載した場合はtopを起点に時計周りで値が適応され、値が指定されていない個所(左側)はその対極にある値をコピーします。

ですので左は右をコピーし、15pxとなります。

border(ボーダ)

borderはpaddingの周りについた装飾可能な枠線です。

イメージとしてはcontent,paddingが人間本体ならborderはその人が着ている服です。

borderは色、太さ、線の見た目、角の丸みを調整する事ができます。

参考:border[MDN]

border-color

borderの色を変更可能です。

<style>
  .border-sample {
    border-color: green;
  }
</style>

<div class="border-sample">
  コンテンツ
</div>

border-colorと記載すると、全てのborderに色が当たってしまいますが、paddingと同じようにtop,right,bottom,leftを別々にセットする事も可能です。

  • border-top-color 
  • border-right-color 
  • border-bottom-color
  • border-left-color

border-style

borderの見た目を変更する事が可能です。

<style>
  .border-sample.item-1 {
    border-style: solid;
  }
  .border-sample.item-2 {
    border-style: dotted;
  }
  .border-sample.item-3 {
    border-style: dashed;
  } 
  .border-sample.item-4 {
    border-style: double;
  }  
  .border-sample.item-5 {
    border-style: groove;
  }
</style>
<div class="border-sample item-1">
  1 本の直線、実線
</div>
<div class="border-sample item-2">
  連続した丸い点
</div>
<div class="border-sample item-3">
  連続した点線や線分
</div>
<div class="border-sample item-4">
  2 本の直線
</div>
<div class="border-sample item-5">
  へこんだように見える実線
</div>

border-width

borderの太さを変更する事が可能です。

<style>
  .border-sample{
    border-width: 6px;
  }
</style>
<div class="border-sample">
  borderの太さを変更
</div>

border-widthも各4方向の太さを個別で指定する事が可能です。

  • border-top-width
  • border-right-width
  • border-bottom-width
  • border-left-width

border-widthとborder-colorを組み合わせると三角を作る事も可能です。

吹き出しなどよく使用するので覚えておきましょう。

三角の作り方はこちらの記事で説明しています。

矢印ラベルの作り方

もっと手軽に三角を作りたい場合三角形ジェネレーターを使用するのもおすすめです。

CSS三角形作成ツール

border-radius

border-radiusを使用する事でborderの角を丸める事が可能です。

<style>
  .border-sample{
     border-radius: 10px;
  }
</style>
<div class="border-sample">
  borderの角を丸める
</div>

border-widthも各4方向の太さを個別で指定する事が可能です。

  • border-top-left-radius
  • border-top-right-radius
  • border-bottom-right-radius
  • border-bottom-left-radius

border-radiusを50%とする事で円を作る事も可能です。

.border-sample{
  border-radius: 50%;
}

参考記事:今更聞けない!?cssのbordr-radiusで様々な角丸に挑戦

box-sizing(ボックスサイジング)

box-sizingとはボックスモデルのpaddingとborderをボックスの中に収めるかどうかをコントロールするものです。

ボックスモデルの初期値ではpaddingとborderはcontentの外側に加算される形でつきます。

その例を見てみましょう。

paddingとborderを持った要素を親の横幅と合わせるためにwidth: 100%;をセットすると直観とは反する動きをします。

<style>
section {
  width: 300px;
}

p {
  width: 100%;
  padding: 10px;
  border: solid 3px #000;
}
</style>

<section>
  <p>テキスト</p>
</section>

親であるsectionの幅300pxに合わせたくてwidth: 100%と記載したのに実際にデベロッパーツールで見てみると横幅が326pxとなっています。

これはwidthプロパティがcontentに対して幅100%を適応するためです。

ですので以下のような計算となります。

content: 300 + padding-left: 10 + padding-right: 10 + border-left: 3 + border-right: 3

= 326

heightに関しても同じです。

これがボックスモデルデフォルトの動きです。

これを300pxにしたい場合以下のようなcssを書く必要が出てきます。

width: calc(100% - 26px);

※calcについては別の章で解説します。

少しややこしいですよね。

ここでbox-sizingの出番です。

box-sizing: border-box;と宣言するとpaddingとborderの値をcontentの中に含めてくれます。

<style>
* {
  // 追加
  box-sizing: border-box;
}

section {
  width: 300px;
}

p {
  width: 100%;
  padding: 10px;
  border: solid 3px #000;
}
</style>

<section>
  <p>テキスト</p>
</section

「*」全称セレクターを使用し、全ての要素に適応させておくことで開発が楽になります。

参考:box-sizing[MDN]

margin(マージン)

marginは人のパーソナルスペースです。

2つの要素がありmarginを設定していた場合、2つの要素の間に空間が空きます。

marginはpaddingやborderとは異なり、離れあったり、引き合ったり、コンテンツの位置を自由にコントロールする事が可能で、奥の深いものです。

marginもpaddingやborderの書き方と似ており、4つの方向と省略した書き方があります。

.item {
  margin-top: 10px;
  margin-right: 15px;
  margin-bottom: 20px;
  margin-left: 25px;

  margin: 10px 15px 20px 25px;

  margin: 10px 20px;

  margin: 10px 15px 20px;
}

See the Pen Untitled by tora (@-tora-) on CodePen.

マイナスマージン

paddingやborderはプラスの値のみ使用する事ができます。

ですが、マージンはマイナスの値を使用する事が可能です。

マイナスマージンをセットするとどのような動きになるのか見ていきましょう。

item-2のボックスにtop: -10pxをセットしました。

See the Pen Untitled by tora (@-tora-) on CodePen.

すると、item-1に重なる形で上方向にボックスが引っ張られます。

マイナスマージンは兄弟要素を近づける事ができるのです。

では親子関係の要素の場合はどうでしょう。

See the Pen Untitled by tora (@-tora-) on CodePen.

このように親をはみ出して、要素を外に引っ張る事も可能です。

マイナスマージンをセットした際に注意する必要があるのは後続の要素です。

マイナスマージンは要素の引っ張るので後の要素は一緒についてきます。

ある一つの要素のみ位置をずらしたいという場合には向いていません。

その場合はtransformというまた別のプロパティを使用します。

See the Pen Untitled by tora (@-tora-) on CodePen.

margin auto

marginにはautoという値が存在します。

marginにautoをセットすると、コンテンツの空いているスペースを埋める働きをします。

左右にautoをセットした場合、左右の値が可能な限り伸び、同じ値となるので、コンテンツは中央配置になります。

フローレイアウト

html要素をcssでレイアウトする時、cssのレイアウトアルゴリズムによって位置が計算され、レンダリングされます。

これらは「レイアウトモード」と呼ばれ、いくつかの異なるモードがあります。

この章では最も基本的なフローレイアウトについて解説します。

フローレイアウトはデフォルトのレイアウトモードです。

ボックスモデルで説明した内容は全てフローレイアウトでレンダリングされています。

CSSが適用されていないプレーンなHTMLドキュメントは、フローレイアウトのみを使用し、ブラウザの組み込み宣言によってスタイリングされています。

フローレイアウトでは全ての要素がdisplay: inline;またはdisplay: block; display: inline-blockを使用します。

この値はcssから宣言しなくても適応されますが、これはフローレイアウトを使用する事で、タグによって自動てきに判断されるからです。

例えばaタグはinlie、divタグはblockとなります。

inlineの特徴:位置調整は行わない

テキストベースの2つの方向イメージを思い出してください。

inline要素は各単語であり、それが横並びになっているだけでした。

inlineはレイアウトを崩すような事はしません。

横並びになっている文章でいきなり要素の上に余白ができ、テキストが凸凹になったらどうでしょうか。

inlineではそのような事は起こってほしくないので、margin-rightとleftは設定できますが、topとbottomは設定できないようになっています。

もし余白を設定したいのであればblockもしくはinline-blockにする必用があります。

inlineの特徴:ラインハイト

block要素にはありませんが、inlineにはline-hightというものがあります。

line-heightとはinline要素の上下についている余白の事です。

なぜこの余白が付いているのか。

それは、inline要素の単語のつながりをイメージすれば理解しやすいです。

inline要素は単語をつなげて文章を作ります。

その文章がもし、親要素よりも横に長くなる場合、文字は折り返されて複数行の文章となります。

その時、この空白が無ければ以下のようになってしまいとても読みにくい文章になるので初めからinline要素には余白が設けられています。

このラインハイトですが、少し厄介な事が起こります。

それはimgタグを使用した時です。

imgタグは画像を挿入する事ができるタグですが、imgはinline要素になります。

ですので余白の機能を受け継ぎ、画像の下の方に余計な余白ができてしまいます。

そんな時の解決策として、imgをblock要素に変換してしまう方法があります。

webサイトを制作していると必ず出てきますので覚えておきましょう。

inlineの特徴:要素の折り返しができる

block要素は要素の折り返しができませんがinline要素は要素の折り返しが可能です。

ここでのポイントは「要素の折り返し」です。

「コンテンツの折り返し」ではありません。

ボックスモデルを思い出してください。

要素とはcontent, padding, border, marginを持ったすべてであり、コンテンツとはcontentの事(例えばテキストなど)を指しています。

ですので、ここで言っている事は改行ではなく、padding, border, marginを含んだ要素自体が折り返すという事を言っています。

違いを見るためにページに収まりきらない長いテキストでblock要素とinline要素の2パターンを用意します。

それぞれにborderをつけるとその違いが一目でわかります。

See the Pen Untitled by tora (@-tora-) on CodePen.

このように、inlineではborderなど要素自体を折り返すので、要素が途中で切れたような形となります。

この時、inlineにpadidng-left,rightをつけた場合、折り返した要素の初めと終わりにしかスペースが付きません。

これを以下のように、全ての場所につけたい場合、

box-decoration-break: clone;を使用する事で可能になります。

blockの特徴:スペースを占有する

block要素を配置するとその要素は余った横幅いっぱいに伸び、スペースを占有します。

例えばテキストの長さが200pxだとしても要素はページの960pxまで伸びるのです。

もし、block要素のまま横幅を余った余白いっぱいに伸ばしたくない。

上の例で言うと、「テキストコンテンツ」の幅にしたいといった場合、以下の方法で可能です。

text-content {
  width: max-content;
}

これは横幅を中のコンテンツ幅にするという指定です。

ですが、これには1つ注意点があります。

通常、中のテキストコンテンツが親要素からはみ出る場合にはテキストが改行され、きれいに収まります。

ですが、max-contentを使用すると、改行がされず、親を突き抜ける形となってしまいます。

そこで出てくるのがfit-contentです。

width: fit-contentと宣言すればテキストは改行され、コンテンツ幅の問題も解決されます。

inline-blockの特徴

inline-blockを使用すると内部的にはblockとして扱い、外部的にはinlineとして扱う事が可能です。

内部的にblockとは、要素にmargin-topなどのblockそしてのスタイルを当てる事が可能という意味を持ちます。

外部的にinlineとは、親要素にたいしてはinlineのようにふるまうので、要素は横いっぱいに広がらず、コンテンツのサイズ(width: fit-contentの状態)となりますので、要素はinlineの時と同じく、横並びのレイアウトとなります。

一見いいとこどりで便利に見えますが、注意点があります。

inline-blockの特徴:行を折り返さない

inline-blockは行を折り返しません。

これがどのようなデメリットがあるかと言うと、長文が入った時です。

See the Pen Untitled by tora (@-tora-) on CodePen.

デモ内の上にあるboxがaタグにinline-blockを適応させた時の動きで、デモ内の下にあるboxがデフォルトのaタグ(inline)のままの動きです。

このように、inline-blockは途中でテキストを折り返しませんので、この長文が入るように、「inline-blockのデメリット」の部分で折り返して、長文が入るスペースを確保しようとします。

幅アルゴリズム

block要素は空いているスペースを埋め尽くすように横幅が伸びると述べました。

これはwidth: 100%;というように解釈できますが実際はそうではありません。

See the Pen Untitled by tora (@-tora-) on CodePen.

テキストコンテンツ1にはwidth: 100%を適応し、テキストコンテンツ2には記載していません。

結果はこのように、width: 100%をつけたほうがフレームの外に飛び出しています。

これは「%」が要素の幅を親要素の横幅を同じにするからです。

親要素が500pxなら子要素も500pxとなります。

そこにmarginが加わる事で500pxのままmargin-leftに16pxが付き、コンテンツが親要素を突き抜ける形となるのです。

では適切な値は何でしょうか、一番はblock要素ですので親いっぱいに伸ばしたいならwidthを記載しない事ですが、あえてwidthを使用するなら、ここでの適切な値は100%ではなく、autoとなります。

autoを使用すれば可能な限り幅を広げますのでblock要素の動きと同じとなります。

幅アルゴリズムの値

widthに使用できる値は数値とキーワードがあります。

ここではキーワードにフォーカスを当てます。

よく使用されるキーワードは以下3つがあり、それぞれの特徴を説明します。

  • min-content
  • max-content
  • fit-content
  • auto

min-content

min-contentをセットすると自信のcontentのサイズに基づいてできるだけ小さな横幅を取ろうとします。

このような親のスペースに基づいてサイズを計算する事を外在的といい、自身のcontentに基づいてサイズを計算する事を内在的と言います。

autoは親のスペースに基づくので外在的ですが、○○-contentは自身のcontentに基づくので内在的です。

min-contentの動きを見てみますが、実はmin-contentは日本語の場合、あまり役に立ちません。

理由は言語の構造にあります。

英語の場合、単語と単語の間にスペースが存在します。

i am a front-end engineer

一方、日本語はこのようなスペースがありません。

そして、英語は単語の途中で改行してしまうと意味が分かりずらくなる言語です。

i am a fro
nt-end engi
neer

ですので、ブラウザは改行が入る際に、単語の途中ではなく、スペースから改行します。

i am a
front-end
engineer

これにより、英語は1つの単語が存在できる幅が最小の単位となります。

ですのでこの例の場合、 front-end が縮小できる最小の横幅です。

ですが、日本語はこのようなスペースや、改行問題がない言語です。

日本語はどこで改行しても意味が通じるのでブラウザは1文字から改行します。





1









ですので、1文字の幅が縮小できる最小の幅です。

これではmin-contentを使う意味があまりありません。

max-content

max-contentはmin-contentとは逆となります。

contentの最大幅が要素の幅となります。

contentの幅いっぱいに伸びますので、contentの内容が親の幅を超える場合でも、改行されずに突き抜けてしまいます。

親要素内に収まる場合はblock要素でもinlin-blockのように要素が横並びとなり扱われるので便利です。

fit-content

fit-contentはmax-contentと同じcontentの最大幅が要素の幅となります。

違いはfit-contentは伸びる事が可能場合、要素が伸びるという点です。

ですのでmax-contentとは違い、親要素の幅を超える場合はcontentが改行されて親要素内に収まります。

min-widthとmax-width

要素の最小幅と最大幅を指定する事ができます。

min-widthに指定した値より要素が縮む事はなく、max-contentに指定した値より要素が広がる事はありません。

min-contentとmax-contentをうまく使用するとfit-contentのような動きが可能です。

See the Pen Untitled by tora (@-tora-) on CodePen.

  • divはblockの要素であるため、ページの幅いっぱいまで伸びようとします。
  • 文字数が多い場合、max-widthにmax-contentを指定しているため、max-contentの改行されない問題は影響せず、親要素を超えて要素が広がる事はありません。通常のblock要素の動きであるwidth: autoによって親いっぱいまで広がり、それよりもcontentが多ければ改行されます 。
  • 文字数が少ない場合、max-contenの働きにより、inlineのようにcontentの値が要素の値となります。
  • 画面サイズを縮めた場合、min-contentの働きにより、最小サイズは単語として一番「content」のサイズまで縮小します。

高さアルゴリズム

高さもwidthと同じようにpx、%、remで指定する事が可能です。

動きもwidthと同じで、%の場合は親要素の高さの○○%となります。

ですが、デザイン上必要な場合を除き、要素の高さを指定する事は避けましょう。

理由は要素をフレキシブルにするためです。

高さは何も指定しなければfit-contentのような動きをします。

2行なら2行分の高さを持ちますし、100行なら100行分の高さになります。

多くの場合、content内の内容は変化する事が多いです。

高さを指定してしまうと、contentの内容が変化した時に柔軟に対応できず、要素からはみ出てしまうかもれません。

マージンの相殺

マージンのメンタルモデルは人のパーソナルスペースです。

プラスのmarginを持つ要素は距離を保ちます。

<style>
.item-2 {
  margin-top: 40px;
}
</style>
<div class="item-1"></div>
<div class="item-2"></div>

上の例では2つの要素があり、下の要素にmargin-topをつけました。

では、上の要素にもmargin-bottomをつけ、2つのmarginがぶつかり合うようにしたらどうなるでしょうか?

直観的には足し算となり、40px + ○○px = というように考えるでしょう。

ですが、実際は、大きい方のmarginに吸収されます。

<style>
.item-1 {
  margin-bottom: 60px;
}
.item-2 {
  margin-top: 40px;
}
</style>
<div class="item-1"></div>
<div class="item-2"></div>

これがmarginがパーソナルスペースという理由です。

パーソナルスペースが40cmの人と60cmの人がいた場合、合わせて100cmの空間を空ける必要があるでしょうか?

必用ないですね。

60cmの人のパーソナルスペース分の空間があれば十分です。

これは垂直方向(block方向)でのみ起こります。

水平方向(inline方向)では起こらず、直観通り足し合わせた値となります。

書き込みモードを変更してみる

現在は垂直方向のmarginが吸収されていますが、書き込みモードを変更して、水平方向がblockの方向になるように切り換えます。

すると今度は見た目上、水平方向のmarginが吸収され、margin-blockの余白が吸収されています。

つまり、marginの吸収は常にblock方向でおこるという事であり、垂直方向と言うと語弊が生まれる可能性があるので、block方向と言うべきです。

marginの吸収はフローレイアウトの、隣接のみで起こる

上のようなmarginの吸収はフローレイアウトのみで起こります。

他にもポジショニングレイアウト、フレックスレイアウト、グリッドレイアウトなど複数のレイアウトモードがありますが、デフォルトのレイアウトモードであるフローレイアウトのみで起こります。

そしてももう一つ、marginの吸収は隣接している要素間でのみ起こります。

以下のように、別の要素が間に入るとmarginの吸収は起こりません。

<div class="item-1"></div>
<p></p> // marginの吸収をブロックする
<div class="item-2"></div>

入れ子の場合は吸収をブロックしません

要素を入れ子にした場合はmarginの吸収をブロックしません。

marginは親の要素を超えて影響を及ぼします。

こちらのコードをためしてみてください。

<style>
.child {
 margin-bottom: 30px;
}
.box{
 margin-top: 30px;
}
</style>

<div class="parent">
 <p class="child"></p>
</div>
<div class="box"></div>

こちらを実行すると、親要素を超えてmarginが影響します。

marginは一見他の要素とのスペースを空ける働きをすると考えますが、少しニュアンスが異なります。

他の要素とスペースを空けるのではなく、兄弟要素にしか影響しません。

親要素のスペースを空ける役割はpaddingが行います。

そして、paddingはmarginの吸収をブロックします。

今回の場合、paddingを親要素に使用した場合、<p>のmarginがブロックされ、marginの吸収は起こらなくなります。

<style>
.parent {
  padding-bottom: 10px;
}
.child {
 margin-bottom: 30px;
}
.box{
 margin-top: 30px;
}
</style>

<div class="parent">
 <p class="child"></p>
</div>
<div class="box"></div>

高さを指定する事で空白ができた場合、marginは吸収されません

親要素に高さを指定し、子要素がその高さに到達しなかった場合、子要素の下の方に空白が生まれます。

その空白により、marginがブロックされ、吸収は起こらなくなります。

<style>
.parent {
  height: 500px;
}
.child {
  margin-bottom: 30px;
  height: 200px;
}
.box{
  margin-top: 30px;
}
</style>

<div class="parent">
 <p class="child"></p>
</div>
<div class="box"></div>

marginは同じ方向でも吸収が起こります

今まではmarginが向き合っていた場合でしたが、同じ要領でmarginが同じ方向にある場合も吸収が起こります。

<style>
.parent {
  margin-top: 60px;
}
.child {
  margin-top: 30px;
}
</style>

<div class="parent">
 <p class="child"></p>
</div>

マイナスmarginでも吸収は起こります

marginの吸収はマイナスの値を設定した場合でも同じように起こります。

<style>
.box-1 {
  margin-bottom: -60px;
}
.box-2 {
  margin-top: -30px;
}
</style>

<div class="box-1"></div>
<div class="box-2"></div>

この場合、-60pxと-30pxでは-60pxの方が大きいのでbox-2がbox-1に対して30px引っ張られる事になります。

プラスとマイナスの場合は単純に相殺する

プラスmarginとマイナスmarginが合わさった場合は、相殺されます。

<style>
.box-1 {
  margin-bottom: -50px;
}
.box-2 {
  margin-top: 50px;
}
</style>

<div class="box-1"></div>
<div class="box-2"></div>

これは50px – 50px = 0pxと相殺されます。

ポジショニングアルゴリズム

positionプロパティを使用する事で、デフォルトのフローレイアウトアルゴリズムをポジショニングアルゴリズムに変更する事ができます。

ポジショニングアルゴリズムに変更する事で要素の配置をコントロールする事ができます。

positionプロパティには以下の値が存在し、それぞれ特長的な動きをします。

  • static デフォルト
  • relative
  • absolute
  • sticky
  • fixed

デフォルトのstatic以外の値をセットすると、top,right,bottom,leftプロパティをセットする事ができるようになり、要素の位置変えが可能となります。

フローレイアウト要素を好きに位置替えできるので

relative:相対ポジショニング

positionにrelativeを設定すると以下の事が起こります。

  • 包括ブロックを生成する
  • top,rigth,bottom,leftを使用して要素の位置をコントロールできる

包括ブロックについては後に解説します。

こちらでは要素の位置コントロールについて触れていきます。

以下の例を見てください。

See the Pen Untitled by tora (@-tora-) on CodePen.

topとleftを指定する事で元の位置から上方向、右方向に余白を空ける動きをします。

marignのような動きですが、postionはこの要素のみに作用します。

marginのイメージとしては、要素をある方向に引っ張るというようなイメージでした。

ですので特長としては、要素が引っ張られるので、その下にある要素も一緒に引っ張られます。

ですが、positionの場合は他の要素を引っ張る事はありません。

その要素のみの位置を変更します。イメージとしては、要素を浮かせて場所を変更するイメージです。

See the Pen Untitled by tora (@-tora-) on CodePen.

marginは3つの並ぶ要素を全て押し下げているのに対して、positonはその要素だけが、下方向に移動し、他の要素は動いていない事がわかります。

もう一つ例を挙げます。

次は横幅に関してです。

See the Pen Untitled by tora (@-tora-) on CodePen.

子供のコンテンツにはmargin contentにもposition contentにも同じくwidth: autoを設定しています。

marginの場合、左に空白を空けるので、その空白分要素が縮み、親要素の中におさまりますが、positonの場合は空白を空けるのではなく、要素を移動させるので横幅は親の幅を保ったままになります。

最後にpositonはinline要素へ適応させる事が可能です。

marginはinline要素へ影響を及ぼしませんが、positionを使えばinline要素でも上や下方向に要素を動かす事が可能となります。

absolute:絶対ポジショニング

positionにabsoluteを設定すると以下の事が起こります。

  • 要素の並び順を無視して好きな位置に配置する事ができる

デフォルトのフロー要素では要素はhtmlでの並び順に並んでいました。

フロー(順序)の中に入っている(イン)ので、これをインフローと呼びます。

absoluteはこの並びから除外され、要素を自由に配置可能となります。

See the Pen Untitled by tora (@-tora-) on CodePen.

デフォルトのフローレイアウトでは要素の並び順を守るため、absolute要素が先にきてnext content要素がその次に来るはずですが、 absolute要素が後に来ています。

このような位置の移動はmarginやrelativeでも可能ですが、 これらは要素の順番を無視はしません。

一方、absoluteは順番を無視します。

例えばrelativeでtop:10pxとセットした時とabsoluteでtop: 10pxを指定すると以下のような違いが生まれます。

See the Pen Untitled by tora (@-tora-) on CodePen.

赤色のブロックがrelative要素で、緑色のブロックがabsolute要素です。

relative要素は順番を無視しませんので、元あった位置から10px動く形となっています。

相対的(現在の位置)から要素が動いています。これが相対ポジショニングと言われる理由です。

緑色のabsolute要素は順番を無視します。

イメージとしては、その位置から要素を引っこ抜いてページ上の上から10px、左から10pxの位置に置いたようなイメージです。

ですのでhtmlの並び順は関係なくなり、二番のうすい緑の要素が一番上に来ています。

子要素がabsoluteの場合、親要素は高さを失います

absoluteのイメージは要素を引っこ抜くと言いました。

それはこちらのデモをみるとわかります。

parent要素の中にchild要素がありますが、absoluteが設定されているのでparentから要素が引っこ抜かれ、parentの高さがなくなっています。

See the Pen Untitled by tora (@-tora-) on CodePen.

これはparentに高さを設定していないため、子要素の高さに依存しているところに absoluteで要素が引っこ抜かれてしまったため、依存する子要素がなくなり、 parentの高さが0になったというわけです。

センター配置

配置プロパティ(top.right,bottom,left)とmarginの面白い組み合わせを見ていきましょう。

See the Pen Untitled by tora (@-tora-) on CodePen.

上下左右すべての方向から値を指定することで、要素をセンターに配置する事が可能となります。

position: absolute;を適応する事で要素の横幅が機能しなくなり、配置プロパティにより、上下左右に要素がピン止めされる事で要素が伸びようなイメージです。

それの証拠に以下のデモを見てください。

right, bottom,のピン止めを外す事で要素が伸びる必要がなくなりました。

div要素はblock要素なので、空いたスペースをblock方向(水平方向)いっぱいに埋め尽くすはずですが、要素の横幅は0pxとなり、見えなくなってしまいます。

これは position: absolute; によって要素の横幅が機能しなくなったと言えます。

ここで要素に横幅を与えてみます。

横幅を与えると50px * 50pxの要素が表れ、top: 50px; left: 50px;により、ピン止めされました。

次にrightとbottomを追加してみます。右方向と下方向からピン止めされるので、初めのデモのように、要素が伸びそうですが、今回は幅と高さを指定しいるのでこの場合は要素のサイズた保たれたままになります。

では、要素の配置はどのようになるのでしょう。

答えはこうです。topとleftが優先され、結果は変わりません。

最後にmarginを組み合わせてみましょう。

この結果は予想外の結果になります。

See the Pen Untitled by tora (@-tora-) on CodePen.

要素はセンターに配置されました。

margin: auto;は利用可能なスペースをできるだけパーソナルスペースとして埋め尽くそうとします。

その結果、要素が中央に配置さました。

この事から以下のようにイメージする事でabsoluteの動きを説明できるのではないでしょか。

position: absolute;をセットするとabsoluteフィールドが展開され、要素は元のhtmlフローからabsoluteフィールドの世界に引っこ抜かれます。

ですのでhtmlフローからは除外され、順番が無視されるわけです。

absoluteフィールドはtop,right,bottom,leftで指定した値の位置にピン止めされます。

そして、要素に幅と高さが指定されていなければblock要素のようにabsoluteフィールドいっぱいに伸びます。

もし要素に幅と高さが指定されていれば、通常フローと同じく、 absoluteフィールド内の左上に配置されます。

margin指定されていれば、 absoluteフィールド内でスペースを取ろうとします。

ですので、margin: autoを指定すると中央配置になるわけです。

absoluteフィールドは個別に展開されますので、 absolute要素を2つ制作しても、その2つの要素が1つの absoluteフィールド内に入り、干渉する事はありません。

別々の absoluteを生成し、要素は重なり合います。

包括ブロック

position: relative;の説明で包括ブロックを生成するとありました。

包括ブロックとは要素と包み込み、拘束するブロックです。

position: absolute;の例で、 absoluteフィールドが生成されるとありましたが、 absoluteフィールドがとこを起点にピン止め位置を決めていたかと言うとページ全体です。

top: 50pxと宣言すれあば、ページから下に50px進んだ位置にピンが打たれます。

これはページ全体が包括ブロックだからです。

包括ブロックはページ全体ではなく、 position: relative;を宣言する事で要素にも適応する事ができます。

以下の例を見てください。

See the Pen Untitled by tora (@-tora-) on CodePen.

child要素にはabsoluteを適応し、上下方向30pxの位置にピン止めをしています。

absoluteの説明の章ではページ全体にたいしてabsoluteフィールドが展開され、要素がページ全体に広がっていたものが、parent要素の中に納まっています。

これはparentにrelativeを宣言する事で包括ブロックになり、absolute要素を拘束したためです。拘束されると中になるコンテンツは親を無視して外に出る事はできなくなります。

言い換えると、拘束する親要素の中だけでabsoluteフィールドが生成されます。

See the Pen Untitled by tora (@-tora-) on CodePen.

absoluteは拘束ブロックにしか拘束されません。

ですので上のデモのように、拘束要素ではない通常の要素は全て無視され、relative-itemにのみ拘束されます。

スタッキングコンテキスト

スタッキングコンテキストとは重なりをコントロールする処理です。

要素が重なっている場合、ブラウザはどの要素上にし、どの要素を下にするという判断をしてるのでしょうか。

まず通常のフローレイアウトでどのようになるのかを確認してみましょう。

See the Pen Untitled by tora (@-tora-) on CodePen.

通常のフローレイアウトではhtml要素の並び順で重なりを決定します。

後にある要素が上に重ねられます。

ただ、上のデモのようにフローレイアウトの場合、後の要素よりも文字が上に来てしまいます。

これを後の要素が完全に一番上のレイヤーに来るようにするには相対ポジショニング(position: relative;)を使用します。

See the Pen Untitled by tora (@-tora-) on CodePen.

基本的にpositionプロパティを使用した要素は常にpositionプロパティを使用していない要素の上に重ねられます。

ですので、first要素にposition: relative;を使用するとsecond要素よりも上に来ます。

See the Pen Untitled by tora (@-tora-) on CodePen.

html上ではfirst -> secondの並び順でので、重なりはfirstよりもsecondが上にくるはずです。

ですが、firstにpositionプロパティを使用したのでfirstがsecondよりも上に来ています。

ではfirstとsecond両方にpositionをセットするとどうなるのでしょう。

結果は、htmlの並び順で重なります。ですのでfirstの上にsecondがきます。

この時、通常のフローレイアウトと異なるのは、first文字がsecondの上に来ない事です。

  • 重なり順はhtml要素の並び順で後に記載されているものが重なりで上になる
  • positionを使用する事でpositionを使用していない要素の上に重ねる事ができます
  • position要素が被るとhtml要素の並びで後に記載されているものが重なりで上になる

z-indexをマスターする

position使用すると重なりを上にする事ができますが、複数のpositionがある中で重なり順をコントロールしたい場合はz-indexを使用する事で重なり順を変更する事ができます。

レイアウトロジックに戻りますが、レイアウトにはinline方向(水平方向)= X軸とblock方向(垂直方向)= Y軸がありましたが、これにz-index方向(重なり方向) = Z軸が追加されたイメージです。

See the Pen Untitled by tora (@-tora-) on CodePen.

z-indexはデフォルトでは0ですので1以上の値を設定する事で重なりが上になります。

ここまでは2の要素のみでの重なり順のコントロールでしたのでそこまで難しくはありません。

ですが、親子関係を持つ要素どうしで重なり順をコントロールする事はとても複雑になります。

下の例はテーブルコンテンツでよく起こる課題です。

テーブル内にテキスト要素が入らない場合、テキストを省略し、ホバー時にツールチップとして全文を表示したいという事はよくあります。

ですが、z-indexのコントロールがうまくいかず、ツールチップがテーブルヘッドの下に潜り込んでしまっています。

この問題はなぜおこるのでしょうか。また、どのようにすれば解決できるのでしょうか?

See the Pen Untitled by tora (@-tora-) on CodePen.

この課題の原因を探るため、スタッキングコンテキストについて掘り下げます。

スタッキングコンテキストの生成

スタッキングコンテキストが生成されると重なり順を判断するための土俵に立ってしまいます。

逆を言えば、スタッキングコンテキストを生成していない要素は重なり順の土俵に立ちません。

重なり順の土俵は、言わばz-indexの戦いに参加したという事です。

土俵に上がらなければ戦いに参加する事はありません。

z-indexの戦いはz-indexの値が大きい方が勝ちます。

z-indexは戦闘力なのですが、親子関係の要素は戦闘力の計算が厄介なのです。

同じフィールドに存在する要素は単純にz-indexを比べて大きい方が勝ちます。

ですが、その子要素は親のz-indexを引き継ぎます。

See the Pen Untitled by tora (@-tora-) on CodePen.

ですので、上のデモの場合、.rowは1です。その子である.tooltipは100ですが、親を引継ぐので、1.100 = 1.1となります。この戦闘力で.table-headの2と戦ってみてください。

当然負けます。

ではこれを勝たせるためにはどうすればよいでしょうか?

方法は2つあります。

  1. 親となる.rowのindexをtable-headよりも大きいものにする
  2. そもそもスタキングコンテキストを生成せずに引継ぎを発生させない

1 – 親となる.roeのindexをtable-headよりも大きくする

.row {
  position: relative;
  z-index: 3;
}

これで、.tootipの戦闘力は3.1になります。

tabel-headは2なので勝つことができますね。

2 – そもそもスタッキングコンテキストを生成せずに引継ぎを発生させない

1の方法でも解決はできますが、1の方法はおススメしません。

理由はさらに複雑になった時にindexの計算が大変になる事と、後から要素を追加する際に厄介になるからです。

なので2の方法で行きましょう。

tooltipの戦闘力が下がった原因は親の戦闘力を引き継いだためです。

せっかく100の戦闘力を持っていても親の1を引継ぎ1.1になってしまいました。

これを避け、本来の100の戦闘力を発揮できるように、引継ぎを起こらないようにします。

引継ぎが起こる原因はスタッキングコンテキストを生成したためですので、親である.rowのz-indexを取ってスタッキングコンテキストを解除します。

See the Pen Untitled by tora (@-tora-) on CodePen.

スタッキングコンテキストを生成するプロパティ

z-indexを消すとスタッキングコンテキストは消えましたが、スタッキングコンテキストを生成するプロパティはz-indexだけではありません。

それを知らないとz-indexを取っているのに重なり順を解決できないハマりポイントとなります。

スタキングコンテキストを生成するプロパティは以下があります。

  • position の値が absolute または relative であり、かつ z-index の値が auto 以外の要素
  • position の値が fixed または sticky の要素 (sticky はすべてのモバイルブラウザーにありますが、古いデスクトップブラウザーにはありません)。
  • フレックスコンテナーの子であり、 z-index の値が auto 以外の要素。
  • グリッド (grid) コンテナーの子であり、 z-index の値が auto 以外の要素。
  • opacity の値が 1 未満である要素 (不透明度の仕様をご覧ください)。
  • mix-blend-mode の値が normal 以外の要素。
  • 以下のプロパティの何れかが none 以外の値を持つ要素。
  • transform
  • filter
  • perspective
  • clip-path
  • mask / mask-image / mask-border
  • isolation の値が isolate である要素。
  • -webkit-overflow-scrolling の値が touch である要素。
  • will-change の値が、初期値以外で重ね合わせコンテキストを作成する任意のプロパティを指定している要素 (この記事を参照)。
  • contain の値が layout または paint であるか、これらのどちらかを含む複合値 (すなわち contain: strict, contain: content) を持つ要素。

参考:重ね合わせコンテキスト[MDN]

transform、opacity、grid、fixed、stickyはよく使用するプロパティなので覚えておきましょう。

固定ポジショニング

固定ポジショニングで要素を固定して配置する事が可能です。

要素を固定すると、ページをスクロールしてもその要素は固定されたままその場所にとどまります。

固定ポジショニングはposition: fixed;を宣言する事で適応されます。

See the Pen Untitled by tora (@-tora-) on CodePen.

デモをスクロールしてみてください。

TOPへボタンがその場にとどまります。

fixedの拘束

fixedはabsoluteと違って何も位置プロパティをセットしなければ親要素に拘束されます。

See the Pen Untitled by tora (@-tora-) on CodePen.

top,rightなど、位置を示すプロパティをセットしていないので親要素からtop: 0; left: 0の位置に配置されました。

親要素には包括プロパティのposition: relative;は宣言していませんがfixedは直属の親に包括されます。

もしtop,leftなど、位置を示すプロパティが宣言されれば、親を無視し配置されます。

そして親にposition: relative;を宣言しても拘束されません。

transformとの組み合わせ

transformが宣言されている要素の中でfixedを宣言するのは相性がよくありません。

transformがfixedを無効にしてしまいます。

See the Pen Untitled by tora (@-tora-) on CodePen.

.parentにtransformを宣言しました。

ページをスクロールしてみてください。 fixedだったはずのTOPボタンが一緒にスクロールされてしまいます。

どうしても親にtransformが必要な場合の解決策はfixed要素をtransform要素の外に出すしかありません。

オバーフロー

記事ページやwebアプリなどを制作する場合、コンテンツが動的に変化する事はよくある事です。

初めに制作した時に想定していた文字数よりも長い文字数が入力される事も多々あります。

その場合、元のデザインが崩れてしまします。

See the Pen Untitled by tora (@-tora-) on CodePen.

長文が入ると予想される場所は高さを指定せずに柔軟に伸び縮みするように制作する事がベストですが、デザインの観点から高さを固定したい場合があります。

その時に使用するのがoverflowプロパティです。

overflowには以下の値がセットできます。

  • visible => デフォルト:コンテンツは要素をはみ出して表示されます
  • hidden => はみ出たコンテンツはカットされ、非表示となります
  • scroll => コンテンツは要素からはみ出ません。スクロールを可能にし、要素を閲覧可能にします
  • auto => scrollと同じですが、コンテンツが要素をはみ出ないときはスクロールが無効になります

See the Pen Untitled by tora (@-tora-) on CodePen.

overflow内のpositonレイアウト

拘束されていない(position: relative;が宣言されていない)overflow内で子要素にpositon: absolute;を宣言すると、overflow: hidden;で非表示設定にしても子要素は表示されてしまいます。

See the Pen Untitled by tora (@-tora-) on CodePen.

これを非表示にしたい場合、overflow要素に position: relative; を宣言し、要素を拘束する事で可能です。

See the Pen Untitled by tora (@-tora-) on CodePen.

今はoverflow: hidden;ですが、overflow: auto;にすると要素内をスクロールする事で absolute 要素を全て表示する事ができます。

See the Pen Untitled by tora (@-tora-) on CodePen.

最後にfixedポジショニングです。

overflow内でfixedを宣言すると、absoluteとはまた違った動きをします。

See the Pen Untitled by tora (@-tora-) on CodePen.

relativeで拘束した要素内にあるfixedですが、overflow要素に拘束されず、 fixed要素は外にはみ出しています。

これは fixed要素が拘束誰にも拘束されないからです。

fixed要素にtop,leftなどの配置プロパティを宣言すると拘束できるのはページ全体のみになります。

スティッキーポジショニング

position: sticky;を使用するとページをスクロールした際に親要素が表示されている間だけ sticky要素をfixedのように固定表示する事が可能です。

stickyはよく、目次エリアを固定する時に使用されます。

See the Pen Untitled by tora (@-tora-) on CodePen.

offset

fiexdなどと同じように、固定位置を指定する事が可能です。

See the Pen Untitled by tora (@-tora-) on CodePen.

inline方向(水平方向)のsticky

leftの値を設定する事で水平方向のstickyを設定可能です。

これはよく、テーブルでカラム固定をしたい時に使用されます。

See the Pen Untitled by tora (@-tora-) on CodePen.

コンテンツの非表示

時に要素を非表示にしたい事があります。

例えば、折りたたまれたメニューなどです。

そんな時、要素を非表示にする方法はいくつかありますが、それぞれの特徴をしり、適切なcssを選択できるようになりましょう。

間違った選択をしてしまうとGoogleの検索順位を落してしまう事もあるので注意が必要です。

display: none

display: noneを宣言する事で要素を非表示にする事が可能です。

特長はDOMから完全に消去される事です。

存在自体をなかった事にされます。

要素自体がなくなるので、読み上げソフトや、タブフォーカスなども反応しなくなります。

要素自体なくなりますが、htmlに記載されたコードがなくなるわけではありませんのでGoogleのボットからは認識されてしまいます。

display: noneを使用して要素を非表示にすると、隠しコンテンツとしてGoogleからペナルティーを食らってしまう恐れがありますが、ユーザーの操作で要素が表示されるようなロジックが入っていたり、表示する画面サイズによって表示されるようになっているものはペナルティー対象ではないので、どんな状況でも完全に表示されない要素でない限り問題はありません。

See the Pen Untitled by tora (@-tora-) on CodePen.

「非表示コンテンツ」という要素があるはずですが、表示されていません。

visibility: hidden

visibility: hiddenを宣言する事で要素を非表示にする事が可能ですが、display: noneとは違い、要素は消去されません。

要素は存在するが、見えないという状態です。

要素は存在しますが、フォーカスなどの操作は行えません。

See the Pen Untitled by tora (@-tora-) on CodePen.

button要素はタブ移動でフォーカスが当たりますが、visibility: hidden;を宣言したのでフォーカスは当たりません。

ですが、要素自体は存在しているので、コンテンツに間が空いています。

opacity: 0

opacityを0にすると要素を非表示にする事が可能です。

opacityは透明度をコントロールするプロパティで、0.5など、半透明にする事も可能です。

要素を透明にしているだけなのでもちろん要素は存在します。

visibility: hidden; との違いは、タブフォーカスが可能な事です。

See the Pen Untitled by tora (@-tora-) on CodePen.

デモ内をクリックしてタブキーを押してみてください。

ボタンにフォーカスが当たり、表示されるようになります。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

プログラムちょと書ける。
いまはバリ島でスクール作っている。
プログラムちょっとできる。

目次