修复移动端(触摸设备)看板垂直滚动异常问题
问题描述
我有一个看板,响应式模式下每次仅显示一列。已在父容器添加列吸附属性scroll-snap-type: x mandatory;,并给每个子元素设置scroll-snap-align: center;。水平滚动运行正常,但在真实移动端尝试垂直滚动单列内容时,内容会出现错乱跳转。
- 问题仅出现在真实移动端,桌面端无此现象
- 期望实现类似原生Trello应用的效果
- 寻求纯CSS解决方案,或CSS+JS组合方案
相关代码
CSS
.app-board-card { position: relative; box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 4px;; border-radius: 5px; padding: 10px 10px 0; cursor: pointer; background: #fff; display: grid; grid-template-columns: 1fr 1fr; grid-gap: 7px; visibility: visible; transform: translateZ(0); margin-top: 7px; } .app-board-columns { list-style-type: none; padding: 0; display: flex; flex-flow: row; align-items: flex-start; margin: 0; } @media only screen and (max-width: 767px) .app-board-columns { display: grid; grid-auto-flow: column; gap: 1rem; overflow-y: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch; } .app-board-column { background: #fff; border-radius: 5px; padding: 5px 0 0; width: 330px; max-width: 330px; margin: 0 10px 5px 0; position: relative; transform: translateZ(0); flex: 1 0 auto; height: 100%; display: flex; flex-flow: column; } @media only screen and (max-width: 767px) .app-board-column { width: 260px; max-width: 260px; scroll-snap-align: center; } .app-board-column-inner-scroll { display: flex; flex-flow: column; overflow-x: hidden; overflow-y: scroll; } .app-board-column-inner { display: flex; flex-flow: column; padding: 20px 0 60px 15px; min-height: 150px; flex: 1 0 auto; } @media only screen and (max-width: 767px) .app-board-column-inner { padding-right: 15px; } .app-board-column.col1 .app-board-card { background-color: #fdc6c4; } .app-board-column.col2 .app-board-card { background-color: #d8edff; } .app-board-column.col3 .app-board-card { background-color: #eee; } /* For demo only */ .app-board-column:after { color: gray; content: ".app-board-column"; } .app-board-column { border: thin dashed blue; min-height: 10rem; } .app-board-card { min-height: 70px; }
HTML
<ul class="app-board-columns"> <li class="app-board-column col1"> <div class="app-board-column-inner-scroll"> <div class="app-board-column-inner"> <article class="app-board-card"></article> <article class="app-board-card"></article> <article class="app-board-card"></article> <article class="app-board-card"></article> <article class="app-board-card"></article> <article class="app-board-card"></article> <article class="app-board-card"></article> <article class="app-board-card"></article> <article class="app-board-card"></article> </div> </div> </li> <li class="app-board-column col2"> <div class="app-board-column-inner-scroll"> <div class="app-board-column-inner"> <article class="app-board-card"></article> <article class="app-board-card"></article> <article class="app-board-card"></article> <article class="app-board-card"></article> <article class="app-board-card"></article> <article class="app-board-card"></article> <article class="app-board-card"></article> <article class="app-board-card"></article> <article class="app-board-card"></article> </div> </div> </div> </li> <li class="app-board-column col3"> <div class="app-board-column-inner-scroll"> <div class="app-board-column-inner"> <article class="app-board-card"></article> <article class="app-board-card"></article> <article class="app-board-card"></article> <article class="app-board-card"></article> <article class="app-board-card"></article> <article class="app-board-card"></article> <article class="app-board-card"></article> <article class="app-board-card"></article> <article class="app-board-card"></article> </div> </div> </div> </li> </ul>
解决方案
1. 修复CSS语法错误
原代码中的媒体查询写法存在语法错误(缺少包裹样式的大括号),会导致移动端样式无法正确解析,先修正:
/* 修正后的媒体查询结构 */ @media only screen and (max-width: 767px) { .app-board-columns { display: grid; grid-auto-flow: column; gap: 1rem; overflow-y: hidden; /* 后续会解释修改这个属性的原因 */ overscroll-behavior-x: contain; scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch; } .app-board-column { width: 260px; max-width: 260px; scroll-snap-align: center; } .app-board-column-inner { padding-right: 15px; } }
2. 解决滚动冲突核心问题
移动端触摸滚动冲突是错乱跳转的根源:父容器(.app-board-columns)原本设置了overflow-y: auto,加上-webkit-overflow-scrolling: touch的触摸滚动优化,会导致垂直滚动时触摸事件被父容器干扰,结合scroll-snap的强制吸附就会出现跳转。
关键CSS调整:
/* 父容器:仅保留水平滚动能力 */ @media only screen and (max-width: 767px) { .app-board-columns { overflow-y: hidden; /* 移除垂直滚动,避免干扰子容器 */ overscroll-behavior-y: contain; /* 隔离垂直滚动事件,防止冒泡到页面 */ } } /* 子列滚动容器:确保高度正确并添加触摸优化 */ .app-board-column { height: 100vh; /* 根据页面布局设置高度,比如减去头部高度可以用calc(100vh - 60px) */ } .app-board-column-inner-scroll { flex: 1; /* 占满列的剩余空间,确保滚动容器高度正确 */ -webkit-overflow-scrolling: touch; /* 给子容器添加触摸滚动流畅度优化 */ }
3. 可选JS增强方案(若CSS方案仍有轻微冲突)
如果移动端仍存在偶尔的滚动干扰,可以添加少量JS来临时禁用父容器的scroll-snap:
// 给每个子滚动容器绑定触摸事件 document.querySelectorAll('.app-board-column-inner-scroll').forEach(container => { container.addEventListener('touchstart', () => { // 触摸子容器时,临时关闭父容器的scroll-snap document.querySelector('.app-board-columns').style.scrollSnapType = 'none'; }); container.addEventListener('touchend', () => { // 触摸结束后恢复scroll-snap setTimeout(() => { document.querySelector('.app-board-columns').style.scrollSnapType = 'x mandatory'; }, 100); }); });
效果说明
修改后,移动端垂直滚动单列内容时,触摸事件会被子滚动容器完全捕获,父容器的水平scroll-snap不会干扰垂直滚动,同时保持水平切换列时的吸附效果,和原生Trello应用的体验一致。
内容的提问来源于stack exchange,提问作者Art
相关产品推荐
相关产品推荐

