2023年からすべてのブラウザで使用できるようになったコンテナクエリ(@container)。私はなかなか使う機会がありませんでした。そろそろ業務に取り入れたいと思い、今回はコンテナクエリの使い方について調べてみることにしました。
使い方はメディアクエリ(@media)によく似ています。例えばメディアクエリで「@media (max-width: 760px)」を指定した場合、画面全体の横幅が760px以下のときにスタイルが適用されます。
対してコンテナクエリでは、「@container (max-width: 500px)」を指定した場合、コンテナの横幅が500px以下のときにスタイルが適用されます。
@container (max-width: 500px){
.hoge{
color: aqua;
}
}
上記のコードであれば、コンテナの横幅が500px以下のとき、子要素にあたる「.hoge」の文字色がaquaになります。
コンテナクエリを使用する際は、コンテナを基準とした単位を使うことができます。
※インラインサイズ・ブロックサイズとは?
スタイルを単純な上下左右で指定するのではなく、インライン軸とブロック軸の概念に従って指定します。
インライン軸とは、文字の流れる方向を基準とした軸です。表示言語が日本語や英語の場合、文字は左から右へ流れるので、インライン軸は左から右になります。アラビア語であれば右から左なので、インライン軸は逆になります。また、日本語の縦書き文章においては、インライン軸は上から下になります。
ブロック軸は、文章を書いたときに段落が追加されていく方向になります。横書きの文章では、段落は下方向にどんどん追加されていきます。縦書きの文章では左側に増えていきます。この方向がブロック軸の方向です。
よって、例えば横書きの日本語におけるインラインサイズとは横方向の大きさを指し、ブロックサイズとは縦方向の大きさを指します。
コンテナを定義するには、コンテナにしたい要素に「container-type」プロパティを追加します。@containerで指定された要素から見て、もっとも近いcontainer-typeが指定された祖先をコンテナとみなします。
<div class="card">
<h2 class="card__ttl">card01</h2>
<p class="card__txt">piyopiyopiyo</p>
</div>
@container (max-width: 500px){
.card__txt{
font-size: max(5cqw, 14px);
}
}
.card{
padding: 24px;
border: 1px solid #fff;
border-radius: 10px;
box-sizing: border-box;
container-type: inline-size;
}
この場合、「.card__txt」から見てもっとも近くて、「container-type」が指定された要素である「.card」がコンテナとみなされます。
container-typeに指定できる値は三種類あります。
inline-sizeではインライン軸を基準とし、sizeではインライン軸とブロック軸の両方を基準とします。normalはデフォルト値です。クエリはmax-width・min-widthで指定することが多いので、基本的にはinline-sizeを使うことになります。
「container-name」プロパティを指定することで、コンテナに名前を付けることができます。名前を付けることで、コンテナクエリを使用するとき、対象となるコンテナを明示的に示すことができます。
@container card-container (max-width: 500px){
.card__txt{
font-size: max(5cqw, 14px);
}
}
.card{
padding: 24px;
border: 1px solid #fff;
border-radius: 10px;
box-sizing: border-box;
container-name: card-container;
container-type: inline-size;
}
container-nameとcontainer-typeは、ショートハンドで書くことも可能です。
.card{
container: card-container / inline-size;
}
それでは、ここまで調べたことを元にデモを作成します。横幅に応じて見た目が変化するため、別ウィンドウで開いた方が分かりやすいと思います。
コンテナクエリを見ていきましょう。
@container (min-width: 400px){
.card{
display: flex;
flex-wrap: wrap;
}
.card__txt{
flex: 1;
margin-right: 16px;
}
}
@container card-container (max-width: 500px){
.card__txt{
font-size: max(5cqw, 14px);
}
}
コンテナが400px以上のとき、.cardにflexが適用されることによって「More」ボタンが右に配置されます。では、この.cardと.card_txtのコンテナはどの要素でしょうか。
まずcard01~03について、container-typeが指定されている一番近い祖先は「.articleGrid__item」です。ので、これらのカードについては「.articleGrid__item」の大きさによってボタンの配置が変化します。
一方、card04にとって一番近い祖先は「.sec」となり、「.sec」の大きさに依存してボタンの位置が変わります。
↑card03のコンテナ「.articleGrid__item」は幅400px未満、card04のコンテナ「.sec」は幅400px以上の状態。
また、.card__ttlのfont-sizeは、コンテナの横幅に依存しています。デモを見ると、画面の横幅を十分広げた時に、card01とcard04がそれぞれのコンテナの大きさに合わせて文字サイズを変化させていることがわかります。
.card{
//~略~
&__ttl{
width: 100%;
font-size: max(8cqw, 18px);
}
}
このように、コンテナクエリを指定した要素は、現在のコンテナによって異なるスタイルを取ることが可能です。
今回はコンテナクエリについて調べていきました。うまく使えばコンポーネント化が捗りそうですね。
個人的には、一か所に纏めて書けるのも見通しが良くていいなぁと思いました。