`<wa-tree>` のサイズをフォントサイズ連動に変更し、インデントガイドの位置ずれも修正

shoelace-style/webawesome

<wa-tree> コンポーネントの内部寸法がすべて font-size に連動するようになり、ツリー全体のサイズ変更が容易になりました。あわせて、インデントガイドの位置ずれも修正されています。

背景

#2147 で指摘されていたとおり、従来の <wa-tree> はフォントサイズが内部でハードコードされており、ツリー全体をリサイズすることが困難でした。ラベル・チェックボックス・展開ボタンなどの内部要素が固定の --wa-font-size-m トークンや絶対的なスペーストークンに依存していたため、外部から font-size を指定しても寸法が追従しませんでした。

また、インデントガイドを実装するために font-size: 0 トリックが使われており、これが問題の根本にもなっていました。このトリックを除去するにあたってインデントガイドの描画ロジック全体を見直した結果、ガイドが中央からずれていたバグも発見・修正されています。

技術的な変更

font-size: 0 トリックの廃止により、インデント量の算出ロジックが刷新されました。これが今回の変更の中核です。

tree.styles.tsfont-size: 0 の削除と --indent-size のデフォルト値変更

変更前は :hostfont-size: 0 を設定し、EMの相対計算でルートのインデントをゼロにしていました。

変更前:

:host {
  --indent-size: var(--wa-space-l);
  display: block;

  /*
   * Tree item indentation uses the "em" unit to increment its width on each level,
   * so setting the font size to zero here removes the indentation for all the nodes
   * on the first level.
   */
  font-size: 0;
}

変更後:

:host {
  --indent-guide-offset: 0;
  --indent-guide-style: solid;
  --indent-guide-width: 0;
  --indent-size: 2em;
  display: block;
}

--indent-size のデフォルト値が var(--wa-space-l)(絶対値トークン)から 2em(相対値)に変わり、ツリー自体の font-size に連動するようになりました。

tree-item.ts — 深さをJavaScriptで計算してCSS変数に注入

font-size: 0 が使えなくなったため、各アイテムのインデント幅をDOMのネスト深さから計算し、プライベートなCSS変数 --indent としてホスト要素に直接設定する updateIndentation() メソッドが追加されました。

/** Counts the nesting depth and sets the private --indent property on the host for indentation. */
private updateIndentation() {
  let depth = 0;
  let node = this.parentElement;
  while (node) {
    if (WaTreeItem.isTreeItem(node)) {
      depth++;
    }
    node = node.parentElement;
  }
  this.style.setProperty('--indent', `calc(${depth} * var(--indent-size, 2em))`);
}

このメソッドは connectedCallback から呼び出され、コンポーネントがDOMに接続された時点でインデントが確定します。深さは親要素を while ループで辿り、WaTreeItem のインスタンスをカウントすることで求めています。

tree-item.styles.ts — 固定値の相対値への置き換え

スタイル側でも固定値の参照が一掃されました。主な変更点は以下のとおりです:

  • .indentation の幅が 1em から var(--indent) に変更(JSで計算した深さを参照)
  • .checkbox / .labelfont-sizevar(--wa-font-size-m) から inherit に変更
  • .itemborder-inline-startsolid 3px transparent から solid 0.1875em transparent に変更(EM単位化)
  • アイコンの margin-inline-endvar(--wa-space-xs) から 0.5em に変更
  • .childrenfont-size: calc(1em + var(--indent-size, ...)) の行が削除(深さ計算をJSに移譲)

また、--indent はコンポーネントが制御するプライベート変数であることをコメントで明示するため、:host ブロックに --indent: 0px の初期値が追加されています。

設計判断

CSSによるEM相対計算からJavaScriptによる深さ計算への移行という方向性が選択されました。

旧実装は font-size: 0 を親要素に設定し、子要素のEM計算で自動的にインデントが積算される巧妙な手法でしたが、ツリー全体の font-size を外部から制御できないという制約がありました。新実装はDOMツリーを走査して深さを明示的に算出することで、この制約を取り除いています。副作用として、インデント計算が宣言的なCSSではなく命令的なJavaScriptに移ったため、動的なDOM操作後に updateIndentation() を呼ぶ責務がコンポーネント側に生まれています。

また、--indent-size のデフォルト値を 2em に固定したことで、font-size を変えるだけでツリー全体が比例してリサイズされます。カスタマイズの際も --indent-size を上書きすることで任意の幅を指定できるため、公開APIは変わっていません。

まとめ

font-size: 0 トリックを廃止し、インデント深さをJavaScriptで計算してCSS変数に注入する方式に切り替えることで、<wa-tree> はフォントサイズに完全に追従するコンポーネントになりました。内部の固定値をEM単位に統一したこの変更は、単なるバグ修正にとどまらず、コンポーネント設計における「CSSトリックの限界とJSによる補完」というトレードオフを示す好例です。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
a1c1dc08

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

「総論→各論→結論」の3部構成が明確に適用されています。特に、任意項目である「設計判断」セクションが含まれており、変更の背景にあるトレードオフを解説することで記事に深みを与えています。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きシンタックスハイライト(```言語:ファイルパス)や、Issue番号・PR番号のリンク記法が正しく使用されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

CSS変数、EM単位、DOMのライフサイクル(connectedCallback)といった専門用語を前提としており、対象読者であるエンジニアにとって適切かつ簡潔な記述となっています。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが要旨から始まり、各パラグラフもトピックセンテンスで始まる構成が徹底されています。1段落1トピックの原則も守られており、非常に読みやすいです。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事内で引用されているすべてのコードブロック(tree.styles.ts, tree-item.ts)およびスタイル変更の説明が、提供されたDiff情報と完全に一致しています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「`font-size: 0` トリック」「EM単位」「プライベートなCSS変数」など、PRやWeb開発の文脈で用いられる技術用語が正確かつ適切に使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

インデント計算ロジックの変更(CSSトリックからJSでの算出へ)に関する説明は、Diff内のコード変更と完全に整合しており、技術的に正確です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事内のすべての主張(フォントサイズ連動化、インデントガイドの位置ずれ修正など)は、PRのDescriptionやDiffから裏付けが取れており、ハルシネーションは見られません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号(#2160)、Issue番号(#2147)、コード内の数値(2em, 0.1875emなど)がすべて正確に記載されています。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事のタイトルは、PRの主題である「Tree sizing」と、Descriptionで言及されている「インデントガイドの修正」の両方を的確に要約しており、内容と一致しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

PR情報に含まれないバージョン情報やリリース予定など、外部の知識に基づく記述はなく、提供された情報源に忠実です。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

「従来の」「変更前」「新実装」といった時間関係を示す表現が、PRの文脈(Before/After)と一致しており、正確です。