Sassyブログ

好きなことで暮らしを豊かにするブログ

画面幅を縮めたり広げたりすることで要素がカクカク左右や上下にずれる問題はマージンの自動算出による小数pxが原因

問題

これはコンテンツ部分の左右マージンにmargin: 0 auto;をしており、画面幅を変えてもコンテンツが中央に配置されるようにしていた。

コンテンツ内にはSVGで描画した円の中心にアイコンを配置していたのだけど、画面幅を変更するとSVGで描画した円が左右に動きアイコンがずれるような見え方をしていることに気づいた。

原因

この動きが奇妙過ぎて色々調べていたのだけど、気づけば他のボタン要素なども左右に動いているではないか…

もう少し調べると画面幅が奇数の時に発生していることが分かった。

これは小数pxのブラウザ毎の解釈が異なることにより、Chromeだと 0.5 刻みになっていた。

またFirefoxだとキレイに小数点を切り捨ててくれるのか要素がカクカクずれる事象は発生しなかった。

解決方法

これを直すにはJavaScriptで左右のマージンを算出してfloor関数で切り捨てるのが確実に早い解決

以下の処理を関数にまとめておく

  const contents = document.getElementById(‘contents’);
  if (!contents) {
    return;
  }
  // 画面サイズの横幅を取得
  const bodyWidth = document.body.clientWidth;
  // コンテンツの横幅を取得
  const contentsWidth = sectionsContents.clientWidth;
  // 左右のマージン合計値を算出
  const totalMargin = bodyWidth - contentsWidth;
  // カスタムプロパティに設定する
  document.documentElement.style.setProperty(
    ‘--left-and-right-margin’,
    `${Math.floor(totalMargin / 2)}px`
  )

addEventListenerで resize イベントをハンドリングし画面サイズ変更を検知して、処理を走らせてあげる。

window.addEventListener(`resize`, hoge);

あとはカスタムプロパティを margin: 0 var(--left-and-right-margin); とすれば良い。

Sassを使っている人ならfloor関数が用意されているため、floor関数を使う手もあるが、これはちょっと上手く使えなかった。

というのもfloor関数は数値を受け取るので、まず auto を引数に渡すことができない。

margin: 0 floor(auto)

このように書くと

Sass::SyntaxError: $value: “auto” is not a number for `floor’

というエラーが発生する。

というか私はそこまでcssに詳しくないのだが、どうやら評価した結果を渡さず、記述したものをそのまま渡していようで、文字列として解釈されてしまっている。

autoを使わないようにして、以下用に書いたが同様にエラーとなった。

margin: 0 floor(calc((100% - $content-width) / 2))

純粋に数値か四則演算の式であれば問題ないみたい。

こんな背景により少しSassで用意されているfloor関数を使っては上手く解決できなかったので、JavaScriptに頼ることにした。

同じ境遇に置かれている方は是非参考にしていただければと思います。