CSSの論理プロパティで、書く向きに合わせて余白を付ける方法

​​CSS​HTML,Playwright

margin-inline-start や padding-block のような論理プロパティを使うと、余白や線を「左」「上」ではなく、「行の始まり」「行の終わり」で指定できます。同じ CSS のまま、右から左に書く言語では左右が入れ替わり、縦書きでは行の始まりと終わりが上と下になるので、向きごとに CSS を書き分けずに済みます。

補足

検証環境は Ubuntu 24.04、Node.js 22.23.4、Playwright 1.63.0、Chromium 153 です。ヘッドレスの Chromium で、幅800px・高さ600pxの画面にページを開き、getComputedStyle() で計算後の上下左右の値を、getBoundingClientRect() で位置と大きさを測りました。Firefox と Safari では試していません。右から左の向きは、アラビア語などの文章ではなく、日本語の文に dir="rtl" を付けて確かめています。

4段の比較。1段目の横書き・左から右では、囲みの左にピンクの線があり、星のアイコンが本文の左にある。2段目の右から左で物理プロパティのままの囲みは、枠の右端にくっつき、ピンクの線は左に残り、星は本文の右に詰まっている。3段目の右から左で論理プロパティの囲みは、枠の右端から少し離れ、ピンクの線は右にあり、星と本文の間が空いている。4段目の縦書きでは、囲みが枠の右上にあり、ピンクの線は上にある
同じお知らせの囲みを、書く向きを変えて表示した画面(点線は親要素の枠)

論理プロパティは「行の向き」と「行が並ぶ向き」で指定する

論理プロパティでは、辺を inline と block で呼び分けます。inline は文字が並んで1行ができる向き、block は行や段落が積み重なる向きです。日本語や英語の横書きなら、inline は左から右、block は上から下です。それぞれの始まりの辺が start、終わりの辺が end です。

MDN の論理プロパティの基本概念の説明にあるとおり、論理プロパティは、margin-left や width のような画面の向きで決まる物理プロパティに対応するものです。同じく MDN の margin-inline の説明によると、対応先は、要素の writing-mode(横書きか縦書きか)と direction(左から右か右から左か)などで決まります。

検証には、次のお知らせの囲みを使いました。行の始まりの側(横書きなら左)に余白と線を付け、アイコンと本文の間を空けたものです。

css
.notice {
  margin-block: 16px;
  margin-inline-start: 24px;
  padding-block: 8px;
  padding-inline: 16px 8px;
  border-inline-start: 6px solid #d85878;
  max-inline-size: 280px;
}
.notice .icon {
  margin-inline-end: 8px;
}
html
<div class="notice"><span class="icon">★</span><span class="text">お知らせの本文です。</span></div>

親要素を、指定なしの横書き、dir="rtl"、writing-mode: vertical-rl の3通りにして、計算後の値を調べました。

指定 横書き・左から右 横書き・右から左 縦書き
margin-inline-start: 24px 左 24px 右 24px 上 24px
margin-block: 16px 上下 16px 上下 16px 左右 16px
padding-inline: 16px 8px 左 16px・右 8px 右 16px・左 8px 上 16px・下 8px
border-inline-start: 6px 左 6px 右 6px 上 6px
max-inline-size: 280px max-width 280px max-width 280px max-height 280px
アイコンの margin-inline-end: 8px 右 8px 左 8px 下 8px

横書きで左から右に書くときは、left や width で書いた場合と同じ値になります。右から左にすると、左右がそっくり入れ替わりました。縦書き(vertical-rl)では、文字は上から下へ進んで1行になり、次の行は前の行の左に並びます(MDN の writing-mode の説明)。そのため、inline の始まりが上、block の始まりが右になります。表のとおり、margin-block は左右の余白に、max-inline-size は高さの上限になりました。

物理プロパティのままだと、右から左のときに線と余白が逆側に残る

同じ囲みを margin-left、padding-left、border-left、margin-right(アイコン)で書き、dir="rtl" の中に置くと、計算後の値は左から右のときと同じで、線も24pxの余白も左のままでした。

一方、右から左の文章では、ブロックは右端に寄り、アイコンは本文の右に来ます。そのため、上の画像の2段目のように、囲みは親の右端にくっつき、線は行の終わりの側に付き、アイコンは本文と詰まって表示されました。論理プロパティで書いた3段目では、余白と線とアイコンの間隔が、そろって右から左の向きに合わせて付いています。

今は右から左の言語に対応していなくても、論理プロパティで書いておけば、あとで対応するときは、CSS を探して書き換えなくても、dir を切り替えるだけで済みます。

margin-inline に値を1つ・2つ書いたとき

margin-inline と padding-inline は、始まりと終わりをまとめて指定する一括指定です。MDN の margin-inline の説明のとおり、値が1つなら両側に同じ値、2つなら1つ目が始まり、2つ目が終わりに入ります。幅400pxの親の中に、幅200pxの子を置いて確かめました。

指定 margin-left margin-right 子の左端
margin-inline: 10px 10px 10px 10px
margin-inline: 10px 20px 10px 20px 10px
margin-inline: auto 100px 100px 100px

margin: 0 auto で中央に寄せていたところは、margin-inline: auto に置き換えられます。margin と違って上下の余白には触れないので、上下に付けた余白をうっかり0にすることもありません。margin-block、padding-block も同じように、上下(縦書きでは左右)をまとめて指定します。

縦書きでは width の代わりに inline-size を使う

幅と高さにも論理プロパティがあります。inline-size は行の向きの大きさ、block-size は行が並ぶ向きの大きさです。inline-size: 200px; block-size: 50px を指定した要素を測りました。

向き 計算後の width 計算後の height
横書き 200px 50px
縦書き(vertical-rl) 50px 200px

縦書きでは、inline-size が高さに、block-size が幅になりました。MDN の inline-size の説明にあるとおりの対応です。囲みの例で使った max-inline-size のように、上限を決めるものもあります。縦書きの段落の1行の長さを決めたいときは、width ではなく inline-size か max-inline-size を使うと、横書きと同じ書き方で済みます。

位置の指定と文字そろえにも始まりと終わりがある

position: absolute の要素を置く top や left にも、inset-block-start や inset-inline-start という論理プロパティがあります。text-align には start と end という値があります。幅400pxの親の中で、inset-block-start: 0; inset-inline-start: 0 で置いた幅50pxの要素と、text-align: start の行を、向きを変えて測りました。

向き inset-inline-start: 0 の計算後の値 text-align: start の行
左から右 left: 0px 左端に寄る
右から左 right: 0px 右端に寄る

右から左のときは、要素は親の右端に付き、文字も右端に寄りました。MDN の inset-inline-start の説明にあるとおり、位置指定されていない要素には効きません。float にも inline-start と inline-end の値がありますが、下の対応表のとおり、Chrome では118からなので、古いブラウザも対象にするなら注意が要ります。

margin-left と margin-inline-start を両方書くと、後に書いたほうが使われる

左から右の横書きでは、margin-left と margin-inline-start は同じ余白を指します。CSS Logical Properties and Values Level 1 の仕様では、このように同じ辺を指す物理プロパティと論理プロパティは、1つのプロパティとみなしてカスケードし、優先度の高い宣言の値を使う、と決められています。同じ規則の中なら、後に書いたほうが使われます。

書いた順 向き margin-left margin-right
margin-left: 10px; margin-inline-start: 20px; 左から右 20px 0px
margin-inline-start: 20px; margin-left: 10px; 左から右 10px 0px
margin-left: 10px; margin-inline-start: 20px; 右から左 10px 20px

右から左では、margin-inline-start は右の余白になるので、2つの宣言はぶつからず、両方が使われました。物理プロパティで書いた古い CSS に、margin-left を残したまま margin-inline-start を足すと、右から左のときには左右の両方に余白が付きます。書き換えるときは、同じ辺の古い宣言を消しておくと迷いません。

余白や線の向きは、その要素自身の writing-mode と direction で決まる

margin-inline-start がどの辺になるかは、親ではなく、その要素自身の向きで決まります。親に dir="rtl" があっても、子に dir="ltr" を付けると、子の margin-inline-start: 20px は margin-left の20pxになりました。親が縦書きで子が横書きのときも、子の margin-inline-start は上ではなく左の余白になりました。前の節で引いた仕様にも、余白・線・大きさなどのプロパティは、要素自身の計算後の書字方向で対応を決める、と書かれています。ただし、float と clear の inline-start と inline-end だけは、その要素ではなく、包含ブロックの書字方向で決まると、同じ仕様に書かれています。

対応しているブラウザ

MDN の互換性データ(@mdn/browser-compat-data 8.1.8)で調べた、最初に対応したバージョンです。

機能 Chrome Firefox Safari iOS の Safari
margin-inline-start、border-inline-start 69 41 12.1 12.2
inline-size 57 41 12.1 12.2
margin-inline、padding-block 87 66 14.1 14.5
inset-inline-start、inset-inline 87 63 14.1 14.5
text-align: start 1 1 3.1 2
float: inline-start 118 55 15 15

margin-inline のような一括指定と、inset- で始まる位置のプロパティは、margin-inline-start などより後に対応しています。

​Posted by 86