以前書いた記事「detailsタグで作るアコーディオン。CSSだけで実装可。アクセシビリティにも対応」を久々に見直したところ、デモコードの矢印が盛大にバグっていました。

事象はPC版のChrome124系とEdgeで確認。Chromiumエンジン系のブラウザトラブルです。
リリース時は問題無かったので、ブラウザアップデートでいつの間にか発生していたようです。
以前はheight値を省略して問題なかったが……
びよ~んと伸びている原因はすぐにわかりました。
矢印のheight値を省略していた結果、縦中央揃えの為に付与していたposition: absolute;
により引き伸ばされていました。
.ico {
position: absolute;
top: 0;
bottom: 0;
width: 18px;
aspect-ratio: 1/.6;
margin: auto;
}
※関係箇所のコードのみ抜粋
position: absolute;
を使って垂直方向を中央揃えする場合、marginを使って上下から互いに対象を引っ張ります。その際、height
値を設定していないと、対象自体が引き伸ばされてしまいます。今まではaspect-ratio
を設定すれば、height
値を省略しても問題ありませんでした。
しかしバグなのか仕様が変わったのか、どうもposition: absolute;
設定中はheight値が指定無し(auto?)と同等の扱いになっている模様。検証ツール上はちゃんとwidth
とaspect-ratio
の設定だけでheight
は算出出来ているはずなのだが、うーん何故だろう。
height値を固定すれば解決する問題ですが、ここに固定値を設定してはaspect-ratio
を使用する意味が無くなってしまいます。レスポンシブ時にwidthの変更だけで同じ比率を維持させるのが目的なので、ここを固定させるわけにはいきません。
【失敗】とりあえずfit-contentを指定してみたがiOS系だとダメな模様
aspect-ratio
による算出結果を超えないよう、試しにfit-content
を使ってみたところ上手くいきました。
fit-content
は対象の最小寸法を算出するプロパティです。使用意図としてはaspect-ratio
による算出値を最小寸法として代入しているイメージ。
.ico {
position: absolute;
top: 0;
bottom: 0;
width: 18px;
height:fit-content;
aspect-ratio: 1/.6;
margin: auto;
}
これを試したところWindows及びAndroid端末では上手くいきましたが、iOS系ではSafariもChromeもダメでした。
むしろこっちは従来通りaspect-ratio
の設定時はheight
を省略したままでOK。むしろfit-content
を指定するとダメになる。
仕方がないのでcalcでアスペクト比を手動計算
height
を書けば済む話ですが、アスペクト比の自動化だけは譲るわけにはいきません。
そこでcalc
を使用してアスペクト比を手動で記述する事にしました。せっかくaspect-ratio
があるのに何故俺はわざわざこんな事を……。
.ico {
--arrow-size: 18px;
position: absolute;
top: 0;
bottom: 0;
width: var(--arrow-size);
height:calc(var(--arrow-size) * .6);
margin: auto;
}
そもそもposition: absolute;を止めれば?
おっしゃる通りw 矢印の位置制御を flex
やgrid
で代替すればこの問題は発生しません。
しかしflex
やgrid
を使った場合、インナー要素内に不意にspan
等のカラムを挟まれるとjustify-content
やgrid-template-columns
の制御がややこしくなる。CMSで編集可能な状態にしていた場合、十分ありえるパターンです。それを防ぐためにテキスト部分に包括要素が必要になったりとそれはそれで面倒。最初からそれ前提で組んでいれば問題無いけれども。。
何かとレガシー扱いされるabsolute
ですが、コンテンツの領域に直接干渉しない点は便利であり、まだまだ使い道はあります。そのためなんとかこの手法を使ったままこの事象は解決したいところです。
2024.5.2 追記:min-width:0;で対処出来る
追記です!height
を省略してもmin-width:0;
を付与すれば対処出来ることがわかりました。
.ico {
--arrow-size: 18px;
position: absolute;
top: 0;
bottom: 0;
width: var(--arrow-size);
min-width: 0;
aspect-ratio: 1/.6;
margin: auto;
}
参考になったのは、以下の記事です。
参考文献
【CSS・Chrome 124】aspect-ratioを使っているページが何もしていないのに壊れた
https://zenn.dev/kagan/articles/css-chrome-aspect-ratio
この記事の執筆者の、かがんさんはdisplay: grid;
設定時に子要素の横幅が崩れるトラブルだったようですが、こちらも同様の方法で対処出来ました。
Chromeでaspect-ratio
まわりの処理が変わったのは確実です。これらの挙動を見るにバグだと思います(思いたい)が、いつ修正されるのかもわかりませんので、当面はmin-width:0;
をセットで付与したいと思います。