当前位置: 首页 > Web前端 > CSS

css-vars-ponyfill在ie环境下使用(nextjs搭建)

时间:2023-03-31 01:09:49 CSS

{styles}css-vars-ponyfill使用css变量实现网页换肤,会存在兼容性问题。为了解决ie、qq、百度浏览器等的兼容性问题,引入了css-vars-ponyfill,但是在ie浏览器下,css-vars-ponyfill在nextjs下表现不佳,主要缺陷是页面由服务端渲染,所以用户看到界面后,动态主题颜色等样式无法快速渲染,但是有一个过渡时间(css-vars-ponyfill只支持client-side),颜色会有一个明显的替换过程。用户体验差。通过阅读源码可以看出,cssVars只有在浏览器contentLoaded时才会被触发,否则会一直监听dom的data内容事件,会导致体验问题。解决方案1.解析速度直接去掉document.readyState!=='loading'等限制,浏览器就可以解析了,然后改变css-vars-ponyfill的引入方式(老的引入方式在nextjs中引入moduleinmainjs,然后直接调用cssVars(),这样其他不相关的chunk会在调用ponyfill脚本之前解析.为了更快的解析css变量,需要手动选择插入位置),修改后的css-vars-ponyfill找到css变量的位置(nextjs将不同组件下的样式打包在header中),然后将改变的ponyfill插入到样式中调用。此步骤选择文件中服务器端更改呈现的_document.tsx。2、解析稳定性通过手动更改文件解析位置,并对源码的条件触发机制进行相关修改,在一定程度上提高了首页的显色速度。但是还有一个问题,就是如果界面中有新的stylechunk通过路由跳转,插入时无法进行有效的css变量解析(我试过配置cssVars的选项开启MutationObserver)。因此,解决方案是通过判断UA,让ie等浏览器下的所有路由都跳转a标签,触发css-ponyfill的重新解析和执行。exportfunctionbrowser(){constUA=window.navigator.userAgentif(UA.includes("qqbrowser"))return"qqbrowser"if(UA.includes("baidu"))return"baidu"if(UA.includes("Opera"))如果(UA.includes("Edge"))返回"Opera"如果(UA.includes("MSIE")||(UA.includes("Trident")&&UA.includes(“rv:11.0”)))如果(UA.includes(“Firefox”))返回“IE”如果(UA.includes(“Chrome”))返回“Firefox”如果(UA.includes(“Safari”"))return"Safari"}typeCommonLinkProps={children:ReactElementhref?:stringtarget?:stringouterLink?:booleanstyles?:unknown}exportdefaultfunctionCustomLink(props:CommonLinkProps){const{children,href,target,as,outerLink,styles=emptyStyles}=propsconst[isIE,setIE]=useState(false)constcloneEl=(c:ReactElement,props?:any)=>React.cloneElement(c,{href:as??href,target,...props})useEffect(()=>{if(["IE","qqbrowser","baidu"].includes(browser())){setIE(true)}},[])functionrenderLink(){if(Children.only(children).type==="a"){constnode=cloneEl(childrenasReactElement)returnnode}else{letfn:()=>void|null=nullif(outerLink){fn=()=>{window.open(as??href)}}else{fn=()=>{window.location.href=??href}}constnode=cloneEl(childrenasReactElement,{onClick:()=>{fn()},})returnnode}}return(<>{!href?(children):isIE?(renderLink()):({children})}{styles})}这里选择了ReactElement作为children的类型,而不是通常slots支持的ReactNode,主要是不想考虑直接插入字符串的情况,这样会增加复杂度问题,所以直接限制在类型层Fragments也不考虑,找不到有效的Fragments类型,所以在ReactNode中是不可能Omit的。如果nextjs中的Link插入到第一层的Fragments中,是不能正常跳转的,可能的原因是不能放在Fragments中。绑定有效事件,目前Fragments(16.13.1)只支持key属性,希望以后可以优化。