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加载完毕之后再操作dom
this.$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*80
sidebar.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 好不好
以上就是我的全部思路了,只能说太难了…