先日公開した記事「CSS コンテナクエリ考察」のなかで、コンテナクエリの課題のひとつとして検証方法が確立していない点を取り上げました。

この問題を緩和させるために、対象要素をリサイズ可能にしてコンテナクエリ(@container)のスタイルを検証できる Bookmarklet「cq-resizer」を作成しました。

以下の手順で Bookmarklet を登録します。

  1. このページなど、適当なウェブページをブックマーク
  2. ブックマークを編集して、URL の値を以下の GitHub Gist のコードに差し替え
  3. 任意でブックマーク名を変更

以下は、コンテナクエリを指定したデモです。登録したブックマークを選択して Bookmarklet を実行してみてください。

デベロッパーツールのコンソールに「cq-resizer.js」のコード全体をペーストしても実行可能です。

Live Demo

LOREM

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

LOREM

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

LOREM

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

LOREM

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Bookmarklet を実行すると、以下のように 5 つの基準コンテナ(container-type プロパティが指定されている要素)の右下にリサイズハンドルが追加され、リサイズが可能になります。加えて、画面の右上にはインフォパネルが追加されます。

Bookmarklet を実行した状態のスクリーンショット。画面の右上にインフォパネル、基準コンテナにリサイズハンドルが追加される
Bookmarklet の JS を実行した状態

インフォパネルは以下の要素で構成されています。

インフォパネルのスクリーンショット。タイトル、Close ボタン、基準コンテナ、No.、セレクタ名、横幅、チェックボックスの項目が示されている
項目内容
タイトルBookmarklet の名称
Close ボタンインフォパネルを閉じるボタン
No.通し番号
セレクタ名基準コンテナの class もしくはタグ名
横幅基準コンテナの横幅(px)
チェックボックスリサイズのオン・オフ

タイトルをドラッグすることで、インフォパネルを移動できます。Close ボタンでインフォパネルを閉じると移動した位置はリセットされます。

セレクタ名にはアンカーリンクが付与されており、選択すると該当の基準コンテナの垂直位置までスクロール移動します。なお、セレクタ名は class 属性の値が表示されますが、class の指定がない場合には HTML の要素名を表示します。

横幅のフィールド(<input type="number">)と基準コンテナの幅は連動しているので、フィールドの数値から基準コンテナの横幅を変更することもできます。

チェックボックスでは、基準コンテナのリサイズ指定のオン・オフを切り替えることができます。

現時点では以下の問題を認識しています。

リサイズハンドルの表示

見出し「リサイズハンドルの表示」

Safari において、基準コンテナの上に背景を持つ子孫要素が重なると、リサイズハンドルが隠れてしまうことがあるようです。

なお、Google Chrome や Firefox のデバイスモード下では、リサイズハンドルが小さく表示されますが、かろうじてリサイズすることはできるようです。

基準コンテナが flex アイテムとして他の要素と並んでいる状態だと、リサイズハンドルでの操作や、フィールドの数値からスムーズにサイズを変更できないことがあります。

基準コンテナに style 属性を追加するため、すでに style 属性が付与されている場合には、スタイルが競合して動作や表示に影響を及ぼす可能性があります。

<iframe> の内部(「CodePen」のコードなど)や、ShadowDOM の内部で使用されている基準コンテナは対象外です。

ここからは、Bookmarklet の実装内容の一部を紹介します。

基準コンテナへのスタイル追加

見出し「基準コンテナへのスタイル追加」

まず、ページ内のすべての HTML 要素のなかで、CSS の container-type プロパティが指定されている要素(基準コンテナ)を検索し、見つからない場合にはメッセージを表示します。

次に、基準コンテナのなかで、親子関係にある要素で、水平・垂直位置が同じ場合には子孫要素を除外しています。これは、リサイズハンドルが重なることで操作が複雑になるのを避けたいのと、親要素側でリサイズできれば十分だというのが理由です1

続いて、このフィルタリングされた基準コンテナにスタイルを追加します。指定されている container-type の値に応じて、以下のようにスタイルを振り分けています。

  • inline-size の場合は、resize: horizontaloverflow-x: auto を追加
  • size の場合は、resize: bothoverflow: auto を追加

これにより、基準コンテナの右下にリサイズハンドルが表示され、ドラッグしてサイズを変更することができるようになります。

さらに、インフォパネル内のセレクタ名に付与されているリンクの遷移先となるアンカー要素を生成し、不可視化したうえで、position: absolute で配置しています。

インフォパネルは Shadow DOM として実装しています。

基本的には外側の CSS の影響は受けませんが、一部のプロパティは継承されるため、以下の指定で初期化しています。

:host {
  all: initial;
}

ただ、この指定をした状態でも、font-sizeline-height など、Shadow ツリーの外側のスタイルが継承されることがあるようでした。

もちろん、Shadow ツリー内部の <style> で、以下のように全称セレクタを指定すれば継承されなくなるのですが、フォーム要素のデフォルトのスタイルも無くなってしまうのと、影響範囲が大きすぎるので採用しませんでした。

/* Shadow ツリー内部のスタイル */
* {
  all: initial;
}

この点は、まだ理解が足りていないので、より良い方法がないかを探っていきたいです。

2024/01/15 追記

Shadow DOM が先祖要素のスタイルを継承することについて、以下の記事で説明しています。

今回作成した Bookmarklet は、当初は基準コンテナをリサイズできる機能だけを想定しており、プライベートでの使用しか考えていなかったのですが、コードを書いていくうちに機能が充実していったので、せっかくなので公開することにしました。

まだ、ほとんど自分のサイトでしか試せていないので、使っていくうちに予測していない不具合が見つかるかもしれません。コードは今後も適宜調整していきますが、もしお気づきの点がございましたらお知らせください。

脚注

  1. 親子要素がそれぞれ inline-sizesize の場合にも子孫要素が除外されますが、まれなケースだと考えられるので、ひとまず対応は保留です。