因为我们的项目是用Taro写的,所以下面的代码是用tsx代码,如果是头条原生代码编写,改一改就行,原理一致

经过前期的一些尝试和调研发现:字节小程序它不是不支持env(safe-area-inset-bottom),而是使用这个属性得到的值是0。 使用 tt.getSystemInfoSync可以获取到设备的上下的安全距离(safeArea)。

我们不妨想这么一个思路。

  1. 全局定义一个CSS变量,默认值设置为 env(safe-area-inset-bottom)(方便未来某一天小程序支持了这个属性我们去除)

  2. 定义一个Wrapper组件去包装一下页面组件(也可以不定义wrapper组件,我这里定定义是为了抹平多端小程序,也为了方便以后去除。)

    1. 使用 tt.getSystemInfoSync获取到设备的上下的安全距离(safeArea

    底部安全距离计算公式: safeAreaBottomHeight = safeArea.bottom - safeArea.height

    1. 将底部安全距离的数值赋值给刚才全局定义的css变量
  3. 至此,所有CSS中需要用到 env(safe-area-inset-bottom)的地方使用 var(全局css变量)即可。如: padding-bottom: var(--safe-area)

    所有用到这个变量的页面都需要使用 Wrapper 组件包装一下

定义全局CSS变量

// app.scss
:global {
  --safe-area: env(safe-area-inset-bottom);
}

创建Wrapper组件并在内部修改CSS变量的值

// Wrapper.tsx
import React from 'react'
import { View } from '@tarojs/components'
import { getSystemInfoByKey } from '@src/utils/native/device'

function getSystemInfoByKey<TKey extends keyof DeviceProps>(key: TKey) {
  const props = Taro.getSystemInfo()
  return props[key]
}

const safeAreaInfo = getSystemInfoByKey('safeArea')

export default function Index(props: { children: React.ReactNode }) {
  const safeAreaHeight = `${safeAreaInfo.bottom - safeAreaInfo.height}px`
  return (
    <View style={
      {
        // @ts-ignore
        '--safe-area': safeAreaHeight,
      }
    }
    >
      {props.children}
    </View>
  )
}

使用Wrapper组件

import React from 'react'
import Wrapper from './components/Wrapper' // Wrapper组件
import Page from '../Index' // 页面组件

export default () => (
  <Wrapper>
    <Page />
  </Wrapper>
)

使用CSS变量

这里只是举例说明,根据你的需求使用即可。

实现一个设置底部安全区域的 SCSS方法

@mixin safeAreaPaddingBottom($paddingBottom: 0px) {
  @if $paddingBottom==0px {
    padding-bottom: constant(safe-area-inset-bottom);
    padding-bottom: var(--safe-area);
  }

  @else {
    padding-bottom: calc(#{$paddingBottom} + constant(safe-area-inset-bottom));
    padding-bottom: calc(#{$paddingBottom} + var(--safe-area));
  }
}


.box {
	@include safeAreaPaddingBottom()
}