18
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

top,left,translate,padding-topなどに指定するパーセント値が何に対する割合なのかを理解する

Last updated at Posted at 2019-09-04

topやleftなど「距離や長さ」に関するCSSプロパティで値にパーセント値を指定したとき、それが「何に対する割合」なのか私は理解があやふやだったので、この記事では理解するためのポイントを整理したいと思います。例として次の4つのケースを取り上げ、プロパティ値に100%を指定したときに要素の配置や寸法が何を基準にどのように変化するかを図で確認してみましょう。

  • position: absoluteのときのtop, left
  • position: relativeのときのtop, left
  • transform: translate関数の引数X | Y
  • padding-top (ブロック要素の高さを確保するのに用いる)

記事中のサンプルのソースコードはこちら。
DEMO: https://codepen.io/kaz_hashimoto/pen/LYPLdPy

例1. position: absoluteのときのtop, left: 100%

最初の例は、position: absoluteを設定した子要素をtop: 100%; left: 100%で配置した場合です(下図)。親要素div.box-1の中に2つの子要素div.child-1, div.child-2を入れ、どちらの子要素もwidth, heightを50%に設定しました。そして、.child-1のみposition: absoluteを設定し、.child-2は通常のフローで配置しtranslateを使って再配置しています。再配置によって子要素がどこからどこまで移動したのかわかるようにアニメーションにしてあります。.box-1の左上角あたりが元の位置(top:0, left:0, translate(0,0))ということになります。
図で.box-1のコンテンツ領域を破線で示してあります(.content-box)。
01_1.gif

html
<div class="box-1">
  <div class="child-1 child-box"><p>width, height 50%<br>top, left 100%</p></div>
  <div class="child-2 child-box"><p>width, height 50%<br>translate 100%</p></div>
</div>
CSS (要点のみ)
css
.box-1 {
  width: 300px;
  height: 100px;
  padding: 20px;
  border: 16px solid rgba(0,0,0,0.3);
  background-color: #B3E5FC;
  position: relative;
}

.child-box {
  box-sizing: border-box;
  width: 50%;
  height: 50%;
  border: 1px solid #000;
}

.child-1 {
  background-color: #E91E63;
  color: #fff;
  position: absolute;
  top: 100%;
  left: 100%;
}

.child-2 {
  background-color: #3F51B5;
  color: #fff;
  transform: translate(100%, 100%);
}
ここで注目すべきは、.child-1のサイズと元の位置です。2つの子要素はどちらもwidth, heightを50%に設定しましたが.child-1の方が.child-2より大きいですね。つまり、`position: absolute`を設定した.child-1の方は、
  • width, heightがそれぞれ.box-1のパディング領域のwidth, heightの50%になっている。
  • 元々の位置(top: 0, left: 0)は.box-1のパディング領域の左上角になっている。
  • top,leftを100%にした結果、元の位置から.box-1のパディング領域の幅と高さの分だけ離れた位置に配置されている。

一方、通常フローで配置した.child-2の方は、

  • width, heightがそれぞれ.box-1のコンテンツ領域のwidth, heightの50%になっている。
  • 元々の位置(translate(0,0))は.box-1のコンテンツ領域の左上角になっている。

ことがわかります。(※translateについては例3に書きます)

position: absoluteの場合の計算根拠をCSSの仕様書で確認してみましょう。たとえばwidthに関して、10.2 Content width: the 'width' propertyの注記によると確かに、

Note: For absolutely positioned elements whose containing block is based on a block container element, the percentage is calculated with respect to the width of the padding box of that element.

ここで包含ブロック(containing block)の定義を確認しておくと、10.1 Definition of "containing block"の説明では

If the element has 'position: absolute', the containing block is established by the nearest ancestor with a 'position' of 'absolute', 'relative' or 'fixed', in the following way:
(中略)
2. Otherwise, the containing block is formed by the padding edge of the ancestor.

例1a. 親と子要素の間にinner divがある場合

例1で、.box-1のposition: relativeはそのままに、.box-1の内側にラッパーとなるdiv.innerを追加して、.child-1と.child-2を.innerの子要素(.box-1の孫)にした場合はどうなるでしょうか?(下図)
01a_1.gif

html
<div class="box-1">
  <div class="inner">
    <div class="child-1 child-box"><p>width, height 50%<br>top, left 100%</p></div>
    <div class="child-2 child-box"><p>width, height 50%<br>translate 100%</p></div>
  </div>
</div>
CSS (要点のみ)
css
.box-1 { /* 例1と同じ */ }
.child-box { /* 例1と同じ */ }
.child-1 { /* 例1と同じ */ }
.child-2 { /* 例1と同じ */ }

.box-1 .inner {
	width: 260px;
	height: 80px;
	outline: 3px solid red;
	outline-offset: -3px;
	background-color: transparent;
}

結果は、.child-2はサイズが.innerに合わせて小さくなりましたが、.child-1の方はサイズ・位置ともに例1から変化しないことがわかります。理由は、上述の包含ブロックの定義によると、.child-1から見て「the nearest ancestor with a 'position' of 'absolute', 'relative' or 'fixed'」(position の値が static 以外の直近の祖先要素)は.box-1のままなので、.child-1は.innerのサイズに影響を受けないためです。

例2. position: relativeのときのtop, left: 100%

次に、例1で.child-1のpositionの値をabsoluteからrelativeに変えてみます(下図の.child-3)。
02_1.gif

html
<div class="box-1">
  <div class="child-3 child-box"><p>width, height 50%<br>top, left 100%</p></div>
  <div class="child-4 child-box"><p>width, height 50%<br>top, left 100%</p></div>
</div>
CSS (要点のみ)
css
.box-1 { /* 例1と同じ */}
.child-box { /* 例1と同じ */}

.child-3,
.child-4 {
  color: #fff;
  position: relative;
  top: 100%;
  left: 100%;
}

.child-3 { background-color: #004d40; }
.child-4 { background-color: #009688; }
要素のサイズと位置に関して、.child-3と例1の.child-1との違いに着目してください。width, heightは50%でどちらの子要素も同じですが、.child-3の方が.child-1より小さくなりましたね。つまり、`position: relative`を設定した.child-3の方は、
  • width, heightがそれぞれ.box-1のコンテンツ領域のwidth, heightの50%になっている。
  • 元々の位置(top: 0, left: 0)は.box-1のコンテンツ領域の左上角になっている。
  • top,leftを100%にした結果、元の位置から.box-1のコンテンツ領域の幅と高さの分だけ離れた位置に配置されている。

図で、.child-4は.child-3の後続要素であり、同じくposition: relativeを設定しています。.child-3と相対的な位置関係を維持したまま再配置されています。

上記の計算根拠をCSSの仕様書で確認してみましょう。widthに関して、10.2 Content width: the 'width' propertyによると、

The percentage is calculated with respect to the width of the generated box's containing block.

topに関して、9.3.2 Box offsets: 'top', 'right', 'bottom', 'left'によると、

The offset is a percentage of the containing block's width (for 'left' or 'right') or height (for 'top' and 'bottom').

で、position: relativeの要素に対する包含ブロックの定義を確認すると、10.1 Definition of "containing block"にあるとおり、

2.For other elements, if the element's position is 'relative' or 'static', the containing block is formed by the content edge of the nearest ancestor box that is a block container or which establishes a formatting context.

例3. translate(X%, Y%)

例1で示したように、translate(X%, Y%)のX, Yは、要素自身のボーダー含む幅・高さに対する割合です。ちなみに、親要素のwidth, heightがautoでないとき、子要素のpositionとtranslateのパーセントに50%を指定することにより、親要素の縦横中央にブロック要素を配置することができます(下図)。
DEMO: https://codepen.io/kaz_hashimoto/pen/vYBWLZz

css
.center {
  width: 200px;
  height: 80px;
  position: absolute;
  top: 50%;  /* 包含ブロックのパディング領域の縦中央*/
  left: 50%; /* (同)横中央*/
  transform: translate(-50%, -50%);  /* 要素自身の幅・高さの半分だけ位置をずらす */
}

div-center_1.gif

transformプロパティのパーセント値についてCSSの仕様書で確認してみましょう。4. The transform Propertyによると、Percentagesは

refer to the size of reference box

reference boxとは6. Transform reference box: the transform-box propertyによると、transform-boxプロパティの値がたとえばborder-boxの場合、

Uses the border box as reference box.

ブラウザの開発ツールからtransform-boxの初期値を調べると、border-box (Firefox, Safari), view-box (Chrome, Opera)になっていました。仕様書の上記説明の補足に以下の記載があるので、Chrome/Operaの動作もborder-boxとみなしてよいのかも?

For elements with associated CSS layout box, the used value for fill-box is content-box and for stroke-box and view-box is border-box.

例4. padding-top: 100%

padding-topにパーセント値を指定した場合は、包含ブロックのコンテンツ領域のに対する割合になります(下図)。幅が可変の親要素の中に、縦横比が一定の領域を確保してブロック要素を配置したいときなどにこのテクニックが役立ちます。(例:width: 100%; padding-top: 75%;

03_1.gif

html
<div class="box-2">
  <div class="child-5"><p>padding-top<br>100%</p></div>
</div>
CSS (要点のみ)
css
.box-2 {
  width: 200px;
  height: 100px;
  padding: 10px 70px;
  border: 16px solid rgba(0,0,0,0.3);
  background-color: #B3E5FC;
}

.child-5 {
  box-sizing: border-box;
  padding-top: 100%;
  width: 50%;
  line-height: 1.4;
  background-color: #FF5722;
  border: 1px solid #000;
}
padding-topプロパティのパーセント値についてCSSの仕様書で確認してみましょう。[8.4 Padding properties: 'padding-top', 'padding-right', 'padding-bottom', 'padding-left', and 'padding'](https://drafts.csswg.org/css2/box.html#propdef-padding-top)によると、確かにこう書かれてます。 > The percentage is calculated with respect to the **width** of the generated box's containing block, even for 'padding-top' and 'padding-bottom'.
18
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?