这两天公司一位妹子问我,“我这边调试的时候本地显示没问题,到手机端就有问题,该怎么办呢?”测试环境没问题到线上就有问题了?对此我也很纳闷。下图是复现的效果图,这个是一个用户选择组件,当点击按钮的时候,弹窗框可以选择用户,当点击按钮后蒙层并没有覆盖全屏。
选择用户按钮点击按钮后问题分析组件代码
importReact,{useState}from"react";exportdefaultfunctionApp({children}){const[visivle,setVisivle]=useState(false)return(spanonClick={()=setVisivle(true)}{children}/span{visivle?divclassName="fixed".../div:null}/);}
我们知道,position:fixed在日常的页面布局中非常常用,在许多布局中起到了关键的作用。它的作用是:
position:fixed的元素将相对于屏幕视口(viewport)的位置来指定其位置。并且元素的位置在屏幕滚动时不会改变。
但是在某些特定场景下,指定了position:fixed的元素却无法相对于屏幕视口进行定位。
MDN[1]中有句话对这些特定场景做了解释:
当元素祖先的transform,perspective或filter属性非none时,容器由视口改为该祖先。
其实并不是本地不能复现,只不过这个表单是用户创建的,只有当该选择组件在Tab组件内部的时候%复现。在上面代码中,就是因为在Tab中使用了transform:translate3d(0,0,0)属性,所以会在该场景下失效。
失效的position:fixed比如下面一个最简单的代码
divid="app"divclass="fixed"/dix/div
#app{width:px;height:px;transform:scale(1);}.fixed{position:fixed;background:blue;top:0;left:0;right:0;bottom:0;}失效的position:fixed
本来应该全屏的div,消失了,上述代码中transform:scale(1);也会导致position:fixed失效,那么,为什么会发生这种情况呢?
这就涉及到了StackingContext,也就是堆叠上下文的概念了。解释上面的问题分为两步:
任何非none的transform值都会导致一个堆叠上下文(StackingContext)和包含块(ContainingBlock)的创建。
由于堆叠上下文的创建,该元素会影响其子元素的固定定位。设置了position:fixed的子元素将不会基于viewport定位,而是基于这个父元素。
解决办法那么要如何解决呢?我开发的是一个公共组件,总不能要求使用组件的父元素都不使用transform,perspective或filter这些属性吧?
是不是直接将弹窗插入到body下就可以了呢?
在React中提供了createPortal方法,该方法可以将子节点渲染到存在于父组件以外的DOM节点中
所以我们可以改一下组件代码:
importReact,{useState,useRef,useEffect}from"react";import{createPortal}from"react-dom";exportdefaultfunctionApp({children}){const[visivle,setVisivle]=useState(false);constnode=useRef();useEffect(()={node.current=document.createElement("div");document.body.appendChild(node.current);return()={if(node.current){node.current.remove();}};},[]);return(spanonClick={()=setVisivle(true)}{children}/span{visivlenode.current?createPortal(divclassName="fixed".../div):null}/);}
这样就可以解决position:fixed失效的问题,当然,因为在body元素下,可以使用position:absolute代替。
position:fixed的其他问题position:fixed还有一些其他问题,比如在移动端实现头部、底部模块定位。或者是在position:fixed中使用了input也会存在一些问题,可以看下这篇文章:移动端web页面使用position:fixed问题总结[]
借用了前端胖头鱼的首图。以上就是本文全部内容,希望这篇文章对大家有所帮助,也可以参考我往期的文章或者在评论区交流你的想法和心得,欢迎一起探索前端。
[1]mdnposition: