コンテナクエリについて学習しました。これは、祖先要素を基準にしてスタイルを定義できるCSSの機能です。
例えば、祖先要素の「幅が500px以下の時」や「イタリック体の時」にその子孫要素のスタイルを自由に定義できます。
コンテナサイズクエリ(container size queries)とコンテナスタイルクエリ(container style queries)の2種類があります。
今回はコンテナサイズクエリについて書きます。
基本的な書き方
index.htmlを用意しました。これにコンテナクエリを書いていきます。
<div class="parent">
<div class="child">子要素だよ〜🍓</div>
</div>
コンテナコンテキストを生成
レスポンシブ対応したい要素の祖先要素にcontainer-type
またはcontainer
プロパティを指定します。指定された要素は、基準コンテナになり「コンテナコンテキスト(container context)」と呼ばれます。
上記index.htmlの場合、class属性parent
を持つdiv
要素に指定します↓
.parent {
container-type:inline-size;
//または、container:parent / inline-size;
}
@containerを使って条件を指定
基準コンテナのサイズがどうなったらスタイルを適用するのかを定義します。
例えば、「基準コンテナの幅が500px未満の時」という条件は以下のように書きます↓
.parent {
container-type:inline-size;
//またはcontainer:parent / inline-size;
max-width:400px;
}
@container (width < 500px) {
.child {
background-color:red;
}
}
コンテナクエリの具体的な使用例を知りたい方はこちら↓
そもそもなぜコンテナクエリが誕生したのか知りたい方はこちら↓
使用できる記述子について
記述子とは、@container(条件) {...}
の「条件」の部分です。
今回取り扱う記述子は以下です↓
width
height
inline-size
block-size
aspect-ratio
orientation
他にも記述子はあります。CSS変数や将来追加されるかもしれない状態クエリです。
詳しくは以下の記事をご覧ください↓
inline-size
writing-mode
の値によって、width
またはheight
プロパティのどちらかに対応します。
horizontal-〇〇
の場合→width
に対応vertical-〇〇
の場合→height
に対応
writing-mode
の初期値はhorizontal-tb
のため、inline-size
の初期対応プロパティはwidth
になります。
inline-size
がwidth
に対応する際、block-size
はheight
に対応します。
反対にinline-size
がheight
に対応する際、block-size
はwidth
に対応します。
細かく分けると以下が指定できます↓
inline-size
max-inline-size
min-inline-size
writing-mode
についてはこちら↓
block-size
writing-mode
の値によって、width
またはheight
プロパティのどちらかに対応します。
horizontal-〇〇
の場合→height
に対応vertical-〇〇
の場合→width
に対応
writing-mode
の初期値はhorizontal-tb
のため、block-size
の初期対応プロパティはheight
になります。
細かく分けると以下が指定できます↓
block-size
max-block-size
min-block-size
aspect-ratio
コンテナコンテキストの幅と高さの比(アスペクト比)に基づいてスタイルを定義できます。
比とは「ある数が、もう一方の数のどれだけに当たるかを表した数」のことです。
ある要素の幅800px、高さ400pxの場合、幅と高さの比は「800:400」→「2:1」になります。幅は高さの2倍であり、高さは幅の0.5倍となります。
aspect-ratio
の分子はwidth
、分母はheight
です。
「aspect-ratio: width / height
」
スラッシュ( /
)とheight
が省略された場合、height
の規定値は1
です。
細かく分けると以下が指定できます↓
aspect-ratio
max-aspect-ratio
min-aspect-ratio
コード例です↓
@container hoge (aspect-ratio: 3/2) {
// 3 / 2 = 1.5 親コンテナのアスペクト比が1.5と等しい時
.hogehoge {
//style
}
}
@container hoge (max-aspect-ratio: 3/2) {
// 親コンテナのアスペクト比が1.5以下の時
.hogehoge {
//style
}
}
@container hoge (min-aspect-ratio: 2) {
// 2 / 1 = 2 親コンテナのアスペクト比が2以上の時
.hogehoge {
//style
}
}
orientation
コンテナコンテキストが縦長または横長に基づいてスタイルを定義します。
以下が指定できます↓
portrait
(縦長。幅より高さの値が大きい。)landscape
(横長。高さより幅の値が大きい。)
各プロパティについて解説
コンテナクエリ周りの主なプロパティについて解説します。
containerプロパティ
container-name
とcontainer-type
を一括で指定できるプロパティです。
スラッシュ( / )で値を区切れます。
以下、構文です↓
.base-container {
container:[container-name] / [container-type];
}
container-typeプロパティ
コンテナクエリで使用されるコンテナの種類を指定します。
コンテナの種類には以下の通りです↓
normal
inline-size
size
container-type:normal;
初期値です。コンテナサイズクエリのクエリコンテナではないですが、コンテナスタイルクエリのクエリコンテナとして残ります。
つまり、コンテナサイズクエリではcontainer-type
プロパティを指定する必要がありますが、コンテナスタイルクエリでは指定しなくて良いです。
コンテナスタイルクエリについてはこちら↓
container-type:inline-size;
コンテナコンテキストの幅または高さのどちらか一方のみの変更を監視して、@container
の条件に一致したとき、レスポンシブ対応したい要素のスタイルが適用されます。
条件として使える記述子には以下があります↓
width
height
inline-size
block-size
aspect-ratio
とorientation
は幅と高さ両方の情報がいるので、inline-size
では使えません。
テキストだと分かりにくいと思うのでコード例を用意しました↓
See the Pen container-type=inline-size by ユイト (@mikiprogram) on CodePen.
container-type
の値を変えてみると違いが分かりそうです。
上記の解説は全く僕の主観の解釈のため、間違っている可能性が高いです。W3Cの正確な解説を引用しておきます↓
Establishes a query container for container size queries on the container’s own inline axis. Applies layout containment, style containment, and inline-size containment to the principal box.
4.1. Creating Query Containers: the container-type property
container-type:size;
コンテナコンテキストの幅と高さ両方の変更を監視して、@container
の条件に一致したときレスポンシブ対応したい要素のスタイルが適用されます。
条件として使える記述子には以下があります↓
container-type:inline-size;
で使える記述子全てaspect-ratio
orientation
こちらもコード例を用意しました↓
See the Pen container-type=size by ユイト (@mikiprogram) on CodePen.
こちらの解説も正確性は無いのでW3Cの解説を引用します↓
Establishes a query container for container size queries on both the inline and block axis. Applies layout containment, style containment, and size containment to the principal box.
4.1. Creating Query Containers: the container-type property
container-nameプロパティ(省略可能)
コンテナコンテキストに名前をつけることができます。
複数のコンテナコンテキストを使うときに名前をつけて区別することができます。
名前をつける際のルールを抜粋します↓
- 名前は引用符で囲まない
- スペース区切りで複数の名前を指定できる
名前を引用符で囲まない
🙆OK例→container-name:layout;
🙅♂️NG例→container-name:"layout";
スペース区切りで複数の名前を指定できる
例→container-name:width height;
用途がよく理解できていないので、MDNのサンプルコードを載せます↓
.base-container {
container-type: inline-size;
container-name: meta card;
}
@container meta (max-width: 500px) {
p {
visibility: hidden;
}
}
@container card (max-height: 200px) {
h2 {
font-size: 1.5em;
}
}
使える単位
クエリコンテナ(基準にした要素)ベースの単位が使えるようになりました↓
cqw
: クエリコンテナのwidth
の1%cqh
: クエリコンテナのheight
の1%cqi
: クエリコンテナのinline-size
の1%cqb
: クエリコンテナのblock-size
の1%cqmin
:cqi
とcqb
の値を比べて、どちらか小さい方cqmax
:cqi
とcqb
の値を比べて、どちらか大きい方
使い方
「クエリコンテナの幅が1000px」 で子孫要素に60cqw
を指定した場合は以下のようになります。
<style>
* {
box-sizing: border-box;
}
.container {
container-type: inline-size;
border: 1px solid;
height: 300px;
max-width: 1000px;
}
.inner {
padding: 1rem;
margin: 1rem;
border: 1px solid;
width: 60cqw;
}
</style>
<div class="container">
1000px
<div class="inner">60cqw</div>
</div>
コンテナコンテキストを生成して、その子孫要素にクエリコンテナベースの単位を使います。
コンテナコンテキストを生成せず、クエリコンテナベースの単位を使うと、スモールビューポートサイズ(Small Viewport Size)の大きさになります↓
For each element, container query length units are evaluated as container size queries on the relevant axis (or axes) described by the unit. The query container for each axis is the nearest ancestor container that accepts container size queries on that axis. If no eligible query container is available, then use the small viewport size for that axis.
6. Container Relative Lengths: the cqw, cqh, cqi, cqb, cqmin, cqmax units
上記index.htmlの.container
にcontainer-type
を指定しなかった場合、.inner
のwidth:60cqw;
は画面幅基準になります。画面幅が2000pxの時、.inner
のwidth
は「2000px * 0.6 = 1200px
」になります。
スモールビューポートサイズについてはこちら↓
%との違い
「%」とは、親要素のサイズが基準の単位です。
先ほどのindex.htmlでは、%とクエリコンテナベースの単位の違いが分かりにくいかもしれません。
以下を見てください↓
See the Pen Untitled by ユイト (@mikiprogram) on CodePen.
width:60%;
を指定した.percent
の値は、親要素である.container
の幅基準で値が決まっています。
一方、width:60cqw;
を指定した.cqw
の値はクエリコンテナである.base-container
の幅基準で値が決まっています。
%は親要素のみが基準となりますが、クエリコンテナベースの単位は親要素を含む祖先要素を基準にできます。
注意点
擬似要素はコンテナコンテキストにできない
::before
や::after
などの擬似要素は@container{...}
内でスタイルを定義することは可能ですが、コンテナコンテキストにすることはできません。
🙆OK例↓
<style>
#container {
width: 100px;
container-type: inline-size;
}
@container (inline-size < 150px) {
#inner::before {
content: "BEFORE";
}
}
</style>
<div id=container>
<span id=inner></span>
</div>
🙅NG例↓
<style>
#container::before {
display:block;
content:"";
width: 100px;
height:100px;
container-type: inline-size;
}
@container (inline-size < 150px) {
#inner {
background-color:red; /*背景色は赤色にならない*/
}
}
</style>
<div id=container>
<span id=inner></span>
</div>
NG.htmlのHTML構造↓
<div id="container">
#container::before
<span id="inner"></span>
</div>
#container::before
は#inner
と兄弟の関係のため祖先ではありません。そのため、コンテナコンテキストになりません。擬似要素がレスポンシブ対応したい要素の祖先になることがないのかもしれません?
親要素以外もコンテナコンテキストにできる
親要素のみコンテナコンテキストできるわけではありません。
レスポンシブ対応したい要素から見て祖先に当たる要素にcontainer-type
を指定するとそこがコンテナコンテキストとなります↓
<style>
.ancestor {
container-type: inline-size;
width: 100px;
}
.parent {
width: 160px;
}
@container (inline-size < 150px) {
.inner::before {
content: "BEFORE";
}
}
</style>
<div class="ancestor">
<div class="parent">
<span class="inner"></span>
</div>
</div>
最も近い祖先要素がコンテナコンテキストとなる
複数の祖先要素にcontainer-type
が指定されている場合を考えます。
この場合、レスポンシブ対応したい要素から見て最も近い祖先要素がコンテナコンテキストになります。
<style>
.container {
container-type: inline-size;
}
.ancestor {
width: 100px;
}
.parent {
width: 160px;
}
@container (inline-size < 150px) {
/*基準コンテナの幅が150px未満の時*/
.inner::before {
content: "BEFORE";
}
}
</style>
<div class="container ancestor">
<div class="container parent">
<span class="inner"></span>
</div>
</div>
上記の場合、.inner::before
の content: "BEFORE";
は表示されません。つまり、コンテナコンテキストはclass属性container
とparent
を持つdiv
要素です。
position:fixed;の基準位置と固定表示
position:fixed;
を指定したときのtop
やleft
などの値は、常にビューポートが基準位置だと思っていました。
しかし、position:fixed
を指定する要素から見て先祖要素のcontainer-type
がnormal
以外の場合、基準位置が変わることを学びました↓
また、固定表示して追従されなくなるので注意が必要です↓
Safariでhtml要素のcontainer-typeが働かない
Safariでhtml要素にcontainer-typeを指定しても、うまくいかないようです↓
各ブラウザの対応状況
2023年4月10日時点で、主要なブラウザはサポートされています↓
参考サイト
まとめ
コンテナクエリの基本的なことについては理解できてよかったです。具体的なデモを見ていつでも使えるようにこれから勉強します。
コンテクエリ周りの単位やスタイルクエリについても勉強します。