zudo-css-wisdom

Type to search...

to open search from anywhere

長い URL とパスの折り返し

作成2026年4月23日更新2026年4月24日Takeshi Takatsudo

長い URL・ファイルパス・パッケージ識別子を、本文(prose)やコードを壊さずに区切り文字を意識した位置で折り返す方法。

問題

サイドバー、テーブル、チャットバブル、コールアウトボックスなどの幅の狭いコンテナには、ブラウザにとって折り返し位置が判断できないような長い一塊のトークンが日常的に流し込まれます。

@scope/org-name/packages/feature-module/src/components/widget.tsx
https://example.com/docs/guide/section?utm_source=newsletter&utm_medium=email&utm_campaign=launch
C:\Users\Example\AppData\Local\Temp\build-artifact-2026-04-24.log

ブラウザはデフォルトでこれらをすべて1つの単語として扱います。トークンはコンテナの端を突き破り、レイアウト全体に横スクロールバーを発生させたり、隣接する列にはみ出したりします。AIエージェントは word-break: break-alloverflow-wrap: anywhere に飛びついて修正を投入し、1週間後にバグ報告を受け取ります。段落という段落が単語の途中でランダムに折り返されるようになり、本文が読めなくなった、というものです。

本当の問題は、ブラウザがどのトークンがURLに似ていて、どのトークンが本文なのかを知らないということです。一律のルールは幅の狭いコンテナの問題を解決する代わりに、ページ上の他のすべてを犠牲にします。

ワンライナーでは不十分な理由

これらのプロパティにはそれぞれ用途がありますが、汎用的な解決策になるものはありません。

プロパティ効果なぜ正解にならないか
word-break: break-all任意の2文字間、どこででも折り返す本文を単語の途中で粉々にし、区切り文字を無視し、ページの残りの部分を読めなくする
overflow-wrap: anywhere同じ効果だが、単語があふれる場合にのみ発動する依然として区切り文字を無視する。長い単語は /? ではなく任意の文字位置で折り返される
hyphens: auto辞書由来の位置にソフトハイフンを挿入するURLやパスには何もしない — 辞書の単語ではないため
word-break: break-wordChromeレガシーの非標準値。より積極的に折り返し、おおむね word-break: normaloverflow-wrap: anywhere の組み合わせに相当するoverflow-wrap: break-word の同義ではない。緊急時の折り返しの積極度は anywhere と同等で、同じく区切り文字を無視する。使わず、上記の標準プロパティを選ぶこと

https://example.com/docs/a/b/c のようなURLに対する正しい答えは、ほぼ常に「/ の後で折り返す」です。C:\Users\Example のようなパスに対する正しい答えは「\ の後で折り返す」です。上記のプロパティのどれもこのことを知りません。

<wbr> 注入戦略

<wbr>word break opportunity 要素です。ブラウザに「ここで折り返す必要があるなら、ここは折り返していい場所だ」と伝えます。折り返しが必要ない場合、視覚的な出力はゼロです。

<wbr> の検証済みの性質:

  • グリフはレンダリングされない — 視覚的なスペースを取らない
  • スクリーンリーダーには読み上げられない — アクセシビリティのノイズにならない
  • クリップボードにコピーされない — ユーザーがURLを選択すると元の文字列がそのまま得られる
  • 選択中のキャレットは正常に動作する — 1文字ずれるようなことはない
  • SSR-safe — 単なるHTMLで、クライアントサイドのJavaScriptは不要

戦略はこうです。URLに似たトークンの中の区切り文字を見つけて、各区切り文字の <wbr> を注入します。レンダリングされた文字列はコピー時にバイト一致します。トークンは任意の文字位置ではなく、意味のある境界で折り返されます。

前:

<code>@scope/org-name/packages/feature-module/src/widget.tsx</code>

後:

<code>@scope/<wbr>org-name/<wbr>packages/<wbr>feature-module/<wbr>src/<wbr>widget.tsx</code>
D1 — 240px カラムでの4つの折り返し戦略

plain セルは水平方向にあふれます。break-all は任意の文字位置で折り返すため、URLは読めません。anywhere も似たように任意の位置で折り返しますが、オーバーフローが起こる場合のみ発動します。smart-break/?& の後できれいに折り返します。

D2 — 狭いサイドバーでの wbr 注入あり/なしの同じパス

区切り文字の集合

/ は第一の区切り文字です — URL、UNIXパス、パッケージ識別子をカバーします。検討に値する完全な集合は以下のとおりです。

区切り文字なぜこの後に注入するか
/第一選択。URLのパスセグメント、UNIXパス、スコープ付きパッケージ名
\Windowsパス (C:\Users\Example\...)
.ドット区切り識別子 (com.example.app)、ファイル名、ホスト名
-ケバブケース識別子、長いスラッグ
_スネークケース識別子
:ポート区切り (host:8080)、プロトコル (https:)、名前空間 (ns:value)
?クエリ文字列の境界
#フラグメントの境界
&クエリパラメータの区切り
=クエリのキー/値の境界

<wbr> は区切り文字の に注入し、前ではありません。区切り文字は前の行に残り、次のセグメントは次の行の先頭から始まります — 自然な読み順です。

isPathLike ゲート(本文ガード)

ドキュメント中のすべての /.- の後に <wbr> を注入すると、通常の本文が破壊されます。

  • and/orand/<wbr>or になる
  • well-knownwell-<wbr>known になる
  • state-of-the-artstate-<wbr>of-<wbr>the-<wbr>art になる
  • 1.2.3-beta.4 は折り返し候補の紙吹雪になる
  • UI/UXUI/<wbr>UX になる

これらのトークンは1行に収まるのが普通なので、通常はレンダリングに変化は出ません — しかしそのトークンは以後、幅の狭いあらゆるコンテキストで折り返し候補になります。

注入は パス風(path-like) チェックで制御します。トークンがパス風なのは、次のいずれかに見える場合です。

  • / を2つ以上含む (/a/b/cpackages/widget/src)
  • URLスキームで始まる (https://file://ftp://)
  • Windowsのドライブレターで始まる (C:\D:\Users\...)
  • ? の後に = を含む(クエリ文字列の形)

そのままにすべき例:

トークンパス風?
and/orNo — / が1つだけ、スキームなし
well-knownNo — - が1つだけ、スラッシュなし
state-of-the-artNo — ダッシュのみ
1.2.3-beta.4No — バージョン文字列であってパスではない
UI/UXNo — / が1つで、周りがすべて大文字
/a/b/c/d/eYes — / が3つ以上
https://example.com/docs/guideYes — スキームあり
C:\Users\Example\logsYes — Windowsドライブ
?q=hello&lang=jaYes — クエリ形
D3 — isPathLike ゲート: 本文はそのまま、パスには折り返し候補を挿入

トークンをパス風だと自信を持って分類できない場合は、注入しないでください。偽陰性(1つのトークンが狭いコンテナで折り返されないまま残る)のコストは、偽陽性(本文がどこでも不自然な位置で折り返される)のコストより大幅に低いです。

コンテナ側の CSS 調整

<wbr> は折り返し位置の候補を提示するだけです。そこで実際にどうするかはコンテナのCSSが決めます。面によって望ましいコンテナルールは異なります。

コンテキスト推奨ルール理由
本文(段落、リスト項目、カード)overflow-wrap: break-wordトークンがあふれる場合のみ <wbr> で折り返す。通常の単語はそのまま
コードブロック (<pre><code>)white-space: pre-wrap — 水平スクロールを受け入れるか、ユーザー切り替えモードとして overflow-wrap: anywhere を追加pre-wrap はインデントと改行を保持する。pre-wrap の中では、1つの長いトークンに対して <wbr> だけでは足りない
Diffビューア(+/- カラム、狭いガター)word-break: break-allセルが隣接要素にあふれないほうが重要で、区切り文字を意識した折り返しよりも収めることが優先される
狭いflexパネル(サイドバー、チャットバブル)overflow-wrap: break-word かつ flex子要素に min-width: 0min-width: 0 がないと、flexアイテムの min-content サイズは最長の単語に等しくなり、縮まなくなる

警告: 同じ要素で word-break: break-all と smart-break を混在させない

word-break: break-all はブラウザに「任意の2文字の間で折り返してよい、以上」と伝えます。このルールが有効になると、ブラウザは行に収まる最初の文字位置で折り返し、<wbr> の折り返し候補ヒントを参照しなくなります。区切り文字を意識した注入は完全に無駄になります。要素ごとに戦略を1つだけ選んでください。区切り文字を意識した折り返しならsmart-break(<wbr> + overflow-wrap: break-word)を、diffセルのような「何としても収める」面なら word-break: break-all を使います。両方を併用してはいけません。

警告: フェンスコードに white-space: pre-wrap を使うと overflow-wrap: break-word が効かなくなる

white-space: pre-wrap はリテラルな空白と改行を保持します。コードブロックに望ましい挙動です。副作用として、長い一塊のトークン(ログ行の中の180文字のURLなど)が overflow-wrap: break-word に応答しなくなります — このルールは必要なときにのみ折り返す仕様であり、pre-wrap のもとではトークンは自前のオーバーフロースクロールする行に技術的には「収まって」しまうからです。コードブロックには2つの選択肢があります。

  • 水平スクロールを受け入れる。コードはバイト正確なまま、ユーザーがスクロールします。
  • 明示的なオプトインモードとして overflow-wrap: anywhere を提供する(break-word より強く、必要ならトークンの途中でも折り返す)。これはユーザー切り替え可能なクラスに限定し、デフォルトにしないでください。

コードブロックに word-break: break-all を持ち出してはいけません — 1行ごとに識別子の途中でコードが粉々になります。

D5 — 同じ注入済みコンテンツに対する overflow-wrap: break-word と anywhere

break-word は、単一セグメント自体があふれるまではセグメントを壊しません — そのため区切り文字付きのURLは /?& できれいに折り返されます。anywhere はもっと積極的です。min-content 幅に寄与するので、flex親要素が最長セグメントより狭くなることが許されます。anywhere を使うのは、break-word では不十分(1つのセグメントがコンテナより長い)で、識別子の途中で折り返すことを受け入れられるときだけにしてください。

ゼロ幅スペース (U+200B) — テキスト専用のフォールバック

U+200B(ゼロ幅スペース、&#8203; とも書く)は文字列の中に折り返し候補を挿入する文字です。これは <wbr> と同等の推奨手段 ではありません。HTMLが使えない場面 — 長い文字列が要素を含められないプレーンテキスト面に存在しなければならないとき — にのみ使います。

HTMLを出力できない面:

  • title 属性の値(ブラウザのツールチップテキスト)
  • aria-label の値
  • HTMLを解釈しないコンポーネントに渡されるプレーンなJSON文字列
  • 表示時にそれでも折り返さなければならないCSVやテキストファイルのエクスポート

<wbr> と比較したトレードオフ:

  • クリップボードの汚染。 U+200B は実在する文字です。選択と一緒にコピーされ、貼り付け先にそのまま貼り付けられます。ゼロ幅スペースを含むURLを端末やURLフィールドに貼り付けると、検出しづらい失敗が起こることがあります。
  • 文字列長の歪み。 "hello".length"hel​lo".length — 後者は6になります。バリデータ、diffツール、バイト数UIは、ユーザーが見ているものとは異なる値を報告します。
  • アクセシビリティ保証が弱い。 スクリーンリーダーはたいてい無視しますが、リーダーやバージョンによって挙動が異なります。<wbr> には「読み上げない」という明文化された契約があります。
  • キャレットの挙動。 U+200B をナビゲート可能な文字として扱うエディタもあります。矢印キーでの移動中にキャレットがそこで止まることがあります。

経験則としては、HTMLを出力できるなら <wbr> を使ってください。U+200B はテキスト専用面にのみ使います。次のメンテナが単純な文字列に戻して折り返し能力を失わないように、コードコメントに判断の理由を記録しておきましょう。

D4 — U+200B によるプレーンテキスト面での折り返し

左のパネルはあふれるか、きれいに折り返されません。右のパネルは挿入された U+200B の位置で折り返されます — <wbr> と同じ見た目ですが、コピー&ペーストに不可視文字が持ち運ばれます。

HTMLが使える場面では常に <wbr> を使ってください。

AIがよくやるミス

  • word-break: break-all を一律ルールとして持ち出す。目の前の狭いコンテナは1つ修正できますが、サイト全体の段落やコードブロックをそっと台無しにします。
  • flex子要素に min-width: 0 を付け忘れる。flexアイテムのデフォルトの min-width: automin-content に等しく、これは最も長い単語です。flexカラム内の長いURLは縮まなくなり、行全体をオーバーフローさせます。子要素に min-width: 0 を付ければ解放されます。
  • isPathLike ゲートなしに <wbr> をグローバルに注入する。and/orstate-of-the-art1.2.3-beta.4 のような本文中のトークンが、本来なるべきでない折り返し候補になります。
  • U+200B<wbr> を同じものとして扱う。<wbr> はHTMLのみ、U+200B は文字列中の文字です。コピー&ペーストや文字列長への影響は異なります。
  • 同じ要素でsmart-breakと word-break: break-all を混ぜる。break-all<wbr> のヒントを無視するので、区切り文字を意識した注入は無駄な作業になります。
  • <pre><code> ブロックに overflow-wrap: break-word を当てて、長いトークンが折り返されることを期待する。これらの要素にはすでに white-space: pre-wrap が効いていて、単一の長いトークンに対しては break-word を無効化します。スクロールを受け入れるか、明示的に overflow-wrap: anywhere にオプトインしてください。

使い分け

smart-break(<wbr> + overflow-wrap: break-word)を使うべき場面

パス風のトークンを含む本文面: サイドバー、カード、チャットバブル、長い識別子カラムを持つテーブル、エラーメッセージパネル、コールアウト。注入は isPathLike で制御します。ユーザー生成やシステム生成のURLやファイルパスをレンダリングするあらゆるUIにとって、これがデフォルトです。

U+200B を使うべき場面

HTMLを出力できないテキスト専用の面: title 属性、aria-label の値、HTMLを解釈しないコンポーネントに渡されるプレーン文字列のJSONフィールド。HTMLが使える場所ではどこでも <wbr> を優先します。将来のメンテナが意図を理解できるよう、呼び出し箇所で選択理由を記録してください。

スクロールや pre-wrap のままにしておくべき場面(コードとdiff)

バイト正確さが重要なコードブロックでは、人為的な折り返し候補より水平スクロールを優先してください。「長い行を折り返す」オプトインのトグルを用意し、overflow-wrap: anywhere に切り替えるようにします。狭いガターを持つdiffビューアでは、区切り文字を意識した折り返しより列に収めることが重要なので、セル内容に word-break: break-all が必要になる場合があります。

参考

isPathLike ゲートを備えた <wbr> 注入戦略の参考実装は zudo-doc に記録されています(エピック zudolab/zudo-doc#370、PR zudolab/zudo-doc#383)。

Revision History