iOSで100vhが効かない問題で、楽な方法をNuxt.jsでやってみる


iOS safariで100vhがうまくいかない時に、
window.innerHeightを取って各要素のstyle属性に一個一個付ける、
というのをやりがちでしたが、楽な方法が無いかと探すとカスタムプロパティが使えるそうなので、
その手順をNuxt.js版で書きます。

mixinを作る

--whという名前でカスタムプロパティを定義する。
ロード時と、リサイズ時にwindow.innerHeightを取って--whに入れる。

mixins/device.js
export default {
  data: () => ({
    style: {
      '--wh': '100vh'
    }
  }),
  mounted() {
    this.$nextTick(() => {
      this.getWindowSize()
      window.addEventListener('resize', this.getWindowSize)
    })
  },
  methods: {
    getWindowSize() {
      this.style['--wh'] = `${window.innerHeight}px`
    }
  }
}

mixinを読み込む

mixinを読み込んで、styleオブジェクトをwrapper要素のstyle属性に入れる。

layouts/default.vue
<template lang="pug">
.l-wrap(:style="style")
  nuxt
</template>

<script>
import deviceMixin from '~/mixins/device'

export default {
  mixins: [deviceMixin]
}
</script>

カスタムプロパティを使う

heightにvar(--wh, 100vh)と書いて、使用する。
書き方: var(設定したカスタムプロパティ名, プロパティが無い時用の初期値)

pages/index.vue
<template lang="pug">
.p-top
</template>

<script>
export default {}
</script>

<style lang="stylus" scoped>
.p-top
  height var(--wh, 100vh)
</style>

まとめ

これで、iOSのツールバーを考慮した実装が

  1. wrapperでwindow.innerHeight取って、変数に格納する
  2. wrapperかそれ以下の小要素でheight var(--wh, 100vh)する

という形でほぼCSSで指定出来るようになりました。

IEはまだ未検証ですが、Nuxt.jsの場合はheight var(--wh, 100vh)とすると、
height 100vhを自動的に手前に追加してくれるようなので、
varが認識されなくても問題なくvhできるかと思います。

<style lang="stylus" scoped>
.p-top
  height 100vh
  height var(--wh, 100vh)
</style>

※mixinを使ったのはlayoutsが複数あるときに、各所に同じ処理を入れることになりそうで面倒だと思ったからなので、default.vueでmixinでやってる処理をそのまま書いても問題ないです。

※実際に使うときはモーダルとかのfixed系要素じゃ無い要素に使うと、iPhoneのスクロール時にがくがく高さ変わるので、リサイズが横幅のリサイズであることを判定することを検討してください。