You need to enable JavaScript to run this app. 如何实现页面滚动控制的水平Image Accordion(图片手风琴)交互效果?
优惠活动
大模型
产品
解决方案
定价
更多

如何实现页面滚动控制的水平Image Accordion(图片手风琴)交互效果?

滚动控制图片手风琴组件实现方案

实现核心思路

这个效果的本质是「滚动区间锚定+进度映射转换」,核心逻辑如下:

  • 手风琴区域进入视口后先固定在屏幕上,将垂直滚动的进度,转换为手风琴横向展开的进度
  • 提前设置足够高度的占位元素撑开页面,保证滚动条长度匹配手风琴完全展开所需的滚动距离
  • 所有图片完全展开后,解除手风琴的固定定位,页面恢复正常垂直滚动逻辑

基础实现代码(原生JS+CSS,框架场景可直接复用逻辑)

HTML 结构

<!-- 页面其他上方内容 -->
<div class="top-content" style="height: 100vh;"></div>

<!-- 手风琴区域占位符,用来撑开滚动高度 -->
<div class="accordion-placeholder"></div>
<!-- 手风琴主体 -->
<div class="image-accordion">
  <div class="accordion-item"><img src="你的图片地址1" alt="展示图1"></div>
  <div class="accordion-item"><img src="你的图片地址2" alt="展示图2"></div>
  <div class="accordion-item"><img src="你的图片地址3" alt="展示图3"></div>
  <div class="accordion-item"><img src="你的图片地址4" alt="展示图4"></div>
  <!-- 可自行添加更多图片项 -->
</div>

<!-- 页面其他下方内容 -->
<div class="bottom-content" style="height: 100vh;"></div>

CSS 样式

.image-accordion {
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  display: flex;
  overflow: hidden;
}
/* 进入滚动触发区间后添加该类,固定手风琴在视口内 */
.image-accordion.fixed {
  position: fixed;
}
.accordion-item {
  height: 100%;
  /* 收起状态的最小宽度,可自行调整 */
  min-width: 80px;
  transition: width 0.1s linear;
  overflow: hidden;
}
.accordion-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* 占位符高度=图片数量*单张展开所需滚动高度,示例为4张图、每张滚动300px展开,总高1200px */
.accordion-placeholder {
  height: 1200px;
}

JS 交互逻辑

const accordion = document.querySelector('.image-accordion')
const placeholder = document.querySelector('.accordion-placeholder')
const items = document.querySelectorAll('.accordion-item')
const itemCount = items.length
// 单张图片完全展开所需的滚动距离,可自行调整控制滚动灵敏度
const perItemScrollDistance = 300

window.addEventListener('scroll', () => {
  const scrollY = window.scrollY
  // 动态计算触发区间的上下边界,避免页面布局变动导致位置偏移
  const triggerTop = placeholder.offsetTop
  const triggerBottom = triggerTop + placeholder.offsetHeight

  if (scrollY >= triggerTop && scrollY < triggerBottom) {
    // 进入触发区间,固定手风琴
    accordion.classList.add('fixed')
    // 计算当前滚动在触发区间内的进度,范围0-1
    const totalProgress = (scrollY - triggerTop) / placeholder.offsetHeight
    // 计算当前应该展开到第几张图片
    const activeIndex = Math.floor(totalProgress * itemCount)
    // 计算当前正在展开的图片的展开进度,范围0-1
    const currentItemProgress = (totalProgress * itemCount) - activeIndex

    items.forEach((item, index) => {
      if (index < activeIndex) {
        // 已经完全展开的图片,占满整个视口宽度
        item.style.width = '100vw'
      } else if (index === activeIndex) {
        // 当前正在展开的图片,宽度按进度动态计算
        item.style.width = `${80 + (window.innerWidth - 80) * currentItemProgress}px`
      } else {
        // 还未到展开时机的图片,保持收起的最小宽度
        item.style.width = '80px'
      }
    })
  } else if (scrollY >= triggerBottom) {
    // 滚动超出触发区间,解除固定,恢复正常页面滚动
    accordion.classList.remove('fixed')
    // 所有图片保持完全展开状态
    items.forEach(item => item.style.width = '100vw')
  } else {
    // 还未滚动到触发区间,解除固定,所有图片保持收起状态
    accordion.classList.remove('fixed')
    items.forEach(item => item.style.width = '80px')
  }
})

可优化点

  • 用requestAnimationFrame处理样式更新,避免滚动事件高频触发导致的卡顿
  • 加入节流函数减少滚动事件的计算量,不影响流畅度的前提下降低性能消耗
  • 图片添加懒加载逻辑,避免初始加载资源过多影响首屏性能
  • 移动端适配场景可调整收起状态的最小宽度、单张图片所需滚动距离,适配小屏幕显示
  • 如果是Vue/React等框架场景,可将逻辑封装为组件,用响应式数据控制样式,无需直接操作DOM

内容的提问来源于stack exchange,提问作者Wanderson Castro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.10 02:00:05