Claude Media
Claude CodeでRTL対応をCSS logical propertiesで進める手順

Claude CodeでRTL対応をCSS logical propertiesで進める手順

アラビア語やヘブライ語の画面で左右が崩れる原因は、margin-leftなど物理方向のCSSです。Claude Codeでinline-start系へ置換し、dir="rtl"のスクリーンショットで崩れを確かめる流れを扱います。

アラビア語やヘブライ語に対応するとき、画面の崩れの大半はmargin-leftやtext-align: leftのような物理方向のCSSから来ます。文字が右から左へ流れる画面で、余白もアイコンも左側に残ってしまうからです。直し方は、物理方向のプロパティをmargin-inline-startなどの論理プロパティに置き換えることです。置換そのものは機械的な作業なので、Claude Codeに洗い出しと書き換えを任せ、dir="rtl"を付けた画面のスクリーンショットで崩れを確かめる流れが組めます。ここでは、置換の対応表、洗い出しの指示、置換できない箇所の見分け方、見た目の確認、再発防止のルールを順に扱います。

物理プロパティはRTLで何が崩れるのか

論理プロパティは、画面の左右ではなく「文字が流れる向き」を基準に方向を決めます。MDNの説明では、行の始まりが常に左側とは限りません。英語やポルトガル語は左から右へ、ヘブライ語とアラビア語は右から左へ書かれます。日本語や中国語は伝統的に縦書きで、行が左へ積まれます。

この基準になるのが、inline(行が進む方向)とblock(段落が積まれる方向)という2つの軸です。英語やアラビア語の横書きでは、inlineは水平方向でblockは垂直方向になります。leftやrightは画面の物理的な辺を指すので、dir="rtl"にしても動きません。inline-startは文字の書き始めの側を指すので、ltrなら左、rtlなら右に自動で入れ替わります。

MDNのmargin-inline-startの説明どおり、横書きでltrならmargin-leftと同じで、rtlならmargin-rightと同じです。つまり、物理プロパティで書いたCSSは次のように崩れます。

  • 見出しの左にあるアイコンとの間隔が、rtlでも左側に残り、アイコンが文字に張り付く
  • text-align: leftの段落だけが左寄せのままで、右から読み始める目線と逆になる
  • float: leftの画像が左に残り、文章の回り込みが逆側になる
  • 左上だけ丸めた角が、rtlでは文字の終わり側に出る

論理プロパティに置き換えたルールは、この4つが書き換えなしでrtlに追随します。

置換の対応表:何をどれに置き換えるか

MDNの対応表は、horizontal-tbの横書きでltrのときの対応です。次の表は、実務で頻出する物理プロパティから拾ったものです。

物理プロパティ論理プロパティ備考
margin-left / margin-right論理プロパティmargin-inline-start / margin-inline-end備考padding、borderも同じ命名
border-left / border-right論理プロパティborder-inline-start / border-inline-end備考color、style、widthの個別指定もある
left / right(位置指定)論理プロパティinset-inline-start / inset-inline-end備考位置指定した要素にだけ効く
text-align: left / right論理プロパティtext-align: start / end備考プロパティは同じで値を替える
float: left / right論理プロパティfloat: inline-start / inline-end備考値を替える
border-top-left-radius論理プロパティborder-start-start-radius備考左上の角
border-top-right-radius論理プロパティborder-start-end-radius備考右上の角
border-bottom-left-radius論理プロパティborder-end-start-radius備考左下の角
border-bottom-right-radius論理プロパティborder-end-end-radius備考右下の角

角丸の名前は、先頭がblock軸の側、後ろがinline軸の側を表します。border-start-start-radiusは、block-startとinline-startの間の角です。

topやbottomに当たるblock軸は、横書きではrtlにしても向きが変わりません。そのためmargin-topを急いでmargin-block-startにする必要はありません。置換の優先度が高いのは、inline軸の左右です。

左右をまとめて指定する省略記法にも論理版があります。margin-inline: 8px 16pxのように、2つの値のうち最初がinline-start、次がinline-endに当たります。値が1つなら両側に同じ値が入ります。

前と後

物理方向から論理方向への書き換え

BEFORE

書き換え前

.card-icon {
  margin-right: 12px;
  float: left;
  text-align: left;
  border-top-left-radius: 8px;
}
AFTER

書き換え後

.card-icon {
  margin-inline-end: 12px;
  float: inline-start;
  text-align: start;
  border-start-start-radius: 8px;
}

書き換え前のmargin-right: 12pxは、アイコンを左に浮かせて文字との間隔を右側に取る意図です。意図は「アイコンの後ろの間隔」なので、inline-endが正解になります。margin-leftに置き換えて向きを逆にしないように注意が要ります。

手順1:Plan Modeで物理方向のCSSを洗い出す

いきなり書き換えさせず、まず洗い出しと分類だけをさせます。Claude Codeの公式ワークフローは、リファクタリングを「古い書き方の特定、改善案の提案、変更の適用、検証」の順に進め、小さく試せる単位で進めるよう勧めています。この移行もその流れに乗せられます。

差分を確認してから進めたいときは、編集せずに調べるPlan Modeが向きます。

claude --permission-mode plan

セッション中にShift+Tabを押して切り替えることもできます。指示文は次のような形にします。

src配下のCSS・SCSS・CSS-in-JSから、左右の物理方向を指定している
宣言を洗い出して。margin/padding/border/left/right/text-align/
float/border-radiusの各種を対象にする。
ファイル別の件数表と、論理プロパティへ機械的に置換できるものと、
人の判断が要るもの(アイコンの向き、translateX、背景位置など)の
分類を出して。編集はしない。

分類を指示に入れる理由は、次の節で扱います。件数の目安を手元でも持っておくと、Claude Codeの報告が漏れていないか突き合わせられます。

grep -rnE "(margin|padding|border)-(left|right)|text-align:[ ]*(left|right)|\
float:[ ]*(left|right)|border-(top|bottom)-(left|right)-radius" \
  src --include='*.css' --include='*.scss' | wc -l

この正規表現はleft:やright:による位置指定を拾いません。left: 0はtop: 0などと組み合わせて全面を覆う用途でも使うので、機械的な検索では意図が読めないためです。位置指定は洗い出しの分類で、Claude Codeに1件ずつ意図を書かせると読み違いが減ります。

手順2:機械的に置換できる箇所と、判断が要る箇所

洗い出しが済んだら、機械的に置換できる箇所から書き換えます。対応表のとおりに左右を入れ替える作業は、規則が決まっているのでClaude Codeに任せやすい部分です。

一方、論理プロパティの一覧に載っていない方向依存が残ります。MDNの論理プロパティ一覧は、block-size、border系、inline-size、inset系、margin系、max/min-size系、padding系で構成されています。次のような方向依存の指定は、この一覧に含まれません。

  • transform: translateX(...)のような、符号で左右を決める指定
  • background-position: left centerのような、背景の位置
  • 矢印やシェブロンなど、向きに意味がある画像やアイコン

これらは置換の対象ではなく、rtlの画面で見て個別に直す箇所です。置換の分類に「判断が要る」という区分を設けておけば、Claude Codeが「置換できない」を黙って飛ばさず、一覧として人に返してくれます。

落とし穴

位置指定の left と right は、位置指定した要素にしか効かない

inset-inline-startは、位置指定していない要素には効果がありません。left: 0をinset-inline-start: 0に置き換えるときは、同じ要素がpositionを持っているかを一緒に確かめます。持っていないleftは、もともと何も効いていない死んだ宣言の可能性があります。

置換の依頼は、ファイルの束に区切って出します。リファクタリングの公式ガイドにある「小さく試せる単位で進める」考え方と同じで、1回の依頼を1つのディレクトリか1つのコンポーネントに絞ります。あとでスクリーンショットを撮り直す範囲も、その単位で足ります。

src/components/card配下の物理方向のCSSだけを論理プロパティに
置換して。対応は margin-left→margin-inline-start、
text-align:left→start のように、意図が「文字の書き始め側」か
「画面の左」かを判断してから書き換える。
画面の左右に固定したい箇所(例: 左固定のサイドバー)は変えずに、
どのファイルのどの宣言かを一覧で返して。

「画面の左に固定したい」箇所は実際にあります。たとえば動画プレーヤーの再生バーを常に左から右へ進めたい場合は、rtlでも向きを変えたくありません。論理プロパティに全面置換すると、この箇所が逆に壊れます。

手順3:dir="rtl"のスクリーンショットで崩れを確かめる

置換が済んだら、実際にrtlで描画して確かめます。向きを決めるのはHTMLのdir属性です。dirはグローバル属性で、ltr、rtl、autoを取ります。属性がなければ、親の要素から引き継ぎ、祖先のどこにも指定がなければ左から右が既定です。

ページ全体を試すなら、<html lang="ar" dir="rtl">のようにルートに付けます。MDNの例でも、lang="ar"とdirを組み合わせています。ユーザー入力のように向きが分からないデータは、dir="auto"で先頭の強い方向性の文字から向きを決めさせます。このautoは、入力欄や投稿内容など、外から来る文字列に使うための値です。固定UIの文言に使うと、文言によって向きが揺れます。

画面の確認は、Claude in Chromeを使えば同じセッションの中で済みます。Claude Codeのブラウザ連携は、ビルドしたあとにブラウザで確かめる作業をつなげるもので、見た目の回帰の確認も用途に挙がっています。ブラウザを開いてスクリーンショットをファイルに保存する指示も出せます。連携にはChromeかEdge、拡張機能、/loginでの認証が要ります。APIキーやclaude setup-tokenで認証しているときは、--chromeを付けても連携は有効になりません。WSLでは使えません。

開発サーバーを起動して、ltrとrtlの両方でトップとカード一覧を
開いて。rtlは<html>にdir="rtl"を付けた状態にする。
それぞれスクリーンショットをshots/ltr-*.pngとshots/rtl-*.png
として保存して。保存したら、2枚を見比べて、
鏡像になっていない箇所を挙げて。

比べる観点は「鏡像かどうか」です。rtlの画面は、ltrの画面を左右反転した配置になるのが基本です。アイコンが文字の右側に来ているか、余白が文字の反対側に付いているか、右端の閉じるボタンが左端に移っているかを見ます。

Claude Codeのベストプラクティスは、完了の報告を鵜呑みにせず、実行したコマンドの出力やスクリーンショットのような証拠を求めるよう勧めています。「rtlでも問題ありません」という一文より、並べた2枚の画像のほうが検証になります。

鏡像にならなかった箇所は、次の3つに仕分けると直しやすくなります。

  1. 置換漏れ。物理プロパティが残っている(洗い出しの正規表現を再実行すれば拾える)
  2. 手順2で「判断が要る」とした箇所。向きに意味のあるアイコンや、符号で動かすtransform
  3. 意図した固定。画面の左右に固定する仕様で、変えてはいけない箇所

3の判断は人が持ちます。Claude Codeには「仕様として固定している」と明示して、それ以降の指摘から外させます。

手順4:CLAUDE.mdに規則を置き、物理方向の再流入を止める

置換が終わっても、新しく書かれるCSSがmargin-leftに戻ると意味がありません。プロジェクトのルールとしてCLAUDE.mdに書いておくと、Claude Codeが新規コードを書くときにも守ります。

## CSSの方向指定
- 左右の余白・内側の余白・罫線・位置・寄せ・回り込みは、
  物理方向(left/right)でなく論理プロパティで書く
  (margin-inline-start、padding-inline-end、border-inline-start、
  inset-inline-start、text-align: start/end、float: inline-start/end)。
- 角丸は border-start-start-radius など論理版を使う。
- 画面の左右に固定する意図のときだけ物理方向を使い、
  同じ行に「/* physical: 理由 */」とコメントを残す。
- translateXや背景位置など論理版がない指定は、
  rtlのスクリーンショットで確認してからマージする。

「physical:」コメントの運用は、洗い出しの正規表現にも使えます。コメント付きの行を除外すれば、意図せず残った物理方向だけが検査に出ます。

grep -rnE "(margin|padding|border)-(left|right)|text-align:[ ]*(left|right)" \
  src --include='*.css' --include='*.scss' | grep -v "physical:"

この検索結果が0件になれば、置換漏れは残っていません。CIに入れる場合は、結果が1件でもあれば失敗にします。

完了の判定:何が揃えば「RTL対応できた」と言えるか

置換が済んだことと、RTLで使える画面になったことは別です。論理プロパティへの置換は、レイアウトの向きが追随する土台を作るだけです。

終わりの目安は3点です。物理方向の検索結果が、意図した固定の箇所だけになっていること。主要な画面のltrとrtlのスクリーンショットが、鏡像として並べて確認済みであること。向きに意味のあるアイコンやtransformが個別に直っていること。文言の翻訳は、また別の工程です。翻訳データの入口やtr()の扱いは、Claude CodeでGodotを翻訳対応にする手順にあります。

論理プロパティへの置換は、新しいCSSの機能を使い始める移行でもあります。最新のCSSを書かせるためのプラグインは、modern-web-guidanceの導入記事で扱っています。スクリーンショットで見た目の差分を確かめる手順は、!importantをcascade layersへ移す記事と同じ型です。

物理方向の置換は、機械的に見えて、意図の読み取りが要る作業です。「画面の左」と「文字の書き始め側」を取り違えた置換は、ltrの見た目を変えずに、rtlでだけ壊れます。だからこそ、洗い出しで分類させ、置換を小さく切り、鏡像のスクリーンショットで確かめる順序が効きます。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. code.claude.com/docs/en/common-workflows
  2. code.claude.com/docs/en/chrome
  3. code.claude.com/docs/en/best-practices
  4. developer.mozilla.org/en-US/docs/Web/CSS/CSS_logical_properties_and_values
  5. developer.mozilla.org/en-US/docs/Web/CSS/Guides/Logical_properties_and_values/Ma…
  6. developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/dir
この記事を共有:XはてブLinkedIn