用户代理嗅探是最流行的浏览器检测方法。不幸的是,由于多种原因,前端开发不太容易使用它。浏览器供应商不断尝试让嗅探变得不可能。因此,每个浏览器都有自己的用户代理字符串格式,解析起来非常复杂。
有一种更简单的方法可以使用浏览器 CSS API 实现相同的目的,我将向您展示。那么让我们创建浏览器功能检测 React hook。
我们将使用 CSS.supports() 静态方法。它返回一个布尔值,指示浏览器是否支持给定的 CSS 功能。这是 @supports at-rule 的 javascript 模拟。它的工作原理与媒体查询类似,但以 CSS 功能为主题。
在组件渲染周期中调用 CSS.supports() 的最简单方法会在服务器端渲染环境(例如 Next.js)中产生问题。因为服务器端渲染器无法访问浏览器 API,所以它只是生成一串代码。
import type {FC} from 'react'; const Component: FC = () => { // ? Don't do this! const hasFeature = CSS.supports('your-css-declaration'); // ... }
我们将使用这个简单的钩子。该钩子接收一个包含support条件的字符串,这是我们要验证的CSS规则,例如显示:弯曲。
import {useState, useEffect} from 'react'; export const useSupports = (supportCondition: string) => { // Create a state to store declaration check result const [checkResult, setCheckResult] = useState(); useEffect(() => { // Run check as a side effect, on user side only setCheckResult(CSS.supports(supportCondition)); }, [supportCondition]); return checkResult; };
现在我们可以从 React 组件内部检查不同的 CSS 功能支持。这是 MDN @supports 参考
import type {FC} from 'react'; const Component: FC = () => { // Check for native `transform-style: preserve` support const hasNativeTransformSupport = useSupports(' (transform-style: preserve) '); // Check for vendor prefixed `transform-style: preserve` support const hasNativeTransformSupport = useSupports(' (-moz-transform-style: preserve) or (-webkit-transform-style: preserve) '); // ... }
为了检测用户浏览器,我们必须进行一些黑客攻击。
浏览器黑客攻击与违法行为无关。它只是一个特殊的 CSS 声明或选择器,在可用浏览器之一中的工作方式有所不同。
这是包含各种浏览器黑客的参考页面。在我的机器上进行彻底的实验后,我选择了这些:
const hacksMapping = { // anything -moz will work, I assume firefox: '-moz-appearance:none', safari: '-webkit-hyphens:none', // tough one because Webkit and Blink are relatives chrome: ' not (-webkit-hyphens:none)) and (not (-moz-appearance:none)) and (list-style-type:"*"' }
这是我们最终的钩子:
export const useDetectBrowser = () => { const isFirefox = useSupports(hacksMapping.firefox); const isChrome = useSupports(hacksMapping.chrome); const isSafari = useSupports(hacksMapping.safari); return [ {browser: 'firefox', condition: isFirefox}, {browser: 'chromium based', condition: isChrome}, {browser: 'safari', condition: isSafari}, ].find(({condition}) => condition)?.browser as 'firefox' | 'chromium based' | 'safari' | undefined; };
这是该钩子的完整工作演示。
我不能说这是一种万无一失、稳定的方法。浏览器经常更新,供应商属性经常被放弃或被标准取代。同时,我可以说一下用户代理嗅探。两种方式都有类似的问题。但 CSS.contains() 更容易维护,而且更细粒度。它欢迎开发人员使用优雅降级或渐进增强方法并精细地应用补丁。
免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。
Copyright© 2022 湘ICP备2022001581号-3