如何处理 Next.js 中不受支持的 CSS 属性或在 Chakra-UI 中使用 @supports 指令

How to handle unsupported CSS properties in Next.js or use @supports directives in Chakra-UI

我正在使用 React component 根据是否支持 CSS backdrop-filter 指令使用不同的不透明度值:

background={(() => {
  const opacity = isBackdropFilterSupported() ? 0.75 : 0.98
  return (
    `linear-gradient(
      180deg, rgba(76, 63, 143, ${opacity}) 62.76%,
      rgba(184, 169, 255, ${opacity}) 100%
    )`
  )
})()}

问题是网站是使用 Next.js 在服务器端生成的。 CSS.supports('backdrop-filter', 'blur(1px)') returns false 在服务器上,因此无论客户端属性如何,该值始终为 false

一种解决方案是使用 CSS,例如:

.drawer {
  --opacity: 0.75;
  background: linear-gradient(
    180deg, rgba(76, 63, 143, var(--opacity)) 62.76%,
    rgba(184, 169, 255, var(--opacity)) 100%
  );
}
@supports not (backdrop-filter: blur(1px)) {
  .drawer { --opacity: 0.98; }
}

这应该由客户端解释并避免服务器端呈现问题,但我没有发现关于如何将这种样式集成到它所基于的 Chakra-UI 中的指示。

我在原来的 post 中没有提到它,但我收到了如下错误:Prop id did not match. Server: "toggle--gxfg3t7xwo" Client: "toggle--ki0j10p2l"

原来这意味着浏览器生成的 DOM 与 Next.js 生成的 DOM 不匹配。发生这种情况时 Next.js 放弃尝试重新水合文档,这就是我获取服务器呈现值的原因。

解决方案是使用挂钩来确定组件何时安装(这只发生在客户端)。那个钩子看起来像:

export const useMounted = () => {
  // https://www.joshwcomeau.com/react/the-perils-of-rehydration/
  const [hasMounted, setHasMounted] = React.useState(false);
  React.useEffect(() => {
    setHasMounted(true);
  }, []);
  return hasMounted;
};

然后不透明度的确定变成:

const hasMounted = useMounted()
⋮
const opacity = hasMounted && isBackdropFilterSupported() ? 0.75 : 0.98