CSS コンテナ クエリのパワーを解き放つ: Netflix チームから学ぶ

Jeremy Weeks
Jeremy Weeks
Stefan Heymanns
Stefan Heymanns

コンテナクエリは、デベロッパーがレスポンシブ デザインに取り組む方法に革命をもたらしました。Netflix チームは、開発の効率化、柔軟性の向上、パフォーマンスの向上にコンテナクエリが及ぼす大きな影響を直接体験しています。この記事では、コンテナクエリを使用する主なメリットを、以前の方法(特に、レイアウト制御に JavaScript に依存する方法)と比較して説明します。各ポイントを説明するコードサンプルが含まれており、コンテナクエリによってデベロッパーの作業が大幅に簡素化される仕組みを説明しています。

1. コンポーネント設計の簡素化、「ボトムアップ」と「トップダウン」

Netflix チームが経験した最も大きな変化の 1 つは、「トップダウン」設計アプローチから「ボトムアップ」アプローチへの移行です。コンテナ クエリが導入される前は、親コンテナは子コンテナのレイアウト要件を完全に把握する必要がありました。コンテナ クエリでは、このロジックが逆になり、子コンポーネントは独自のコンテナのサイズに基づいてレイアウトを制御できます。これにより、親の役割が簡素化され、コード内のレイアウト ロジックの量が削減されます。

例: コンテナクエリとメディアクエリ、JavaScript の比較

以前(JavaScript が必要):

/* Layout with media queries */
.card {
    width: 100%;
}

@media (min-width: 600px) {
    .card {
        width: 50%;
    }
}

@media (min-width: 900px) {
    .card {
        width: 33.33%;
    }
}
// JavaScript to detect parent container size
const container = document.querySelector('.container');
const card = document.querySelector('.card');

function adjustLayout() {
    if (window.innerWidth >= 900) {
        card.style.width = '33.33%';
    } else if (window.innerWidth >= 600) {
        card.style.width = '50%';
    } else {
        card.style.width = '100%';
    }
}

window.addEventListener('resize', adjustLayout);
adjustLayout();

変換後:

/* Container Query */
.container {
    container-type: inline-size;
}

.card {
    width: 100%;
}

@container (min-width: 600px) {
    .card {
        width: 50%;
    }
}

@container (min-width: 900px) {
    .card {
        width: 33.33%;
    }
}

この例は、親コンテナが子レイアウトを管理する必要がなくなる方法を示しています。@container ルールを使用すると、.card は直近のコンテナのサイズに反応できるため、レイアウト ロジックを簡素化し、JavaScript を完全に不要にできます。

2. 複雑なメディアクエリを使用しないレスポンシブ性

Netflix チームは、コンテナクエリによって、特にモバイルファースト デザインのレスポンシブ性を簡素化する方法を発見しました。複雑なメディアクエリを記述する代わりに、コンテナのサイズに基づいて調整される再利用可能なコンポーネントを作成できます。これにより、さまざまな画面サイズとデバイスで動的レイアウトが可能になります。これは、モバイル トラフィックが支配的な Netflix などのアプリに特に便利です。

例: コンテナ クエリを使用したコンポーネントの応答性

変換前:

/* Desktop versus Mobile
this only works if.sidebar is directly contained by a viewport-width element */
.sidebar {
    width: 300px;
}

@media (max-width: 768px) {
    .sidebar {
        width: 100%;
    }
}

変換後:

/* Responsive sidebar based on container,
.sidebar can be placed in any element of any width */
.container {
    container-type: inline-size;
}

.sidebar {
    width: 100%;
}

@container (min-width: 768px) {
    .sidebar {
        width: 300px;
    }
}

.sidebar はビューポートベースのメディアクエリに依存するのではなく、コンテナサイズに応答するようになり、ビューポートまたは親コンテナのサイズを把握しなくても、動的レイアウトにより自然に適応できるようになりました。

3. レイアウト管理における JavaScript の依存関係の軽減

コンテナ クエリが登場する前は、Netflix を含む多くのチームが動的レイアウトに JavaScript に依存していました。ウィンドウ サイズをクエリすると、JavaScript によってレイアウト変更がトリガーされ、複雑さとバグの発生の可能性が高まります。コンテナクエリを使用すると、CSS がコンテナサイズに基づいてレイアウトのレスポンシブ性を処理できるため、この必要がなくなります。

例: JavaScript ベースのレイアウト ロジックを削除する

変換前:

const cardContainer = document.querySelector('.card-container');
const cards = cardContainer.children;

function adjustLayout() {
    if (cardContainer.offsetWidth > 900) {
        cards.forEach(card => card.style.width = '33.33%');
    } else if (cardContainer.offsetWidth > 600) {
        cards.forEach(card => card.style.width = '50%');
    } else {
        cards.forEach(card => card.style.width = '100%');
    }
}

window.addEventListener('resize', adjustLayout);
adjustLayout();

変換後:

.card-container {
    container-type: inline-size;
}

.card {
    width: 100%;
}

@container (min-width: 600px) {
    .card {
        width: 50%;
    }
}

@container (min-width: 900px) {
    .card {
        width: 33.33%;
    }
}

このアプローチでは、必要な JavaScript の量を削減できるだけでなく、ランタイム計算を回避することでパフォーマンスも向上します。

4. コードが少なく、バグが少ない

Netflix チームは、コンテナクエリを使用するとコード行数が減り、レイアウト関連のバグが減ることを発見しました。レイアウト ロジックを JavaScript から CSS に移動し、複雑なメディアクエリの必要性を排除することで、デベロッパーはメンテナンス性に優れたコードを記述できます。

例: レイアウト コードを削減する

Netflix チームは、コンテナ クエリを導入した後、CSS コードが大幅に削減されたことを確認しました(特定のコンポーネントでは最大 30% 削減)。同時に、子コンポーネントを制御するロジックを削除することで、複雑で競合が発生しやすい多くのメディアクエリを簡素化し、関心の分離をより高度に実現できました。これにより、開発がスピードアップするだけでなく、障害が発生する可能性のあるポイントが最小限に抑えられ、バグが減ります。

変換前:

/* Before with complex media queries */
.card {
    width: 100%;
}

@media (min-width: 600px) {
    .card {
        width: 50%;
    }
}

@media (min-width: 900px) {
    .card {
        width: 33.33%;
    }
}

変更後

.container {
    container-type: inline-size;
}

.card {
    width: 100%;
}

@container (min-width: 600px) {
    .card {
        width: 50%;
    }
}

@container (min-width: 900px) {
    .card {
        width: 33.33%;
    }
}

5. デベロッパー エクスペリエンスの向上

bq。「この機能によって、生活が 100 倍楽になりました」

コンテナクエリの最も過小評価されているメリットの一つは、デベロッパー エクスペリエンスの向上です。CSS の動作をより直感的でコンポーネント重視のものにすることで、デベロッパーは、考えられるあらゆるレイアウト シナリオでコンポーネントがどのように動作するかを気にすることなく、再利用可能な柔軟なコンポーネントの構築に集中できます。

Netflix チームのメンバーの一人は、「これが CSS が最初から機能する方法だったはずだ」と述べています。

6. ポリフィル フォールバック

コンテナクエリは現在、すべての主要ブラウザで使用されていますが、以前のバージョンのブラウザが引き続き使用されていることに懸念が寄せられています。フォールバックは非常に重要です。Netflix チームは、ウェブ コミュニティのコントリビューターが作成したこの JavaScript ポリフィルを使用しています。特徴検出を使用すると、実装は簡単です。

if (! CSS.supports("container-type:size")) {
  /*use polyfill from
  https://www.npmjs.com/package/container-query-polyfill */
 }

まとめ

コンテナクエリは CSS の大きな進歩であり、デベロッパーがサイトのさまざまな部分で再利用できる柔軟でレスポンシブなコンポーネントを簡単に構築できるようになります。レイアウトに JavaScript の依存を減らし、複雑なメディアクエリを排除し、開発を高速化することで、パフォーマンスとメンテナンスの両面で大きなメリットが得られます。現在、ユースケースのほとんどは Netflix の Tudum ページにあり、Netflix の他の部分でコンテナ クエリを使用する予定があります。Netflix チームは、コンテナ クエリをデベロッパー ツールボックスの優れたツールと見なしています。コンテナ クエリの使用は、その柔軟性とパワーをデベロッパーが取り入れていくにつれて拡大するでしょう。既存のコンポーネントの改造やまったく新しいコンポーネントの設計にかかわらず、コンテナクエリはレスポンシブ デザインのよりシンプルでクリーンな方法を提供します。

まだ試していない場合は、コンテナクエリを試してみてください。予想していなかった方法でワークフローが簡素化される可能性があります。