こんにちは!Webブラウザの仕組みの裏側を覗く旅へようこそ。
日々のWeb制作、本当にお疲れ様です。「CSSを書いたら、なぜか意図しないところがガタガタ動いちゃった…」「ちょっとしたアニメーションを入れただけなのに、ページ全体のスクロールがカクつく…」そんな涙ぐましい経験、ありませんか? 大丈夫です、あなただけじゃありません。世界中のフロントエンドエンジニアが毎日のように頭を悩ませている「あるある」です。
今日は、そんな私たちの救世主となってくれる、ちょっとマニアックだけど最高にクールな技術「CSS Containment(コンテインメント)」、その中でも主役である `contain` プロパティについて、難しい専門用語の壁をすっと取り払って、一緒に紐解いていきましょう!
—
1. Webブラウザの「おせっかいな大掃除」の正体
まず、ブラウザが画面を表示する仕組みを、身近な例えでお話ししますね。
例えば、あなたの部屋(Webページ)の片隅で、小さな付箋紙(要素)の文字を書き換えたとします。普通なら「そこだけ直せばいいじゃん!」と思いますよね? でも、真面目すぎるブラウザのレンダリングエンジンは、こう考えます。
「大変だ!付箋の文字が変わったことで、部屋全体のバランスが変わったかもしれない! カーテンのドレープも、本棚の傾きも、もしかしたら床のフローワングの寸法まで全部計算し直さなきゃ!」
これが、ブラウザの「レイアウト再計算(リフロー)」です。
DOMのほんの一部が変わっただけなのに、ブラウザは「影響範囲が分からないから、とりあえずドキュメントのてっぺんから底まで全部チェックし直そう」と、家中を大掃除し始めちゃうんです。これがページの重さ、すなわちカクつきの根本原因。
ここで登場するのが、今回主役の `contain` プロパティ です。
—
2. `contain` プロパティってなに?(お買い物の「仕切り板」の例え)
`contain`(コンテイン=封じ込める、独立させる)は、一言で言うと「ブラウザに対する、通行止めと立ち入り禁止の看板」です。
スーパーのレジを想像してみてください。たくさんのレジ袋やカゴがごちゃ混ぜになっていたら、お会計は大混乱しますよね。だから、レジごとに「ここからここまでがあなたの担当エリアです」と仕切り板があります。
`contain` を使うと、まさにその「仕切り板」をDOMツリーの中に作ることができます。
「このエリアの中で起きた変更は、このエリアの外には一歩も漏らさない! だから、外のエリアは再計算しなくていいよ!」と、ブラウザの過剰なおせっかいをピタッと止めてあげられるのです。
これにより、ブラウザの計算量が劇的に減り、ページの動作が嘘のように軽くなります。
—
3. 具体的にどう使うの?代表的なキーワードたち
`contain` プロパティには、いくつかのモード(キーワード)があります。最初は全部覚えなくて大丈夫です。まずは一番よく使う代表選手たちを見ていきましょう。
① `contain: layout;` (レイアウトの隔離)
「この要素の中で何が起きようとも、外側のレイアウトには影響しません」と宣言します。絶対配置(`position: absolute` など)の子供が暴れても、親の外側には飛び出さないようになります。
② `contain: paint;` (描画の隔離・クリッピング)
「この要素からはみ出たものは、一切画面に描画(ペイント)しません」というお墨付きを与えます。これによって、要素が画面の外(スクロース領域の外など)にあるとき、ブラウザは「どうせ見えないから描画の計算をサボっちゃおう!」と賢くサボってくれるようになります(これを「レイヤーの最適化」と言います)。
③ `contain: size;` (サイズの独立)
「この要素の大きさは、中の子供たちの大きさに関係なく独立しています」と伝えます。ただし、これは少し上級者向けで、要素の幅や高さをあらかじめCSSで固定している場合にしか使えません。
④ そして全部乗せの最強キーワード:`contain: strict;`
上記を全部まとめて適用するのが `strict` です。「完全に孤立した別世界」を作ります。ただし、少し強力すぎて中の要素が見えなくなったりすることがあるので、実務ではもう少しマイルドな `content` という値(`layout`, `paint`, `style` の複合)を使うことが多いです。
—
4. 実務でどう書く?サンプルコードで体感しよう
百聞は一見にしかず。みんな大好き、チャットアプリやニュースフィードの「無限スクロール(あるいは大量のコメント欄)」をイメージしたコードを見てみましょう。
このコードの `.post-card` に指定した `contain: layout paint;` が、まさにブラウザへの「ここから先は独立した小部屋ですよ」というサインです。例えば、JavaScriptでこのカードの中身を書き換えたとき、ブラウザは他のカードの再計算をパパッとスキップしてくれます。
—
5. 使っていく上での注意点(転ば先の杖)
ここまで読むと「じゃあ、すべての要素に `contain: strict;` を貼っちゃえば最強じゃん!」と思われるかもしれませんが、ちょっと待ってください!そこは優しいチーフアーキテクトからのアドバイスです。
Containment(分離)は、文字通り「外との通信を遮断する」ことでもあります。
そのため、以下のような副作用が起きることがあります。
- ポップアップやドロップダウンが切れる:`contain: paint;` を使うと、要素からはみ出るもの(例えば `position: absolute;` で作ったセレクトボックスのメニューなど)が強制的にプツッと切れて(クリップされて)見えなくなります。「あれ、メニューが消えた!?」と慌てないようにしましょう。
- サイズが決まっていないと潰れる:`contain: size;` を使うと、明示的に高さを指定していない限り、要素がペチャンコになってしまうことがあります。
「動的なウィジェット、タブ切り替えのコンテンツ、無限スクロールの各アイテム、モーダルウィンドウ」など、明確に他から独立させたい独立部品(コンポーネント)単位で、ピンポイントに導入するのが、実務における一番安全で美味しい使い方です。
—
おわりに
いかがでしたでしょうか?
`contain` プロパティは、一見すると地味で難しそうに見えますが、その正体は「ブラウザに無駄な苦労をさせないための、優しい思いやりプロパティ」です。
Webブラウザの気持ちになって、「ここは独立させてあげたほうが、ブラウザくんも楽ちんだよね」という視点を持てるようになると、あなたの書くフロントエンドコードは一段も二段も洗練されていきます。
もし次のプロジェクトでスクロールのカクつきやパフォーマンスの低下に悩んだら、ぜひこの「仕切り板」のことを思い出してみてくださいね。あなたのWeb制作ライフが、より軽やかで楽しいものになりますように!

コメント