ツールバーのオーバーフロー検出を `clientWidth` ベースに刷新

basecamp/lexxy

scrollWidth と独自計算に依存していたツールバーのオーバーフロー判定を、clientWidth / offsetWidth を使ったシンプルな実装に置き換えました。シングルパス設計は維持され、強制レイアウト(Forced Layout)の発生を防ぐ設計方針が引き継がれています。

背景

ツールバーのオーバーフロー検出は、表示領域に収まらないボタンを「オーバーフローメニュー」へ移動する仕組みの核心です。変更前の実装では、#isToolbarOverflowing() による事前チェックと #toolbarOverflowAmount() による溢れ幅の計算という2段階のアプローチが取られていました。これらは scrollWidth や独自の幅積算に依存していたため、コードパスが複雑化していました。

PR の説明によれば、clientWidthscrollWidth の比較でオーバーフローを判定し、各ボタンの幅取得には offsetWidth を直接使う方式に切り替えることで、この複雑さを解消しています。なお、ボタン移動のたびに幅を再計算すると強制レイアウトが発生するため、シングルパスで処理する設計は意図的に維持されています。

技術的な変更

#compactMenu() メソッドの責務が分割され、オーバーフロー幅の取得とボタン回収が独立したメソッドに切り出されました。

変更前:

#compactMenu() {
  if (!this.#isToolbarOverflowing()) return

  this.#overflow.style.display = "block"

  const overflowAmount = this.#toolbarOverflowAmount() + 1
  const buttons = this.#overflowButtons
  const overflowButtons = []
  let recoveredWidth = 0

  while (recoveredWidth < overflowAmount) {
    const button = buttons.pop()
    if (!button) break
    // ...
  }
}

変更後:

#compactMenu() {
  this.#showOverflowMenu()
  const overflowWidth = this.#getOverflowWidth()

  if (overflowWidth > 0) {
    this.#reclaimWidth(overflowWidth)
  }
}

#showOverflowMenu() {
  this.#overflowMenuButton.style.display = "block"
}

#reclaimWidth(overflowWidth) {
  const gap = this.#getToolbarGap()
  const buttons = this.#overflowableButtons
  const overflowButtons = []
  let recoveredWidth = 0

  while (recoveredWidth < overflowWidth && buttons.length) {
    const button = buttons.pop()
    if (!button) break
    // ...
  }
}

変更前は #isToolbarOverflowing() で事前チェックを行い、true の場合のみ処理を続行していました。変更後は常に #showOverflowMenu() でオーバーフローメニューボタンを表示した上で #getOverflowWidth() で溢れ幅を取得し、overflowWidth > 0 の場合のみ #reclaimWidth() を呼び出す構造になっています。

DOM要素の参照も整理されており、this.#overflowthis.#overflowMenuButton に、this.#overflowMenuthis.#overflowMenuDropdown に改名されています。また、ボタンのコレクションも #overflowButtons から #overflowableButtons へとリネームされ、意味がより明確になっています。

while ループの終了条件にも改善が加えられており、変更前の buttons.length チェックなしの実装から、recoveredWidth < overflowWidth && buttons.length という二重条件に変わっています。これにより、ボタンが枯渇した場合の pop() の失敗を if (!button) break に頼らずとも、ループ条件で安全に制御できるようになっています。

設計判断

シングルパス設計の維持が本PRで最も重要な設計判断です。PR説明に「forced layouts を防ぐためシングルパス設計を維持した」と明示されており、ボタン移動のたびに幅を再計算しないことが意図的なトレードオフとして選択されています。

オーバーフロー判定の方式として clientWidth vs scrollWidth の比較が採用された点も注目に値します。scrollWidth はスクロール可能なコンテンツ全体の幅を返すのに対し、clientWidth はパディングを含む表示領域の幅を返します。この2つを比較することで、コンテナに収まりきらないコンテンツの有無をシンプルに判定できます。また、各ボタンの幅取得に offsetWidth を使用することで、マージン・ボーダーを含む実際のレイアウト上の幅を正確に取得しています。

メソッドの細分化(#compactMenu#showOverflowMenu + #getOverflowWidth + #reclaimWidth)は、単一責任の原則に沿った整理であり、コードの削減(52行削除、30行追加)とともに、各ステップの意図をより明確にしています。

まとめ

ブラウザ標準の clientWidth / offsetWidth を活用することで、独自の幅計算ロジックを排除し、コードを大幅に簡素化しました。DOM 要素名の整理と合わせて可読性が向上しており、強制レイアウトを回避するシングルパス設計という核心的な制約を守りながら、実装の複雑さを下げることに成功しています。

記事メタデータ

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

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

品質レビュー結果

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

Review Criteria:

記事構成 ✓ PASS

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

リード文(総論)→背景・技術・設計(各論)→まとめ(結論)の3部構成が明確に守られており、記事の骨格が非常にしっかりしている。

カスタムMarkdown構文 ⚠ WARNING

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

ファイル名付きシンタックスハイライトは正しく使用されているが、GitHubのPRリンク記法がガイドラインの推奨形式([#1062])と異なっている([PR #1062])。

対象読者への適合性 ✓ PASS

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

「強制レイアウト」「シングルパス設計」といった専門用語を前提として解説しており、対象読者である専門知識を持つエンジニアに完全に適合している。

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

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

各セクションが総論→各論の構成で、かつ各段落がトピックセンテンスで始まるため、非常に高い可読性を実現している。1段落1トピックの原則も守られている。

Diff内容との照合 ✓ PASS

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

変更前後のコード引用はDiff内容を正確に反映しており、特にメソッド分割の様子が的確に表現されている。ファイルパスも正しい。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

clientWidth, offsetWidth, scrollWidth, 強制レイアウトなど、PRで言及されている技術用語を正確かつ適切な文脈で使用している。

説明の技術的正確性 ✓ PASS

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

clientWidthとscrollWidthの違いや、シングルパス設計を維持する理由(強制レイアウトの防止)など、技術的な説明が正確かつ論理的である。

事実の突合 ✓ PASS

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

記事内の主張はすべてPRのDescriptionやDiff内容から裏付けられている。特にコードの追加/削除行数(52行削除、30行追加)を正確に引用しており、ハルシネーションは見られない。

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

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

PR番号(#1062)やコードの追加/削除行数が正確に記載されている。

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

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

記事タイトル「ツールバーのオーバーフロー検出を `clientWidth` ベースに刷新」は、PRタイトル「Refactor overflow with clientWidths」の内容を的確に和訳・要約している。

外部知識の正確性 ✓ PASS

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

clientWidth/scrollWidthの一般的な説明が含まれているが、これはPRの文脈を理解するために必要不可欠な補足情報であり、PRに記載のない外部知識の捏造には当たらない。

時間表現の正確性 ✓ PASS

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

記事内にはPR情報と矛盾するような時間表現(「既に」「まもなく」など)は含まれていない。