CSS transform 使 fixed 定位失效?
1. 最终实现效果如下
看似简单的一个动画,却出现了种种bug,也不叫bug,毕竟是W3C官方的嘛,整整耗费了我一下午的时间去搞它。
2. 布局样式(关键点)
先来看一下我的布局吧
首先index_bar_container
是cl_header
的父元素(坑)就先看这个父子关系吧,其他的都一样了
<!-- 收藏位置弹窗 start --><div v-if="show" :class="isShow ? 'index_bar_container ' + overhidden : 'index_bar_container cl_show'"><!-- 头部 start --><div :class="isShow ? 'cl_header ' + clhpos : 'cl_header cl_show ' + clhpos"><span class="cl_text">请选择收藏位置</span><van-icon class="cl_close" :name="require('@/assets/关闭.svg')" @click="onCClose"></van-icon></div><!-- 头部 end --><!-- 当前壁纸信息 start -->此处省略...<!-- 当前壁纸信息 end --><!-- indexBar 索引栏 start -->此处省略...<!-- indexBar 索引栏 start --></div><!-- 收藏位置弹窗 end -->
我把没用的代码都删了,方便阅读
再来看看我的样式
.cl_show {display: none !important;}.index_bar_container {background: #fff;position: fixed;left: 0;top: 0;right: 0;bottom: 0;margin: auto;width: 300px;height: 439px;border-radius: 14px;overflow: scroll;padding: 0 4.5px;z-index: 10;animation: rotateInDownLeft 1s;}/* 禁止滚动 */.overhidden {overflow: hidden;}.index_bar {position: relative;left: 0;top: 0;font-size: 13px;color: #101010;font-weight: 700;}/* cl_header 共同样式 */.cl_header {/* width: 300px; */height: 84px;background: #fff;border-radius: 14px;display: flex;align-items: center;padding: 0 0px 0 16px;color: #101010;z-index: 11;}/* cl_header fixed 定位布局样式 */.cl_header_fixed {position: fixed;left: 37.5px;}/* cl_header 非 fixed 定位布局样式 */.cl_header_abs {position: absolute;left: 0;top: 0;}@keyframes rotateInDownLeft {0% {transform-origin: left bottom;transform: rotate(-90deg);opacity: 0;}100% {transform-origin: left bottom;transform: rotate(0);opacity: 1;}}
注意动画中是使用了
transform
属性的,不仅transform
能够使fixed
定位失效,变成absolute
的效果,rotate
,scale
等等属性也能够使fixed
定位失效
好了,扯了这么多主要是给不知道原因的人看的,接下来请看我的解决方案吧!
3. 另类解决 transform 使 fixed 定位失效问题
监听那个点击事件,无论什么方式都好首先要知道transform 只会使 fixed 定位失效那么我可以在动画开始时使当前元素的定位为absolute
或者relative
即可,我用的是absolute
并且在动画执行时是不可以让用户操作的,我使用的是overflow: hidden;
在动画结束后把absolute
再变回fixed
定位,把overflow
变回scroll
即可实现无缝切换最后就是,在动画关闭后即可 v-if 删除当前 dom ,防止当前 dom 保存当前状态,使再次进行动画时,布局出现暂时性(1100ms)失效data() {return {clhpos: "cl_header_fixed",overhidden: "overhidden",}}watch: {show(val, oldVal) {console.log(val);// 保证dom加载完毕之后再操作domthis.$nextTick(()=>{if(val == true) {this.clhpos = "cl_header_abs"this.overhidden = "overhidden"let indexBar = this.$refs.indexBar.$el;let sidebar = indexBar.getElementsByClassName("van-index-bar__sidebar")[0];// 当前 1rem 等于 37.5px// 当前页面宽度相对于 750 宽的缩放比例,可根据自己需要修改.let top = 1/37.5*80sidebar.setAttribute("style", `position: absolute; right: 0; top: ${top}rem; `);// console.log(sidebar);setTimeout(()=>{this.clhpos = "cl_header_fixed"this.overhidden = ""sidebar.setAttribute("style", "");}, 1100)}})}}
不知道用 watch 好不好
以上就是我的全部思路了,只能说太难了…