描述
一种2023年很流行的页面布局方式。bilibili的视频播放页。知乎的文章页都是类似设计。类似品字大致可以分为
- 最顶部的内容
- body主内容,分为左右两侧。
当页面主体部分小于一屏高度时,页面看上去和正常流式布局类似。
当页面主体部分大于一屏高度时。
如果是页面主体左侧大于一屏高度。当页面主体右侧滚动到浏览器顶部时会吸顶,并随之滚动。当主体右侧内容滚动到底时,吸附在浏览器底部
如果是页面主体右侧内容大于一屏高度。页面看上去和正常流式布局类似
核心代码
简化html结构
<div id="home-root"> // 起到类似html的作用占满全屏,100hv+100vw
<div id="home-page"> // 容器,垂直方向排列的弹性盒子
<header class="home-header" id="home-header">
// 见style
<div class="home-header-container">
</div>
</header>
<main id="home-main">
// 见style
<div>
<header class="main-layout-header">
// 姑且认为这里随便占位了些内容
</header>
<main class="main-layout-main">
<div class="profile-body">
<div class="profile-body-left">
// 一般的弹性盒子
</div>
<div class="profile-body-right">
// 一般的弹性盒子
<div class="profile-body-right-container" style="isSticky && {
top: stickyTop + 'px'
}">
</div>
</div>
</div>
</main>
</div>
</main>
</div>
</div>
<style>
#home-header {
position: sticky;
top: 0;
}
#home-main {
flex: auto;
// 默认占满剩下内容的容器
}
</style>
const bodyRightRef = ref<HTMLDivElement>(null);
const bodyRightContainerRef = ref<HTMLDivElement>(null);
const homeRootDom = document.getElementById('home-root');
const pageHeaderDom = document.getElementById('home-header');
const stickyTop = ref(0);
const isSticky = ref(false);
useEventListener(homeRootDom, 'scroll', throttle(() => {
const el = bodyRightContainerRef.value;
const bodyEl = bodyRightRef.value;
if (!el || !bodyEl) {
return;
}
stickyTop.value = window.innerHeight > el.clientHeight
? pageHeaderDom.offsetHeight // 这样才能看上去吸在header下面
: window.innerHeight - el.offsetHeight;// 动态计算右侧下部吸底时的样式
const {
height,
} = el.getBoundingClientRect();
const { top: bodyTop } = bodyEl.getBoundingClientRect();
const distance = window.scrollY + window.innerHeight - bodyTop - height;// 计算右侧内容是否吸底
isSticky.value = distance >= 0 && bodyTop <= 0;// 计算右侧内容吸底||吸顶启动sticky布局
}, 1000 / 144));