先日公開した記事「CSS コンテナクエリ考察」のなかで、コンテナクエリの課題のひとつとして検証方法が確立していない点を取り上げました。
この問題を緩和させるために、対象要素をリサイズ可能にしてコンテナクエリ(@container)のスタイルを検証できる Bookmarklet「cq-resizer」を作成しました。
使用方法
見出し「使用方法」以下の手順で Bookmarklet を登録します。
- このページなど、適当なウェブページをブックマーク
- ブックマークを編集して、URL の値を以下の GitHub Gist のコードに差し替え
- 任意でブックマーク名を変更
https://gist.github.com/griponminds/506f75ae0aa7d12e72a85571727a635f
以下は、コンテナクエリを指定したデモです。登録したブックマークを選択して Bookmarklet を実行してみてください。
デベロッパーツールのコンソールに「cq-resizer.js」のコード全体をペーストしても実行可能です。
Bookmarklet を実行すると、以下のように 5 つの基準コンテナ(container-type
プロパティが指定されている要素)の右下にリサイズハンドルが追加され、リサイズが可能になります。加えて、画面の右上にはインフォパネルが追加されます。
インフォパネル
見出し「インフォパネル」インフォパネルは以下の要素で構成されています。
項目 | 内容 |
---|---|
タイトル | Bookmarklet の名称 |
Close ボタン | インフォパネルを閉じるボタン |
No. | 通し番号 |
セレクタ名 | 基準コンテナの class もしくはタグ名 |
横幅 | 基準コンテナの横幅(px) |
チェックボックス | リサイズのオン・オフ |
タイトルをドラッグすることで、インフォパネルを移動できます。Close ボタンでインフォパネルを閉じると移動した位置はリセットされます。
セレクタ名にはアンカーリンクが付与されており、選択すると該当の基準コンテナの垂直位置までスクロール移動します。なお、セレクタ名は class
属性の値が表示されますが、class
の指定がない場合には HTML の要素名を表示します。
横幅のフィールド(<input type="number">
)と基準コンテナの幅は連動しているので、フィールドの数値から基準コンテナの横幅を変更することもできます。
チェックボックスでは、基準コンテナのリサイズ指定のオン・オフを切り替えることができます。
既知の問題
見出し「既知の問題」現時点では以下の問題を認識しています。
リサイズハンドルの表示
見出し「リサイズハンドルの表示」Safari において、基準コンテナの上に背景を持つ子孫要素が重なると、リサイズハンドルが隠れてしまうことがあるようです。
なお、Google Chrome や Firefox のデバイスモード下では、リサイズハンドルが小さく表示されますが、かろうじてリサイズすることはできるようです。
Flexbox
見出し「Flexbox」基準コンテナが flex アイテムとして他の要素と並んでいる状態だと、リサイズハンドルでの操作や、フィールドの数値からスムーズにサイズを変更できないことがあります。
スタイルの競合
見出し「スタイルの競合」基準コンテナに style
属性を追加するため、すでに style
属性が付与されている場合には、スタイルが競合して動作や表示に影響を及ぼす可能性があります。
対象外
見出し「対象外」<iframe>
の内部(「CodePen」のコードなど)や、ShadowDOM の内部で使用されている基準コンテナは対象外です。
実装内容
見出し「実装内容」ここからは、Bookmarklet の実装内容の一部を紹介します。
基準コンテナへのスタイル追加
見出し「基準コンテナへのスタイル追加」まず、ページ内のすべての HTML 要素のなかで、CSS の container-type
プロパティが指定されている要素(基準コンテナ)を検索し、見つからない場合にはメッセージを表示します。
次に、基準コンテナのなかで、親子関係にある要素で、水平・垂直位置が同じ場合には子孫要素を除外しています。これは、リサイズハンドルが重なることで操作が複雑になるのを避けたいのと、親要素側でリサイズできれば十分だというのが理由です1。
続いて、このフィルタリングされた基準コンテナにスタイルを追加します。指定されている container-type
の値に応じて、以下のようにスタイルを振り分けています。
inline-size
の場合は、resize: horizontal
とoverflow-x: auto
を追加size
の場合は、resize: both
とoverflow: auto
を追加
これにより、基準コンテナの右下にリサイズハンドルが表示され、ドラッグしてサイズを変更することができるようになります。
さらに、インフォパネル内のセレクタ名に付与されているリンクの遷移先となるアンカー要素を生成し、不可視化したうえで、position: absolute
で配置しています。
Shadow DOM
見出し「Shadow DOM」インフォパネルは Shadow DOM として実装しています。
基本的には外側の CSS の影響は受けませんが、一部のプロパティは継承されるため、以下の指定で初期化しています。
:host {
all: initial;
}
ただ、この指定をした状態でも、font-size
や line-height
など、Shadow ツリーの外側のスタイルが継承されることがあるようでした。
もちろん、Shadow ツリー内部の <style>
で、以下のように全称セレクタを指定すれば継承されなくなるのですが、フォーム要素のデフォルトのスタイルも無くなってしまうのと、影響範囲が大きすぎるので採用しませんでした。
/* Shadow ツリー内部のスタイル */
* {
all: initial;
}
この点は、まだ理解が足りていないので、より良い方法がないかを探っていきたいです。
2024/01/15 追記
Shadow DOM が先祖要素のスタイルを継承することについて、以下の記事で説明しています。
おわりに
見出し「おわりに」今回作成した Bookmarklet は、当初は基準コンテナをリサイズできる機能だけを想定しており、プライベートでの使用しか考えていなかったのですが、コードを書いていくうちに機能が充実していったので、せっかくなので公開することにしました。
まだ、ほとんど自分のサイトでしか試せていないので、使っていくうちに予測していない不具合が見つかるかもしれません。コードは今後も適宜調整していきますが、もしお気づきの点がございましたらお知らせください。
脚注
-
親子要素がそれぞれ
inline-size
とsize
の場合にも子孫要素が除外されますが、まれなケースだと考えられるので、ひとまず対応は保留です。 ↩