如何实现点击子Div后平滑滚动居中并展开占满父容器?
问题描述
我有1个父div和4个子div,4个子div默认均分父容器空间;点击任意子div时,该子div要展开占满父容器,同时父容器变为可水平滚动状态。现在的问题是点击后子div无法平滑滚动到屏幕中心并吸附居中,之前用scrollIntoView方法没生效。
解决方案
问题核心是先执行滚动再修改布局,导致滚动计算基于旧的元素尺寸,同时scrollIntoView的执行时机没跟上DOM布局更新。以下是修复方案:
关键修复点
- 调整执行顺序:先给目标子元素添加
active类更新布局,再等待DOM重绘完成后执行滚动操作 - 修正flex属性:避免
flex-grow导致的布局异常,确保激活的子元素固定占满父容器宽度 - 全局滚动吸附:给所有子元素添加滚动吸附规则,提升交互一致性
修改后的完整代码
JavaScript
const items = document.querySelectorAll(".wrapper"); items.forEach((item) => { item.addEventListener("click", () => { // 单选逻辑:移除其他子元素的active类 items.forEach(i => i.classList.remove("active")); // 给当前点击的子元素添加active类,触发布局更新 item.classList.add("active"); // 等待DOM重绘完成后执行滚动,确保基于新布局计算位置 requestAnimationFrame(() => { item.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" }); }); }); });
CSS
.container-selection { display: flex; flex-direction: row; justify-content: space-evenly; align-items: center; min-height: calc(100% - var(--l-footer-height) - 5.5rem); padding-top: 1rem; padding-bottom: 1rem; gap: 1rem; padding-inline: 1rem; overflow-x: scroll; scroll-snap-type: x mandatory; scroll-behavior: smooth; } .container-selection .selection { display: flex; flex: 1 1 0; flex-direction: column; justify-content: center; align-items: center; align-self: stretch; border-radius: 1.5rem; font-weight: bold; gap: 1rem; min-width: calc(25vw - 2rem); user-select: none; -moz-user-select: none; -webkit-user-select: none; transition: flex 0.3s ease; } .container-selection::-webkit-scrollbar { display: none; } .wrapper { display: flex; align-self: stretch; flex: 1 1 0; /* 默认均分父容器空间 */ scroll-snap-align: center; /* 默认支持滚动吸附 */ transition: all 300ms ease; } .wrapper.active { flex: 0 0 100%; /* 固定占满父容器宽度,避免flex-grow异常 */ scroll-snap-align: center; /* 激活后依然保持滚动吸附 */ }
HTML
<div class="container-selection"> <div class="wrapper"> <div class="selection glass" id="admin"> <img src="<?= ADMIN_ICON ?>" alt="admin icon"> <span>ADMIN</span> </div> </div> <div class="wrapper"> <div class="selection glass" id="official"> <img src="<?= OFFICIAL_ICON ?>" alt="official icon"> <span>OFFICIAL</span> </div> </div> <div class="wrapper"> <div class="selection glass" id="faculty"> <img src="<?= FACULTY_ICON ?>" alt="faculty icon"> <span>FACULTY</span> </div> </div> <div class="wrapper"> <div class="selection glass" id="nonteaching"> <img src="<?= NONTEACHING_ICON ?>" alt="nonteaching icon"> <span>NON-TEACHING</span> </div> </div> </div>
原理说明
requestAnimationFrame:等待浏览器完成下一帧重绘后执行滚动,此时.wrapper.active的新尺寸已经生效,scrollIntoView能计算出正确的滚动位置flex: 0 0 100%:固定激活子元素的宽度为父容器100%,避免flex-grow导致父容器宽度被额外撑开,保证滚动逻辑正常- 全局
scroll-snap-align: center:无论子元素是否激活,都能在滚动时自动吸附到容器中心,提升交互流畅度
内容的提问来源于stack exchange,提问作者John Lee Ingua
相关产品推荐
相关产品推荐

