こんにちは。今回はposition: fixed;が効かない理由とその対処法をまとめていきます。
なぜposition:fixed;が効かないのか | 親要素がtransformしていると効かない
例えばこんなヘッダーを作ろうとしています。こういうヘッダー、コーディングしてると結構出会います。
- ページ読み込み時にしたからふわっと出てくる
- グローバルナビがスクロールに追従する
見た目としてはこんな感じです。
さて、これをコーディングすると考えてみます。
まずは見た目はこんな感じでしょう。
<header class="Header" id="Header">
<nav class="Nav">
<ul class="List">
<li class="List-Item"><a href="#">メニュー1</a></li>
<li class="List-Item"><a href="#">メニュー2</a></li>
<li class="List-Item"><a href="#">メニュー3</a></li>
</ul>
</nav>
</header>
.Header {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 60px;
background-color: #6ba6e7;
}
.Nav {
position: fixed;
top: 18px;
right: 20px;
}
.List {
display: flex;
gap: 20px;
}
.List-Item {
color: #fff;
font-size: 24px;
line-height: 1;
}
アニメーションは以下のような形。
<script
src="https://code.jquery.com/jquery-3.6.0.slim.min.js"
integrity="sha256-u7e5khyithlIdTpu22PHhENmPcRdFiHRjhAuHcs05RI="
crossorigin="anonymous"
></script>
<script>
window.onload = function () {
$("#Header").addClass("FadeIn")
}
</script>
.Header {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 60px;
background-color: #6ba6e7;
transition: all 1s; //追加
transform: translateY(30px); //追加
opacity: 0; //追加
}
...省略
.FadeIn {
transform: translateY(0);
opacity: 1;
}
さて、こうするとなんとposition: fixed;を指定しているはずのグローバルナビ部分がスクロールに追従しません(試してみてください)。
これは親要素(今回は.Header)に、アニメーションのためのtransform: translateY(30px)が付与されているからです。
MDNのpositionプロパティのページ(https://developer.mozilla.org/ja/docs/Web/CSS/position)にも、fixedについて以下のように書かれています。
祖先の一つに transform, perspective, filter の何れかのプロパティが none 以外 (CSS Transforms 仕様書を参照) に設定されている場合は例外で、その場合は祖先が包含ブロックとしてふるまいます。
要するに、親要素にtransformなどの指定があるとposition: absolute;と同様の挙動になってしまうのです。
どう対処するか
transform以外の方法が使えるならそちらを使う
今回であれば.Headerと.Navのtopの値を調整すれば実現可能です。それぞれtranslateYを使った時と同様に最初の値を30pxずらします。
.Header {
position: absolute;
top: 30px; //変更
left: 0;
width: 100%;
height: 60px;
background-color: #6ba6e7;
transition: all 1s;
opacity: 0;
}
.Nav {
position: fixed;
top: 48px; //変更
right: 20px;
transition: all 1s; //追加
opacity: 0; //追加
}
...省略
//追加
.FadeIn__Nav {
top: 18px;
opacity: 1;
}
window.onload = function () {
$("#Header").addClass("FadeIn")
$("#Nav").addClass("FadeIn__Nav") //追加
}
これで想定通りの動きになります。
子要素をそれぞれtransformさせる
position: fixed;にしたい要素の親要素にtransformが指定されているのが問題なので、その状態さえ回避すれば良いです。背景とグローバルナビ部分を分け、それぞれをtransformさせます。
<header class="Header" id="Header">
<div class="Header__Background js-FadeIn"></div> <!-- 追加 -->
<nav class="Nav js-FadeIn"> <!-- js-FadeInというクラスを追加 -->
<ul class="List">
<li class="List-Item"><a href="#">メニュー1</a></li>
<li class="List-Item"><a href="#">メニュー2</a></li>
<li class="List-Item"><a href="#">メニュー3</a></li>
</ul>
</nav>
</header>
.Header {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 60px;
//background-colorを削除
}
//追加
.Header__Background {
width: 100%;
height: 100%;
background-color: #6ba6e7;
transition: all 1s;
transform: translateY(30px);
opacity: 0;
}
.Nav {
position: fixed;
top: 18px;
right: 20px;
transition: all 1s; //追加
transform: translateY(30px); //追加
opacity: 0; //追加
}
<script>
window.onload = function () {
$(".js-FadeIn").addClass("FadeIn") //.js-FadeInを対象に変更
}
</script>
これで想定通りの動きになります。
まとめ
というわけで、position: fixed;が効かない理由と、その対処をまとめました。知らないとかなり対処が難しいので、ぜひ参考にしてください。
コメント