SafeArea-前端组件设计

365 阅读3分钟

在现代Web开发中,响应式设计是必不可少的,它能让网页在各种设备上都能良好显示。不过,很多人忽略了一个重要细节:如何处理移动设备上的安全区域。特别是那些有刘海屏圆角屏幕的设备,我们需要确保内容不会被遮挡

Insets (边衬区)?

在设计组件之前我们需要了解一个概念, 当我们在移动设备上使用应用程序时,你可能会注意到一些应用的内容并不会贴紧屏幕的边缘,而是留有一些空白区域。这种空白区域被称为Insets,用于确保应用内容不会被遮挡或遮挡其他重要的界面元素

当涉及到移动设备上的显示问题时,env() 函数在CSS中扮演着重要的角色。它允许开发人员访问安全区域插图,这些插图显示了屏幕上内容可以安全显示的区域,从而避免了系统UI元素(例如手机屏幕上的刘海或Home指示器)对内容的干扰

  1. env(safe-area-inset-top) 安全区域距离顶部边界距离
  2. env(safe-area-inset-right) 安全区域距离右边边界距离
  3. env(safe-area-inset-bottom) 安全区域距离底部边界距离
  4. env(safe-area-inset-left) 安全区域距离左边边界距离

什么是 SafeArea?

当您使用 包裹小部件时SafeArea,它会自动向小部件的顶部、底部、左侧或右侧添加填充,具体取决于该设备上的系统 UI。这意味着,如果您针对具有凹槽或特殊显示功能的设备,SafeArea则会动态调整布局以适应安全边界

safeArea 使用场景

  1. 设备多样性:由于各种设备具有不同的屏幕配置,SafeArea因此确保您的应用在所有设备上都看起来不错。

  2. 复杂布局:如果您的 UI 具有复杂的设计或多个组件,使用SafeArea可以防止内容被系统 UI 元素遮挡。

  3. 全屏模式:在您可能切换全屏模式的应用程序中(例如游戏或视频播放器),SafeArea确保内容仍然可见

如何设计 safeArea

interface ISafeAreaProps {
  position: 'top' | 'bottom'
  className?: string
  style?: React.CSSProperties
}

const SafeArea: React.FC<ISafeAreaProps> = props => {
  const { position, className, style } = props

  const styleMap = {
    top: {
      paddingTop: 'env(safe-area-inset-top)',
    },
    bottom: {
      paddingBottom: 'env(safe-area-inset-bottom)',
    },
  }

  return (
    <div
      className={classNames('w-full', 'block', className)}
      style={{
        ...styleMap[position],
        ...style,
      }}
    />
  )
}

兼容性如何处理

在 rem 布局下,SafeArea 高度很小怎么办?

如果整体缩放为了 0.5 倍,你可以将 --adm-safe-area-multiple 设置为 2

:root {
  --adm-safe-area-multiple: 2; /* 根据整体缩放倍数进行调整 */
}

应用到 SafeArea 元素

interface ISafeAreaProps {
  position: 'top' | 'bottom'
  className?: string
  style?: React.CSSProperties
}

const SafeArea: React.FC<ISafeAreaProps> = props => {
  const { position, className, style } = props

  const styleMap = {
    top: {
      paddingTop: 'calc(env(safe-area-inset-top) * var(--adm-safe-area-multiple))',
    },
    bottom: {
      paddingBottom: 'calc(env(safe-area-inset-bottom) * var(--adm-safe-area-multiple))',
    },
  }

  return (
    <div
      className={classNames('w-full', 'block', className)}
      style={{
        ...styleMap[position],
        ...style,
      }}
    />
  )
}

  env() 不起作用该怎么办?

注意:当 viewport-fit=contain 时,env() 是不起作用的,必须要配合 viewport-fit=cover 使用。对于不支持 env() 的浏览器,浏览器将会忽略它。

<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=contain">