メモログ

⛰ 塵が積もって山とならないメモのログ 👄

fieldset要素内のlegendとフィールドを一列に並べる

fieldset要素内のlegendは通常「rendered legend」として扱われ、特別な仕様になる。そのため他の要素と一列に並べたい場合はそこに配慮する必要がある。

rendered legendの仕様

rendered legendの仕様によると、fieldset配下の子要素は以下の条件を満たしているとrendered legendとして扱われる

  • 子要素がlegend要素である
  • 子要素のfloatがnoneである
  • 子要素のpositionがabsoluteまたはfixedではない

たとえば以下のようなHTMLがあった場合、legendはrendered legendとして扱われ、fieldsetのボーダー上に配置される。

レジェンド
<div>
  <fieldset>
    <legend>レジェンド</legend>
    <label><input type="checkbox" />チェックボックス</label>
  </fieldset>
</div>

逆に言えば、float:leftposition:absoluteを使用すればrendered legendとして扱われなくなり、通常の要素と同じように扱うことができる。

また、display: contentsには「特別な要素に対するdisplay:contentsの効果」という付記があり、display: contentsの場合にrendered legendとして扱わないことが書かれている。

float: left

float: left を設定すると、rendered legendではなくなり他に要素と同じように扱える。

レジェンド
legend { float: left; width: 200px; }
label { overflow: hidden; }

gridやflexレイアウトで制御することもできるけど、今確認したらSafariでは期待通りに動いてくれないよう。

レジェンド
fieldset { display: grid; grid-template-columns: 200px 200px; }
legend { float: left; }
レジェンド
fieldset { display: flex; }
legend { float: left; flex-basis: 200px; }
label { flex-basis: 200px; }

position: absolute

position:absoluteを使ってもrendered legendでなくすことができる。

レジェンド
fieldset { position: relative; }
legend { position: absolute; width: 200px; box-sizing: border-box; }
label { margin-left: 200px; }

display: contents

display: contentsのサポート状況を見るに、button要素に適用すると問題があるようだけど、legendに対しては問題なく利用できそう。IE非対応だけど。

レジェンド
fieldset { display: grid; grid-template-columns: 200px 200px; }
legend { display: contents; }

また「特別な要素に対するdisplay:contentsの効果」によると、fieldsetにdisplay: contentsを設定すると、fieldsetのprincipal boxがなくなり、fieldsetが普通のコンテンツと同じように描画されるようになる。

この場合、legendは変わらずrendered legendとして扱われるけど、fieldsetのボーダー上にrendered legendを配置するという処理はなくなる(boxが存在しないから)。

その上で、fieldsetの親の要素でdisplay: flexが設定されると、fieldsetの子要素のformatting contextがFlex formatting contextになり、Flex Layoutの仕様に従ってlegendのboxも配置されるということなのかなと思う。ここはよく分かっていない。

レジェンド
div { display: flex }
fieldset { display: contents; }
legend { flex-basis: 200px; }
label { flex-basis: 200px; }

同じように親の要素に対してdisplay: grid を設定することで、一列に並べることもできる。

レジェンド
div { display: grid; grid-template-columns: 200px 200px; }
fieldset { display: contents; }

というメモ。