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つなら両側に同じ値が入ります。
物理方向から論理方向への書き換え
書き換え前
.card-icon {
margin-right: 12px;
float: left;
text-align: left;
border-top-left-radius: 8px;
}書き換え後
.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つに仕分けると直しやすくなります。
- 置換漏れ。物理プロパティが残っている(洗い出しの正規表現を再実行すれば拾える)
- 手順2で「判断が要る」とした箇所。向きに意味のあるアイコンや、符号で動かす
transform - 意図した固定。画面の左右に固定する仕様で、変えてはいけない箇所
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でだけ壊れます。だからこそ、洗い出しで分類させ、置換を小さく切り、鏡像のスクリーンショットで確かめる順序が効きます。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。
- code.claude.com/docs/en/common-workflows
- code.claude.com/docs/en/chrome
- code.claude.com/docs/en/best-practices
- developer.mozilla.org/en-US/docs/Web/CSS/CSS_logical_properties_and_values
- developer.mozilla.org/en-US/docs/Web/CSS/Guides/Logical_properties_and_values/Ma…
- developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/dir