css 实现刘海屏样式兼容并支持 js 获取刘海屏高度后动态修改
css
:root { --safe-area-inset-top: 0px; --safe-area-inset-right: 0px; --safe-area-inset-bottom: 0px; --safe-area-inset-left: 0px; --safe-area-inset-constant-top: 0px; --safe-area-inset-constant-right: 0px; --safe-area-inset-constant-bottom: 0px; --safe-area-inset-constant-left: 0px; } @supports (top: env(safe-area-inset-top, 44px)) { :root { --safe-area-inset-top: env(safe-area-inset-top, 44px); --safe-area-inset-right: env(safe-area-inset-right, 34px); --safe-area-inset-bottom: env(safe-area-inset-bottom, 34px); --safe-area-inset-left: env(safe-area-inset-left, 34px); } } @supports (top: constant(safe-area-inset-top)) { :root { --safe-area-inset-constant-top: constant(safe-area-inset-top); --safe-area-inset-constant-right: constant(safe-area-inset-right); --safe-area-inset-constant-bottom: constant(safe-area-inset-bottom); --safe-area-inset-constant-left: constant(safe-area-inset-left); } }
首先设置 css 根属性变量值,如果是 less,通过 calc 计算出增加刘海屏高度后的值,注意 calc 计算不支持不带单位的数字相加,会导致结果为 0 ,所以一定要处理不带单位的场景。
由于安卓不支持 constant css 函数,以及安卓 9 以下低版本系统不支持 env css 函数,会导致获取的结果为 0 从而导致 calc 计算结果也为 0 ,所以要在初始化写为 0px,则通过 css @supports 来判断支持 constant 和 env 函数的情况下再赋值刘海屏高度值。
js 通过与iOS 和安卓的接口获取到客户端返回的实际刘海屏的高度,当返回的高度存在时,则重新赋值 root 跟元素的变量,否则用浏览器默认的。
这样实现的目的是为了解决部分机型下,env 函数和 constant 函数都获取失败导致无法处理刘海屏高度的场景。
js vue3 代码
import { readonly, reactive, watch, ref } from 'vue' import { setRootProperty } from '@/common/util' export default { install: (app) => { const config = reactive({}) const insets = ref({ top: 0, left: 0, bottom: 0, right: 0 }) if (window.getSafeAreaInsets && typeof window.getSafeAreaInsets === 'function') { insets.value = window.getSafeAreaInsets() // 初始化获取刘海屏值 } const setConfigAreaInsets = () => { config.areaInsets = insets.value } const updateInsets = (top, left, bottom, right) => { insets.value = { top, left, bottom, right } } function applySafeInsets() { if (!window.EVENTS.safeAreaInsetsChange) { return false } setConfigAreaInsets() ;['top', 'right', 'bottom', 'left'].forEach(prop => { setRootProperty(`--safe-area-inset-${prop}`, `${insets.value[prop]}px`) setRootProperty(`--safe-area-inset-constant-${prop}`, `${insets.value[prop]}px`) }) } watch(insets, (val) => { applySafeInsets() }) app.mixin({ mounted() { applySafeInsets() if (this === this.$root) { window.mraid.addEventListener('safeAreaInsetsChange', updateInsets) } }, beforeUnmount() { if (this === this.$root) { window.mraid.removeEventListener('safeAreaInsetsChange', updateInsets) } } }) app.config.globalProperties.$config = config app.provide('config', readonly(config)) } }