position:sticky;の使い方と上手く機能しない場合の解決方法を解説

position:sticky;の使い方と上手く機能しない場合の解決方法を解説

position:sticky;はスクロールしたときに、要素が指定した位置に来たところから固定させることができるとても便利なプロパティです。

position:fixed;と似ていますが、position:sticky;ならjavascriptも書かないとできなかった難しい指定がたった2行でできてしまいます。

また指定したのに上手く機能しないといった場合の解決方法も書いています。

ぜひこの機会に覚えて積極的に使っていきましょう。

この記事で身につく内容

  • position:sticky;とposition:fixed;の違い
  • 基本的な使い方
  • 便利な使い方
  • position:sticky;が効かない場合の対処法

position:sticky;とは

大きな特徴は最初から固定するのではなく、要素が画面内の指定した位置に来たところから固定表示できる点です。また、要素の高さを保ったまま固定表示することができレイアウトに影響を与えない点です。

この点がこの後解説するposition:fixed;との大きな違いなのでぜひ覚えてください。

まずはサンプルで動きを確認してみましょう!

position:sticky;とposition:fixed;の違い

要素の位置を固定するという点で似ているposition:sticky;とposition:fixed;ですが、明確な違いがありますのでまずはそこを確認していきましょう。

要素が固定される位置

  • position:sticky:親要素
  • position:fixed:画面全体

要素の高さ

  • position:sticky:保たれる
  • position:fixed:保たれない

位置の指定

  • position:sticky:必要
  • position:fixed:不要
位置の基準 要素の高さ 位置の指定
sticky 親要素 保たれる 必要
fixed 画面全体 保たれない 不要

スティッキーコンテナとは?

スティッキーコンテナはスティッキーアイテムをラップする親要素になります。特に何も指定する必要はありませんが、position:sticky;を理解する上で重要な要素なので覚えておきましょう。

スティッキーアイテムとは?

CSSでposition:sticky;を指定した要素がスティッキーアイテムになります。スティッキーアイテムはスティッキーコンテナ内でのみ固定表示することができます。

position:sticky; の使い方

では実際の使い方を見ていきましょう。

基本のコード

HTML

<body>
	<div class="contents">
		<h1>position:sticky;の基本的な使い方</h1>
		<div class="box sticky_container">
			<h2 class="sticky_item">スティッキーアイテムを指定したタイトル</h2>
			<p>コンテンツ</p>
		</div>
		<div class="box sticky_container">
			<h2 class="sticky_item">スティッキーアイテムを指定したタイトル2</h2>
			<p>コンテンツ</p>
		</div>
	</div>
	<div class="scroll_area">
		<p>スクロール領域を確保するためのエリア</p>
	</div>
</body>

こちらの例ではh2タイトルにクラス名sticky_itemをつけてposition:sticky;を指定します。ポイントは、CSSの指定は必要はありませんがスティッキーアイテムをラップする親要素のスティッキーコンテナに高さがあるかを意識しておくことです。

上手く機能しない場合のほとんどの原因が、スティッキーコンテナに固定表示するだけの十分な高さがないことによるためです。

CSS

.contents{
	margin: 0 auto;
	max-width: 800px;
	padding: 60px;
}
.contents h1{
	margin-bottom: 60px;
	text-align: center;
}
.box{
	border: 2px dashed #ccc;
	height: 1000px;
	padding: 20px;
}
.box + .box{
	margin-top: 40px;
}
.sticky_container{
	border: 2px dashed #7f31d6;
}
.sticky_item{
	background: #fff;
	color: #7f31d6;
	position: sticky;
	top: 0;
}
.scroll_area{
	background: #ccc;
	margin-top: 60px;
	height: 1000px;
	padding: 40px;
}

必要なCSSはハイライトしたたった2行だけです。ポイントはposition: sticky;だけの指定では機能しないためtopやbottomも合わせて指定する必要があることです。これはスティッキーアイテムを画面のどの位置に固定するかを明確にするためです。

では上記を踏まえた基本的なサンプルを見てみましょう。

スティッキーアイテムがスティッキーコンテナの枠線の中だけで固定表示されていることがわかります。

z-indexで重なり順を変更する

固定表示される際に重なり順を変更することもできます。

HTML

<body>
	<div class="contents">
		<h1>position:sticky;の重なり順を変更</h1>
		<div class="box sticky_container">
			<div class="sticky_item1">sticky_item1</div>
			<div class="sticky_item2">sticky_item2</div>
		</div>
	</div>
	<div class="scroll_area">
		<p>スクロール領域を確保するためのエリア</p>
	</div>
</body>

本来ならsticky_item2の方が後に配置されているので、重なり順は上になりますがこの後のCSSで変更します。

CSS

.contents{
	margin: 0 auto;
	max-width: 800px;
	padding: 60px;
}
.contents h1{
	margin-bottom: 60px;
	text-align: center;
}
.box{
	border: 2px dashed #ccc;
	height: 1000px;
	padding: 20px;
}
.sticky_container{
	border: 2px dashed #7f31d6;
}
.sticky_item1{
	background: #74D7EE;
	height: 200px;
	padding: 20px;
	position: sticky;
	top: 0;
	width: 200px;
	z-index: 1;
}
.sticky_item2{
	background: #FEF968;
	height: 200px;
	margin-left: 100px;
	padding: 20px;
	position: sticky;
	top: 0;
	width: 200px;
}
.scroll_area{
	background: #ccc;
	margin-top: 60px;
	height: 1000px;
	padding: 40px;
}

sticky_item1の方にz-index:1を指定しました。z-indexの初期値は0なのでこれでsticky_item2より重なり順を上に変更できました。

便利な使い方5選

次に実用的な使い方の例を5つご紹介します。

01.ヘッダーを固定させる

ヘッダーの固定表示は今や当たり前になっていますが、position: sticky;を使うと、とても簡単にできます。

HTML

<body>
	<header class="sticky_header">
		<img src="img/logo.webp" alt="logo">
	</header>
	<div class="contents">
		<p>コンテンツ</p>
	</div>
	<div class="scroll_area">
		<p>スクロール領域を確保するためのエリア</p>
	</div>
</body>

こちらの例ではbodyがスティッキーコンテナになります。

CSS

.sticky_header{
	background: #eee;
	padding: 20px;
	position: sticky;
	top: 0;
}
.sticky_header img{
	height: 60px;
}
.contents{
	background: #74D7EE;
	height: 1000px;
	margin: 60px auto 0;
	width: 1140px;
	padding: 60px;
}
.scroll_area{
	background: #ccc;
	margin-top: 60px;
	height: 1000px;
	padding: 40px;
}

ほとんど装飾やレイアウトの指定のため、やっていることは基本的なことと全く同じです。sticky_headerにposition: sticky;とtop:0を指定して固定表示させます。

ポイントは、ヘッダーが最初から固定表示されているのにその後に続く要素が下に回り込んでしまわないということです。これが冒頭に書いた要素の高さを保ったまま固定表示することができるのでレイアウトに影響がないということです。

position: fixed;だと要素の高さがなくなってしまい後に続く要素が下に回り込んでしまうため、marginやpaddingでその分の余白を取る必要がありました。

この下に回り込んでしまう分の余白対応が面倒だったんですよね。。。あとstickyはwidthの指定も必要ないですが、fixedでは必要になります。

さらに画面最上部にヘッダーがなくても同様に固定できます。

HTML

<body>
	<div class="fv_banner">
		ヘッダー上のエリア
	</div>
	<header class="sticky_header">
		<img src="img/logo.webp" alt="logo">
	</header>
	<div class="contents">
		<p>コンテンツ</p>
	</div>
	<div class="scroll_area">
		<p>スクロール領域を確保するためのエリア</p>
	</div>
</body>

ヘッダー上にエリアを追加しただけです。

CSS

.fv_banner{
	background: #ccc;
	padding: 80px;
	text-align: center;
}
.sticky_header{
	background: #eee;
	padding: 20px;
	position: sticky;
	top: 0;
	z-index: 10;
}
.sticky_header img{
	height: 60px;
}
.contents{
	background: #74D7EE;
	height: 1000px;
	margin: 60px auto 0;
	width: 1140px;
	padding: 60px;
}
.scroll_area{
	background: #ccc;
	margin-top: 60px;
	height: 1000px;
	padding: 40px;
}

CSSもヘッダー上のエリアのスタイルが追加になっただけで他はいじってません。

途中から固定させるのもコードの変更さえ必要なく、あまりにも簡単なので拍子抜けしますが、これをposition: fixed;やろうとするとさあ大変です!

以前、まだposition: sticky;を知らない私が四苦八苦しながら書いた記事があるので、お時間あれば見てみてください。jQueryを駆使して画面のスクロール位置を取得してゴニョゴニョやっているのを見ると、いかにposition: sticky;が優れているかわかります。

02.サイドバーでバナーを固定させる

当サイトでもサイドバーの目次と広告を固定表示しております。サイドバーのエリアを有効活用できるテクニックなので、2カラムレイアウトのブログなどではぜひ取り入れたいですね。

HTML

<body>
	<header class="sticky_header">
		<img src="img/logo.webp" alt="logo">
	</header>
	<div class="flex_container">
		<div class="main_contents">
			<p>メインカラムのコンテンツ</p>
		</div>
		<aside class="sidebar">
			<div class="sidebar_box">
				サイドバーのコンテンツ
			</div>
			<div class="sidebar_box">
				サイドバーのコンテンツ
			</div>
			<div class="sidebar_box sticky_banner">
				固定表示させるバナー
			</div>
			<div class="sidebar_box">
				サイドバーのコンテンツ
			</div>
		</aside>
	</div>
	<div class="scroll_area">
		<p>スクロール領域を確保するためのエリア</p>
	</div>
</body>

こちらの例ではasideがスティッキーコンテナになります。

.sticky_header{
	background: #eee;
	padding: 20px;
	position: sticky;
	top: 0;
	z-index: 10;
}
.sticky_header img{
	height: 60px;
}
.flex_container{
	display: flex;
	justify-content: space-between;
	margin: 60px auto 0;
	width: 1140px;
}
.main_contents{
	background: #FEF968;
	height: 2000px;
	padding: 40px;
	width: 60%;
}
.sidebar{
	background: #01B8BE;
	padding: 40px;
	width: 36%;
}
.sidebar_box{
	background: #fff;
	padding: 20px;
	height: 100px;
}
.sidebar_box + .sidebar_box{
	margin-top: 20px;
}
.sticky_banner{
	background: #FEF968;
	height: 200px;
	position: sticky;
	top: 106px;
}
.scroll_area{
	background: #ccc;
	margin-top: 60px;
	height: 2000px;
	padding: 40px;
}

ここでのポイントは、メインカラムとサイドバーを横並びにして、かつ高さも揃えるため、flex_containerにdisplay:flex;を指定している点です。

display:flex;の便利なところは横並びになったボックスの高さが揃うことです。ひと昔前までレイアウトの主流だったfloatでは高さは揃わず固定表示できません。

あとは今までやってきた通り、固定表示させるsticky_bannerにposition: sticky;とtopの指定をします。

display:flex;について詳しく説明した記事もあるので興味がある方は見てみてください。

03.フッターを固定させる

ここまでずっとtopで画面上部に固定表示してきましたが、bottomで画面下部に固定表示することもできますよというサンプルです。

HTML

<body>
	<header class="header">
		<img src="img/logo.webp" alt="logo">
	</header>
	<div class="flex_container">
		<div class="main_contents">
			<p>メインカラムのコンテンツ</p>
		</div>
		<aside class="sidebar">
			<div class="sidebar_box">
				サイドバーのコンテンツ
			</div>
			<div class="sidebar_box">
				サイドバーのコンテンツ
			</div>
			<div class="sidebar_box">
				サイドバーのコンテンツ
			</div>
		</aside>
	</div>
	<footer class="sticky_footer">
		<p>固定表示させるフッター</p>
	</footer>
	<div class="scroll_area">
		<p>スクロール領域を確保するためのエリア</p>
	</div>
</body>

こちらもbodyがスティッキーコンテナになります。

CSS

.header{
	background: #eee;
	padding: 20px;
}
.header img{
	height: 60px;
}
.flex_container{
	display: flex;
	justify-content: space-between;
	margin: 60px auto 0;
	width: 1140px;
}
.main_contents{
	background: #74D7EE;
	height: 2000px;
	padding: 40px;
	width: 60%;
}
.sidebar{
	background: #01B8BE;
	padding: 40px;
	width: 36%;
}
.sidebar_box{
	background: #fff;
	padding: 20px;
	height: 100px;
}
.sidebar_box + .sidebar_box{
	margin-top: 20px;
}
.sticky_footer{
	background: #FEF968;
	bottom: 0;
	margin-top: 60px;
	padding: 40px;
	position: sticky;
}
.scroll_area{
	background: #ccc;
	margin-top: 60px;
	height: 1000px;
	padding: 40px;
}

前述の通りtopではなくbottomを指定します。

実際の制作ではあまりないとは思いますが、フッター下にさらにスクロール領域があるので、フッターが本来ある位置に来た以降は、固定表示ではなくなっているのがわかります。

04.見出しを固定させる

こちらについては冒頭の基本的な使い方のサンプルが正にこれなのですが、もう少し実用性がありそうなサンプルにしてみました。

HTML

<body>
	<header class="header">
		<img src="img/logo.webp" alt="logo">
	</header>
	<div class="contents">
		<div class="contents_item">
			<div class="contents_item_title">
				<h2>コンテンツタイトル</h2>
			</div>
			<div class="contents_item_text">
				<p>コンテンツテキスト</p>
			</div>
		</div>
		<div class="contents_item">
			<div class="contents_item_title">
				<h2>コンテンツタイトル</h2>
			</div>
			<div class="contents_item_text">
				<p>コンテンツテキスト</p>
			</div>
		</div>
	</div>
	<footer class="footer">
		<p>フッター</p>
	</footer>
	<div class="scroll_area">
		<p>スクロール領域を確保するためのエリア</p>
	</div>
</body>

こちらの例ではcontents_item_titleがスティッキーコンテナになります。

CSS

.header{
	background: #eee;
	padding: 20px;
}
.header img{
	height: 60px;
}
.contents{
	margin: 60px auto 0;
	width: 1140px;
}
.contents_item{
	display: flex;
	justify-content: space-between;
}
.contents_item + .contents_item{
	margin-top: 60px;
}
.contents_item_title{
	width: 36%;
}
.contents_item_title h2{
	position: sticky;
	top: 0;
}
.contents_item_text{
	background: #eee;
	height: 600px;
	padding: 40px;
	width: 60%;
}
.footer{
	background: #FEF968;
	margin-top: 60px;
	padding: 40px;
}
.scroll_area{
	background: #ccc;
	margin-top: 60px;
	height: 1000px;
	padding: 40px;
}

実はサイドバーでバナーを固定表示させたのとやり方は全く一緒です。display:flex;でタイトルエリアとテキストアリアを横並びにしつつ高さを揃えてタイトルを固定表示しています。

05.画像を固定させる

タイトルだけではイメージがわかないかもしれないですが、サンプルを見てもらうと「こんなの見たことある!」となると思います。こちらも小難しい指定は必要なくとても簡単です。

HTML

<body>
	<header class="header">
		<img src="img/logo.webp" alt="logo">
	</header>
	<div class="contents">
		<img class="sticky_img" src="img/img1.jpg" alt="img1">
		<img class="sticky_img" src="img/img2.jpg" alt="img2">
		<img class="sticky_img" src="img/img3.jpg" alt="img3">
		<img class="sticky_img" src="img/img4.jpg" alt="img4">
	</div>
	<div class="scroll_area">
		<p>スクロール領域を確保するためのエリア</p>
	</div>
</body>

4つの画像が縦に並ぶように配置しただけです。

CSS

.header{
	background: #eee;
	padding: 20px;
}
.header img{
	height: 60px;
}
.sticky_img{
	height: auto;
	position: sticky;
	top: 0;
	width: 100%;
}
.scroll_area{
	background: #ccc;
	margin-top: 60px;
	height: 1000px;
	padding: 40px;
}

やっていることはずっと変わらず、固定表示させたいsticky_imgにposition: sticky;とtopを指定しているだけです。

position:sticky; が機能しないときの対処法

ここからはposition:sticky; が上手く機能しないときの対処法を見ていきましょう。この項目の最後にまとめのチェックリストもあるのでそちらでもチェックしてみください。

スティッキーコンテナ(親要素)に高さがない

すでにお伝えしましたが、スティッキーアイテムはスティッキーコンテナ内でのみ固定表示されます。ということはスティッキーコンテナに高さがなければ固定表示はされません。

陥りやすいパターンとして先ほどやった「サイドバーでバナーを固定させる」サンプルに1箇所だけ手を加えてやってみたいと思います。下記が上手く機能しないサンプルです。

変更したのはHTMLのみ。asideの中にさらにsticky_containerというdivを加えています。

<body>
		<header class="sticky_header">
			<img src="img/logo.webp" alt="logo">
		</header>
		<div class="flex_container">
			<div class="main_contents">
				<p>メインカラムのコンテンツ</p>
			</div>
			<aside class="sidebar">
				<div class="sticky_container">
					<div class="sidebar_box">
						サイドバーのコンテンツ
					</div>
					<div class="sidebar_box">
						サイドバーのコンテンツ
					</div>
					<div class="sidebar_box">
						サイドバーのコンテンツ
					</div>
					<div class="sidebar_box sticky_banner">
						固定表示させるバナー
					</div>
				</div>
			</aside>
		</div>
		<div class="scroll_area">
			<p>スクロール領域を確保するためのエリア</p>
		</div>
	</body>

こうしてしまうとせっかくdisplay:flex;でメインコンテンツとサイドバーの高さが揃っているのに、スティッキーコンテナはsticky_containerになります。そして高さがなくなったために機能しなくなってしまいました。

固定する位置(topやbottom)を指定していない

こちらも基本的な使い方で触れましたが、スティッキーアイテムを画面のどの位置に固定するかを指定しないと機能しません。下記が位置の指定をなくしたサンプルです。

こちらは先ほどの「見出しを固定表示する」サンプルのCSSのみ変更しました。見出しのCSS指定を1個目と2個目で別にして、2個目の方はtopの指定をなしにしています。

.header{
	background: #eee;
	padding: 20px;
}
.header img{
	height: 60px;
}
.contents{
	margin: 60px auto 0;
	width: 1140px;
}
.contents_item{
	display: flex;
	justify-content: space-between;
}
.contents_item + .contents_item{
	margin-top: 60px;
}
.contents_item_title{
	width: 36%;
}
.contents_item_title.title1 h2{
	position: sticky;
	top: 0;
}
.contents_item_title.title2 h2{
	position: sticky;
}
.contents_item_text{
	background: #eee;
	height: 600px;
	padding: 40px;
	width: 60%;
}
.footer{
	background: #FEF968;
	margin-top: 60px;
	padding: 40px;
}
.scroll_area{
	background: #ccc;
	margin-top: 60px;
	height: 1000px;
	padding: 40px;
}

位置の指定がないとブラウザはどこに固定表示すれば良いかわからないため機能しなくなってしまうというわけです。

要素にoverflowが指定されている

こちらもハマりやすいパターンです。position: sticky;を指定した要素の親要素にデフォルトであるoverflow: visible ;以外の値(auto,hidden,scroll)の指定があると機能しません。もっと言うと親要素だけでなく先祖要素も同様です。

ですので上手く機能しない際にoverflowが原因の場合は親要素だけ調べても解決しない可能性があるので、その場合は先祖要素までさかのぼって調べる必要があります。

上手く機能しない場合のまとめ

改めて以下に原因をまとめます。

ブラウザの対応状況

position: sticky; は、Internet Explorerではサポートされていませんでした。また、数年前まではsafariでベンダープレフィックスを指定する必要がありました。この辺りがposition: sticky; の使用を避けてしまう原因でした。

しかし現在(2024.06時点)ではInternet Explorerのサポートが終了し、safariでベンダープレフィックスを指定する必要もなくなりました。

ということで使用する上での懸念材料は全てなくなりましたので安心して使っていきましょう!

まとめ

position: sticky;について細かく解説をしました。「position: fixed;じゃないと実装できない」という場面に出会ったことがなく、むしろここまで解説してきた通りposition: sticky;の方が少し複雑な仕様も明らかに実装ハードルが低いのでぜひ積極的に使ってみてください。

position: sticky;のまとめ

  • 要素が画面内の指定した位置に来たところから固定表示できる
  • 要素の高さを保ったまま固定表示することができるのでレイアウトが崩れない
  • スティッキーコンテナ(親要素)内でのみ固定表示される
  • z-indexで重なり順も変更可能
Category&Tag