0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

position:fixedと包含ブロック (containing block)

Posted at

あまり機会がなく、すぐ忘れてしまうので備忘録として。

最終形はこちら

うまくいかないケース

下記のようなHTMLにおいて、CSSで.containeroverflow:scroll、(.fix)にposition:fixedを設定した時に、思った結果にならない。

<div class="container">
    <nav class="fix">ナビゲーションなど</nav>
    <p>長い文章〜(略)〜長い文章。</p>
</div>
body {
  padding: 100px 0;/* わかりやすいように隙間を開ける */
}

.container {
    border: 1px solid #ccc;
    width: 30em;
    height: 5em;
    overflow: hidden scroll;
}

nav.fix {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    background-color: #eee;
}

サンプル(jsfiddle)

期待

  • .containerの上部にnav.fixを固定したい
  • .containerをスクロールしてもposition:stickyのように、そのままの位置に固定したい

実際

  • nav.fixが画面(ビューポート)の上部に固定されてしまう
  • .containerposition:relativeとしてもうまくいかない(position:fixedな子孫要素の包含ブロックにはならない)

.containerを包含ブロックとして機能させられればいいのだが、そのためにはいくつかある条件の1つを満たす必要がある。

position:stickyを使う

たいていの場合はposition:fixedでなく、position:stickyで対応すればいい。

stickyを使ったサンプル
<div class="container">
    <nav class="fix">ナビゲーションなど</nav>
    <p>長い文章〜(略)〜長い文章。</p>
</div>
body {
  padding: 100px 0;/* わかりやすいように隙間を開ける */
}

.container {
    border: 1px solid #ccc;
    width: 30em;
    height: 5em;
    overflow: hidden scroll;
}

nav.fix {
-   position: fixed;
+   position: sticky;
    top: 0;
    left: 0;
    width: 100%;
    background-color: #eee;
}

サンプル(jsfiddle)

何らかの理由でposition:fixedでなければならない時

特にposition:stickyのような、粘着する動作を実現したい時には、HTMLの構造を変えるなどの工夫が必要。

まず、スクロールする要素を.content、fixedする要素を.fix、その2つを包含する要素を.containerとする。

<div class="container">
    <nav class="fix">ナビゲーションなど</nav>
+   <div class="content">
        <p>長い文章〜(略)〜長い文章。</p>
+   </div>
</div>
body {
  padding: 100px 0;/* わかりやすいように隙間を開ける */
}

.container {
    border: 1px solid #ccc;
    width: 30em;
    height: 5em;
-   overflow: hidden scroll;
}

+ .content {
+    width: 100%;
+    height: 100%;
+    overflow: hidden scroll;
+ }

nav.fix {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    background-color: #eee;
}

サンプル(jsfiddle)

(ここで、.container自体をスクロールできるようにすると、次項の処理を行なってもposition:stickyのように粘着する動作にならず失敗する。)

最終形

これだけだと、.fixはビューポートを基準に配置されてしまい、ページの最上部に固定されてしまうので、.containerが包含ブロック1となるように.containerのスタイルにtransform:scale(1)(など)を追加する。

<div class="container">
    <nav class="fix">ナビゲーションなど</nav>
    <div class="content">
        <p>長い文章〜(略)〜長い文章。</p>
    </div>
</div>
body {
  padding: 100px 0;
}

.container {
    border: 1px solid #ccc;
    width: 30em;
    height: 5em;
+   transform:scale(1);
}

.content {
    width: 100%;
    height: 100%;
    overflow: hidden scroll;
}

nav.fix {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    background-color: #eee;
}

サンプル(jsfiddle)

思いがけず包含ブロックになってしまうケース

別の事例で、思いがけず包含ブロックになってしまい、思いがけない結果になるケース。

<div class="content">
    <p>文章〜(略)〜文章</p>
    <nav>
        <button>Item 1</button>
        <button>Item 2</button>
        <div class="close">×</div>
    </nav>
</div>
.content {
  position: relative;
  border: 1px solid #ccc;
}

nav {
  background-color: #eee;
  filter: drop-shadow(3px 3px 3px rgba(0, 0, 0, 0.5));
}

.close {
  position: absolute;
  top: 4px;
  right: 4px;
}

サンプル(jsfiddle)

.close.contentの右上に配置するつもり。

しかし、navfitlerプロパティが設定され、値がnone以外であるため、navが包含ブロックになってしまう。

結果、.closenavの右上に表示される。

  1. MDN - レイアウトと包含ブロック - 包含ブロックの識別

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?