自动卡片滑块最左侧卡片显示不全,寻求修复方案
解决卡片滑块最左侧卡片截断问题
问题根源
- CSS代码存在语法错误,导致布局计算异常
- JS中硬编码的
cardPerView远大于实际卡片数量,引发无限滚动逻辑偏移 - 初始滚动位置计算错误,导致默认显示状态下卡片被截断
一、修复CSS语法错误
修正无效属性与格式问题,确保布局计算准确:
@import url('https://fonts.googleapis.com/css2?family=Wix+Madefor+Text:ital,wght@0,400..800;1,400..800&display=swap'); * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Wix Madefor Text', sans-serif; } body { display: flex; justify-content: center; align-items: center; min-height: 100vh; background: #fff; margin: 0 20px; } .wrapper { position: relative; max-width: 1560px; width: 100%; padding: 0 60px; overflow: hidden; } .wrapper i { position: absolute; top: 50%; transform: translateY(-50%); cursor: pointer; color: #E21C21; font-size: 3.5rem; padding: 5px; z-index: 1; user-select: none; } .wrapper i#left { left: 10px; } .wrapper i#right { right: 10px; } .wrapper i:hover { color: #020202; } .carousel { display: flex; gap: 15px; overflow: hidden; scroll-behavior: smooth; padding: 15px 0; border-radius: 10px; scroll-snap-type: x mandatory; } .carousel.no-transition { scroll-behavior: auto; } .card { min-width: 130px; max-width: 130px; height: 150px; background: #fff; padding: 10px 15px; border-radius: 10px; box-shadow: 0 3px 10px rgb(0 0 0 / 0.2); scroll-snap-align: start; display: flex; flex-direction: column; justify-content: center; align-items: center; } .card:hover { box-shadow: 0 3px 10px rgb(0 0 0 / 0.3); } .card .img { width: 100%; height: 80%; display: flex; justify-content: center; align-items: center; } .card .img img { max-width: 100%; max-height: 100%; object-fit: contain; } .card .text { width: 100%; height: 20%; display: flex; justify-content: center; align-items: center; font-size: 1rem; font-weight: 700; text-align: center; color: #333; margin-top: 10px; font-family: "Wix Madefor Text", sans-serif; }
二、修正JS逻辑错误
优化滚动计算与无限滚动触发条件,确保卡片完整显示:
document.addEventListener("DOMContentLoaded", () => { const wrapper = document.querySelector(".wrapper"); const carousel = document.querySelector(".carousel"); const firstCardWidth = carousel.querySelector(".card").offsetWidth + 15; // 包含卡片间隙 const arrowBtns = document.querySelectorAll(".wrapper i"); const carouselChildren = [...carousel.children]; let isDragging = false, isAutoPlay = true, startX, startScrollLeft, timeoutId; // 动态计算可见卡片数,适配不同屏幕宽度 let cardPerView = Math.floor((wrapper.offsetWidth - 120) / firstCardWidth); // 避免可见数大于实际卡片数 cardPerView = Math.min(cardPerView, carouselChildren.length); // 仅当卡片数量超过可见数时,添加复制卡片实现无限滚动 if (carouselChildren.length > cardPerView) { carouselChildren.slice(-cardPerView).reverse().forEach(card => { carousel.insertAdjacentHTML("afterbegin", card.outerHTML); }); carouselChildren.slice(0, cardPerView).forEach(card => { carousel.insertAdjacentHTML("beforeend", card.outerHTML); }); } // 设置初始滚动位置,确保第一张卡片完整显示 carousel.classList.add("no-transition"); carousel.scrollLeft = carouselChildren.length > cardPerView ? firstCardWidth * cardPerView : 0; carousel.classList.remove("no-transition"); arrowBtns.forEach(btn => { btn.addEventListener("click", () => { carousel.scrollLeft += btn.id === "left" ? -firstCardWidth : firstCardWidth; }); }); const dragStart = (e) => { isDragging = true; carousel.classList.add("dragging"); startX = e.pageX; startScrollLeft = carousel.scrollLeft; }; const dragging = (e) => { if (!isDragging) return; carousel.scrollLeft = startScrollLeft - (e.pageX - startX); }; const dragStop = () => { isDragging = false; carousel.classList.remove("dragging"); // 滚动后自动对齐到卡片边界 const scrollPos = Math.round(carousel.scrollLeft / firstCardWidth) * firstCardWidth; carousel.scrollLeft = scrollPos; }; const infiniteScroll = () => { // 卡片数量不足时跳过无限滚动逻辑 if (carouselChildren.length <= cardPerView) return; if (carousel.scrollLeft <= firstCardWidth * cardPerView - firstCardWidth) { carousel.classList.add("no-transition"); carousel.scrollLeft = carousel.scrollWidth - 2 * firstCardWidth * cardPerView; carousel.classList.remove("no-transition"); } else if (Math.ceil(carousel.scrollLeft) >= carousel.scrollWidth - firstCardWidth * cardPerView) { carousel.classList.add("no-transition"); carousel.scrollLeft = firstCardWidth * cardPerView; carousel.classList.remove("no-transition"); } clearTimeout(timeoutId); if (!wrapper.matches(":hover")) autoPlay(); }; const autoPlay = () => { if (window.innerWidth < 800 || !isAutoPlay || carouselChildren.length <= cardPerView) return; timeoutId = setTimeout(() => carousel.scrollLeft += firstCardWidth, 1000); }; autoPlay(); carousel.addEventListener("mousedown", dragStart); carousel.addEventListener("mousemove", dragging); document.addEventListener("mouseup", dragStop); carousel.addEventListener("scroll", infiniteScroll); wrapper.addEventListener("mouseenter", () => clearTimeout(timeoutId)); wrapper.addEventListener("mouseleave", autoPlay); });
三、关键优化点
- 动态计算
cardPerView,避免硬编码导致的适配问题 - 调整初始滚动位置,确保默认状态下第一张卡片完整显示
- 仅当卡片数量超过可见数时才触发无限滚动逻辑,避免无意义的偏移
内容的提问来源于stack exchange,提问作者Omer Can
相关产品推荐
相关产品推荐

