はじめに
ChromeやEdgeのバージョンが128に更新された時、
縦スクロール固定、横スクロールは動的に動かしている要素の位置がずれた。
状況
cssのzoomプロパティが適用されたdiv要素の子要素に対して、
縦スクロールはposition:fixedで固定されるけど
横移動した時に位置を動的に動かすために
jQueryのoffset().leftで絶対位置を取得してスクロールしたpxと引き算して動かすということをしていた。
jQueryのバージョンはv1.12.4とかなり古い...
原因
Chromeのバージョンが127から128に変わった時に、
cssのzoomが標準化されて、それに合わせてjavascriptのAPIが色々変更されたらしい。
リリースノート
API影響
iframe コンテンツ ドキュメントに適用するズームを変更する 継承されたすべての長さのプロパティに適用されるように変更します。 (以前は、継承された font-size のみが変更されました)。
例えば、横幅100pxのdiv要素をzoom: 2とした時に
その要素が表示されるときは200pxでレンダリングされる。
その子要素にposition: fixedの要素があったとして、
バージョン127までは、left: 20pxとした時は、左から20pxの位置に表示されていた。
128からはzoom: 2の値が積算されて、左から40pxの位置に表示されるようになった。
という感じかな?
これまでは、position:fixedの要素は親要素に関係なく絶対位置に配置されていたけど、
親要素にzoomが含まれる場合は、例外にならず全ての長さ要素が相対化されるっぽい。
根本対策
zoomを使い続けたまま他だけを修正する場合の対策だけど、
zoomが使用されている子要素の全ての長さのプロパティーがzoomの値で再計算されるので、
動的に長さを出してる場合は以下のような感じで、
静的に書いてる場合はzoomの値をかけてやる必要がある。
$(document).ready(function() {
// 例として要素を選択
var element = $('#yourElement');
// 要素のオフセットの left 値を取得
var offsetLeft = element.offset().left;
// document の zoom 値を取得
var zoom = window.getComputedStyle(document.documentElement).zoom;
// zoom の値が取得できない場合は 1 とする(デフォルト値)
zoom = zoom ? parseFloat(zoom) : 1;
// zoom を適用した新しい left 値を計算
var adjustedLeft = offsetLeft / zoom;
console.log("Adjusted Left: ", adjustedLeft);
});
回避策
css zoom 標準化前の仕様にする。
2025年4月16日まではTrial for DisableStandardizedBrowserZoom
のOrigin Trialsに登録してヘッダーとかmetaタグとかで設定すると元の仕様になるっぽい?
まぁそこらへんはやったことないし、調査不足なんでドキュメントを見てもろて
Chromeの場合 Trial for DisableStandardizedBrowserZoom
Edgeの場合 Trial for DisableStandardizedBrowserZoom
Origin Trials 説明
関連リンク
css zoomの仕様に関する議論
Feature
Demo