CSSのposition:fixedが効かない時の原因と対策
2022/12/03
ページのスクロール時に、ある要素を画面の特定の位置に固定したい場合があります。
例えば、ナビゲーションメニューやページトップに戻るボタンなどです。
このように要素を固定したい時に、よく使われるCSSと言えばposition:fixed
を挙げられます。
しかし、一部の条件下でposition:fixed
がうまく機能しない…なんてケースがあります。
今回はposition:fixed
が効かない時の原因と対処法について解説します。
もくじ
1.position:fixedの基本事項を確認しよう
まずposition:fixed
の基本的な使い方について、簡単におさらいしておきましょう。
そもそもposition
とは、要素の位置を調整することができるプロパティです。
position
プロパティには以下の4つの値があります。
- static
- relative
- absolute
- fixed
static
はデフォルトの値で、位置調整ができません。
その他の値を指定した場合、top
、right
、bottom
、left
によって、具体的な位置を決めることができます。
例えば、以下のような感じにです。
1 2 3 4 5 |
.sample { position: relative; top: 100px; left: 50px; } |
直感的にわかると思いますが、top
は上から、right
は右から、bottom
は下から、left
は左からの距離を示してます。
「どこを基準にして」という部分をstatic
以外の値で決めます。
relative
なら「本来その要素がある位置」、absolute
は「親要素」、そしてfixed
は「画面」を基準とします。
今回の主役はfixed
なので、fixed
の使用方法のみ詳しく説明します。
例えば、以下のCSSを適用させてみましょう。
1 2 3 4 5 |
.sample { position: fixed; right: 50px; bottom: 50px; } |
right: 50px
、bottom: 50px
なので、画面の右と下から50pxの距離に固定されるはずです。
結果は以下のとおりです。
.sample
(青色の四角)は画面の右端付近に固定され、上下にスクロールしても位置を留めていることがわかります。
ちなみにposition: absolute
の場合、その親要素に対してstatic
以外の値を指定しないと思い通りに機能しませんが、fixed
にはそのような操作は必要ありません。
以上がposition: fixed
の基本的な使用方法です。
補足情報としてもう一点だけ。
現時点(22年12月)において、主要ブラウザでposition: fixedが使用できない…なんてことはほぼほぼありません。
参考:CSS position:fixed | Can I use… Support tables for HTML5, CSS3, etc
ただし「Opera Mini」と呼ばれるOperaのスマートフォン用のブラウザでは未対応のようです。
2.position:fixedが効かない原因は親要素のtransform
position: fixed
のコードの記述に問題が無ければ、効かない原因として疑われるのは親要素のtransform
です。
transform
とは要素を変形したり、移動させたりするCSSプロパティです。
主にメニューの開閉やボタンの変化など、アニメーションを施したい場合に使用されます。
実はposition: fixed
は、親要素のtransform
をnone
以外に指定していると上手く機能しません。
例えば、以下のように親(.parent)と子(.child)の関係にある要素があると仮定します。
1 2 3 |
<div class="parent"> <div class="child"></div> </div> |
さらにCSSで以下のように成形し、子要素にはposition: fixedを指定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
.parent { width: 100px; height: 100px; background: steelblue; } .child { position: fixed; top: 50px; right: 50px; width: 50px; height: 50px; background: tomato; } |
position: fixed
を指定された要素は、top
・right
・bottom
・left
によって親要素ではなく画面を基準にして位置調整できます。
結果は以下の通りで、親要素との位置関係を無視して、画面の上端(top)と右端(right)から50px離れた位置(9~10行目)で固定されています。
では、今度は親要素にtransform
を指定してみましょう。
1 2 3 4 5 6 |
.parent { width: 100px; height: 100px; transform: rotate(45deg); background: steelblue; } |
rotate()
(4行目)は、要素を好みの角度に回転させることができるCSS関数です。
角度の単位である「deg」で調整します。
では、子要素の挙動を確認してみましょう。
上図の通り、親要素の回転は成功したものの、子要素が適切な位置に固定されていないことがわかります。
現状、子要素には親要素を基準にしてtop
、right
の値が適用されているよう見えます。
すなわち、absolute
と同様な挙動になっています。
MDN Web Docsにもposition: fixed
の例外事項について以下のように述べられています。
祖先の一つに transform, perspective, filter の何れかのプロパティが none 以外に設定されている場合は例外で、その場合は祖先が包含ブロックとしてふるまいます。
position – CSS: カスケーディングスタイルシート | MDN
MDNによれば、親要素に対してtransform
だけでなくperspective
やfilter
の値がnone以外に指定されていると、同様な挙動になるようです。
3.position:fixedを有効にするための対処法
では、transform
を使いつつposition: fixed
をちゃんと機能させるためにはどうしたら良いのでしょうか。
3-1.固定したい要素をtransformが指定されている親要素から外す
そもそもposition: fixedは画面を基準にして位置を決めるためのものです。
親要素を基準としないため、コーディングする上で親子関係にする必要性が無いケースがほどんどです。
親要素が原因で子要素のposition: fixed
が効かないのであれば、親子関係を解消してあげれば良いです。
例えば、前述の例でいえばHTMLを以下のように変えてみます。
1 2 |
<div class="parent"></div> <div class="child"></div> |
.parent
の中の.child
を取り出して、並列させただけです(クラス名がややこしいですが^^;)。
結果は以下の通りで、もともと子要素だった要素(オレンジの四角)にきちんとposition :fixedが適用されていることがわかります。
元々、親要素だった要素(青の四角)のtransformも正常に機能しています。
このように親子関係である必要性が無ければ、要素を並列させることで問題を解決できます。
3-2.transform以外の方法で同じ動作が可能か探る
親子関係を維持したい場合には、親要素のほうのtransform
で実現したいことが、別のCSSプロパティで可能か考えてみると良いでしょう。
例えば、以下のHTMLを想定してください。
1 2 3 4 5 |
<div class="grandparent"> <div class="parent"> <div class="child"></div> </div> <div> |
そして、transform
のtranslate()
関数で.parent
を水平方向に移動させてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
.grandparent { width: 300px; height: 400px; background: tan; } .parent { width: 100px; height: 100px; transform: translate(50px); background: steelblue; } .child { position: fixed; top: 50px; right: 50px; width: 50px; height: 50px; background: tomato; } |
さらに、先程と同様に.child
にはposition: fixed
が指定されています。
しかし、親要素にtransform
が指定されているため、.child
のposition: fixed
は正常に機能しません。
現状は下図のとおりです。
ただし、要素の位置を調整するだけであればtransform
以外の方法もあります。
例えば、position: absolute
です。
先程のCSSを以下のように変更します(.childはそのまま)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
.grandparent { position: relative; width: 300px; height: 400px; background: tan; } .parent { position: absolute; left: 50px; width: 100px; height: 100px; background: steelblue; } |
absolute
の注意点として、親要素のposition
をstatic
以外に指定(2行目)する必要があることに気を付けましょう。
では、結果を見てみましょう。
子要素がposition: fixed
によって画面端に固定されており、また親要素の移動にも成功しました。
まとめ
今回はCSSのposition: fixedが効かない原因と対策について解説しました。
最後に今回、説明した内容をまとめておきます。
position: fixed
はほとんどの主要ブラウザで対応されている。- スペルに間違いがなければ、親要素に
transform
が指定されていないかチェックしよう。 - 親要素に
transform
がnone
以外に指定されていると、子要素のposition: fixed
は正常に機能なくなる - 親子(入れ子)関係を解消させるか、
transform
と代替可能なプロパティに変えても問題ないか試してみよう。