Skip to content

Fullscreen Page Adaptation

To install all solutions, please refer to Solutions Installation

Applicable Scenarios

The page size matches the screen's viewport, and the project page needs to be fully displayed on the screen while maintaining the UI design's dimensions and proportions.

Solution

Use postcss-pxtorem to convert page units to rem (relative to the root element's font size). Then calculate an appropriate scaling ratio based on the UI design dimensions and the screen size to ensure the page is fully displayed while preserving the design proportions.

TIP

Note: Areas requiring adaptive layout within the page need manual style adjustments.

Install This Hook Separately

shell
npm install @havue/use-full-screen-adapt --save
shell
yarn add @havue/use-full-screen-adapt
shell
pnpm install @havue/use-full-screen-adapt

Steps

Install postcss-pxtorem

bash
npm install -D postcss-pxtorem

Configure Environment Variables

Edit .env file:

env
# UI design width
VITE_UI_DESIGN_WIDTH = 1280

# UI design height
VITE_UI_DESIGN_HEIGHT = 740

# postcss-pxtorem rootValue
VITE_PXTOREM_ROOTVALUE = 100

Configure postcss-pxtorem

Edit `.postcssrc.cjs

js
// PostCSS plugins
const autoPrefixer = require('autoprefixer')
const pxtorem = require('postcss-pxtorem')
const vite = require('vite')
module.exports = ({ env }) => {
  const envObj = vite.loadEnv(env, './')
  return {
    plugins: [
      autoPrefixer(),
      pxtorem({
        rootValue: Number(envObj.VITE_PXTOREM_ROOTVALUE) || 16, // Root element font size
        unitPrecision: 5,
        propList: ['*'],
        replace: true,
        mediaQuery: true,
        minPixelValue: 1
      })
    ]
  }
}

Implement Dynamic Root Font Size Adjustment

ts
import { useFullScreenAdapt } from 'havue'
// or
import { useFullScreenAdapt } from '@havue/hooks'
// or
import { useFullScreenAdapt } from '@havue/use-full-screen-adapt'
ts
/**
 * 根据UI设计尺寸,以及当前屏幕尺寸,计算合适的根元素字体大小
 * @param uiWidth UI设计宽度
 * @param uiHeight UI设计高度
 * @param pxtoremRootValue postcss-pxtorem的rootValue值
 * @param stopOnInput 在input聚焦时,停止计算根元素字体大小,固定页面尺寸
 */
export function useFullScreenAdapt(
  uiWidth: number,
  uiHeight: number,
  pxtoremRootValue: number = 16,
  stopOnInput: boolean = false
) {
  const docEl = document.documentElement

  let isStopAdapt: boolean = false

  const stop = () => (isStopAdapt = true)
  const resume = () => (isStopAdapt = false)

  function setBodyFontSize() {
    if (document.body) {
      setRemUnit()
      if (stopOnInput) {
        stopAdaptOnInputFocused(stop, resume)
      }
    } else {
      document.addEventListener('DOMContentLoaded', setBodyFontSize)
    }
  }
  setBodyFontSize()

  /** 更改根元素字体大小 */
  function setRemUnit() {
    if (isStopAdapt) {
      return
    }
    /** UI 设计比例 */
    const uiRatio = uiWidth / uiHeight
    const { clientWidth, clientHeight } = docEl
    /** 屏幕宽高比例 */
    const screenRatio = clientWidth / clientHeight

    let targetWidth = clientWidth
    if (uiRatio > screenRatio) {
      const targetHeight = clientWidth / uiRatio
      targetWidth = targetHeight * uiRatio
    } else {
      targetWidth = uiRatio * clientHeight
    }
    const rem = (targetWidth * pxtoremRootValue) / uiWidth
    docEl.style.fontSize = rem + 'px'
  }

  setRemUnit()

  window.addEventListener('resize', setRemUnit)
  window.addEventListener('pageshow', function (e) {
    if (e.persisted) {
      setRemUnit()
    }
  })

  return {
    stop,
    resume
  }
}

/**
 * 输入时,暂停根元素字体自适应计算
 * @param onFocus
 * @param onBlur
 */
export function stopAdaptOnInputFocused(onFocus: (e?: FocusEvent) => void, onBlur: (e?: FocusEvent) => void) {
  const docEl = document.documentElement
  let oldBodyWidth: string
  let oldBodyHeight: string

  docEl.addEventListener(
    'focus',
    function (e) {
      const target = e.target as HTMLElement
      if (target.tagName === 'INPUT') {
        onFocus()
        const { clientWidth, clientHeight } = docEl
        oldBodyWidth = docEl.style.width
        oldBodyHeight = docEl.style.height

        docEl.style.width = `${clientWidth}px`
        docEl.style.height = `${clientHeight}px`
      }
    },
    { capture: true }
  )
  docEl.addEventListener(
    'blur',
    function (e) {
      const target = e.target as HTMLElement
      if (target.tagName === 'INPUT') {
        onBlur()
        docEl.style.width = oldBodyWidth
        docEl.style.height = oldBodyHeight
      }
    },
    { capture: true }
  )
}

Skip this step if already installed.

Use in Entry File (main.ts)

ts
  useFullScreenAdapt(Number(import.meta.env.VITE_UI_DESIGN_WIDTH), Number(import.meta.env.VITE_UI_DESIGN_HEIGHT), Number(import.meta.env.VITE_PXTOREM_ROOTVALUE) || 16)