如何在Bootstrap 5中实现上一张图片固定的垂直轮播?
Bootstrap 5垂直轮播:实现切换时上一张图片固定的方案
问题说明
需要实现Bootstrap 5垂直轮播,要求滚动切换当前图片时,上一张图片保持固定不动,参考Zara官网的滑块效果。尝试给上一张图片添加position: fixed;属性但未生效,以下是原代码及修改后的解决方案。
原代码
HTML
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" /> <link href="./style.css" rel="stylesheet" /> <link rel="preload" href="https://www.jqueryscript.net/dummy/7.jpg" as="image" /> <link rel="preload" href="https://www.jqueryscript.net/dummy/8.jpg" as="image" /> <link rel="preload" href="https://www.jqueryscript.net/dummy/9.jpg" as="image" /> <link rel="preload" href="https://www.jqueryscript.net/dummy/10.jpg" as="image" /> <title>Bootstrap 5 Vertical Carousel Example</title> <link rel="icon" type="image/x-icon" href="./images/bootstrap.ico" /> </head> <body> <div class="carousel-container justify-content-center"> <div id="vertical-carousel" class="carousel slide" data-bs-ride="carousel" data-bs-interval="false" data-bs-wrap="false" > <div class="carousel-inner"> <div class="carousel-item active" style=" background-image: url(https://www.jqueryscript.net/dummy/7.jpg); " ></div> <div class="carousel-item" style=" background-image: url(https://www.jqueryscript.net/dummy/8.jpg); position: fixed; " ></div> <div class="carousel-item" style=" background-image: url(https://www.jqueryscript.net/dummy/9.jpg); " ></div> <div class="carousel-item" style=" background-image: url(https://www.jqueryscript.net/dummy/10.jpg); " ></div> </div> </div> </div> <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous" ></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous" ></script> <script src="./index.js"></script> </body> </html>
CSS
html, body { width: 100%; height: 100%; background-color: rgba(231, 0, 0, 0.901); display: flex; justify-content: center; align-items: center; animation: hide-scroll 5s backwards; } @keyframes hide-scroll { 0% { overflow: hidden; } 100% { overflow: auto; } } .container { width: 100%; height: 100%; } .carousel-inner, .carousel, .carousel-item, .carousel-container { height: 100%; width: 100%; background-position: center center; background-size: cover; } .carousel-item-prev:not(.carousel-item-end), .active.carousel-item-start { transform: translate3d(0, -100%, 0); -webkit-transform: translate3d(0, -100%, 0); -moz-transform: translate3d(0, -100%, 0); -ms-transform: translate3d(0, -100%, 0); -o-transform: translate3d(0, -100%, 0); } .carousel-item-next:not(.carousel-item-start), .active.carousel-item-end { transform: translate3d(0, 100%, 0); -webkit-transform: translate3d(0, 100%, 0); -ms-transform: translate3d(0, 100%, 0); -moz-transform: translate3d(0, 100%, 0); -o-transform: translate3d(0, 100%, 0); } .img-style { width: 100%; } .img-style:hover { width: 100%; } .roll-in-blurred-right { -webkit-animation: roll-in-blurred-right 1s cubic-bezier(0.175, 0.885, 0.320, 1.275) both; animation: roll-in-blurred-right 1s cubic-bezier(0.175, 0.885, 0.320, 1.275) both; } @-webkit-keyframes roll-in-blurred-right { 0% { -webkit-transform: translateX(1000px) rotate(720deg); transform: translateX(1000px) rotate(720deg); -webkit-filter: blur(50px); filter: blur(50px); opacity: 0; } 100% { -webkit-transform: translateX(0) rotate(0deg); transform: translateX(0) rotate(0deg); -webkit-filter: blur(0); filter: blur(0); opacity: 1; } } @keyframes roll-in-blurred-right { 0% { -webkit-transform: translateX(1000px) rotate(720deg); transform: translateX(1000px) rotate(720deg); -webkit-filter: blur(50px); filter: blur(50px); opacity: 0; } 100% { -webkit-transform: translateX(0) rotate(0deg); transform: translateX(0) rotate(0deg); -webkit-filter: blur(0); filter: blur(0); opacity: 1; } }
JS
$("#vertical-carousel").bind("mousewheel DOMMouseScroll", function (e) { if (e.originalEvent.wheelDelta > 0 || e.originalEvent.detail < 0) { $(this).carousel("prev"); } else { $(this).carousel("next"); } e.preventDefault(); }); $("#vertical-carousel").on("touchstart", function (event) { var yTouchPointStart = event.originalEvent.touches[0].pageY; $(this).on("touchmove", function (event) { var yTouchPointEnd = event.originalEvent.touches[0].pageY; if (Math.floor(yTouchPointStart - yTouchPointEnd) > 1) { $("carousel").carousel("next"); } else if (Math.floor(yTouchPointStart - yTouchPointEnd) < -1) { $("carousel").carousel("prev"); } }); $("carousel").on("touchend", function () { $(this).off("touchmove"); }); event.preventDefault(); });
问题原因
Bootstrap轮播的carousel-inner容器默认是相对定位,所有轮播项都嵌套在这个容器内,直接给单个轮播项加position: fixed会被容器的定位上下文限制,同时轮播自带的transform动画也会干扰固定定位的渲染效果。
修改后的解决方案
核心思路
- 新增独立的固定层容器,与轮播容器同级,专门用来显示固定的上一张图片
- 通过轮播切换事件,动态更新固定层的背景图片
- 调整层级关系,确保当前轮播项能覆盖在固定层上方
修改后的完整代码
HTML
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" /> <link href="./style.css" rel="stylesheet" /> <link rel="preload" href="https://www.jqueryscript.net/dummy/7.jpg" as="image" /> <link rel="preload" href="https://www.jqueryscript.net/dummy/8.jpg" as="image" /> <link rel="preload" href="https://www.jqueryscript.net/dummy/9.jpg" as="image" /> <link rel="preload" href="https://www.jqueryscript.net/dummy/10.jpg" as="image" /> <title>Bootstrap 5垂直轮播示例</title> <link rel="icon" type="image/x-icon" href="./images/bootstrap.ico" /> </head> <body> <!-- 固定显示上一张图片的容器 --> <div class="fixed-prev-slide"></div> <div class="carousel-container justify-content-center"> <div id="vertical-carousel" class="carousel slide" data-bs-ride="carousel" data-bs-interval="false" data-bs-wrap="false"> <div class="carousel-inner"> <div class="carousel-item active" data-img="https://www.jqueryscript.net/dummy/7.jpg" style="background-image: url(https://www.jqueryscript.net/dummy/7.jpg);"></div> <div class="carousel-item" data-img="https://www.jqueryscript.net/dummy/8.jpg" style="background-image: url(https://www.jqueryscript.net/dummy/8.jpg);"></div> <div class="carousel-item" data-img="https://www.jqueryscript.net/dummy/9.jpg" style="background-image: url(https://www.jqueryscript.net/dummy/9.jpg);"></div> <div class="carousel-item" data-img="https://www.jqueryscript.net/dummy/10.jpg" style="background-image: url(https://www.jqueryscript.net/dummy/10.jpg);"></div> </div> </div> </div> <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script> <script src="./index.js"></script> </body> </html>
CSS
html, body { width: 100%; height: 100%; background-color: rgba(231, 0, 0, 0.901); display: flex; justify-content: center; align-items: center; animation: hide-scroll 5s backwards; } @keyframes hide-scroll { 0% { overflow: hidden; } 100% { overflow: auto; } } .container { width: 100%; height: 100%; } .carousel-inner, .carousel, .carousel-item, .carousel-container { height: 100%; width: 100%; background-position: center center; background-size: cover; } /* 固定层样式 */ .fixed-prev-slide { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-position: center; background-size: cover; z-index: 1; /* 低于轮播容器,避免遮挡当前轮播项 */ } .carousel-container { position: relative; z-index: 2; /* 确保轮播在固定层上方 */ } .carousel-item-prev:not(.carousel-item-end), .active.carousel-item-start { transform: translate3d(0, -100%, 0); -webkit-transform: translate3d(0, -100%, 0); -moz-transform: translate3d(0, -100%, 0); -ms-transform: translate3d(0, -100%, 0); -o-transform: translate3d(0, -100%, 0); } .carousel-item-next:not(.carousel-item-start), .active.carousel-item-end { transform: translate3d(0, 100%, 0); -webkit-transform: translate3d(0, 100%, 0); -ms-transform: translate3d(0, 100%, 0); -moz-transform: translate3d(0, 100%, 0); -o-transform: translate3d(0, 100%, 0); } .img-style { width: 100%; } .img-style:hover { width: 100%; } .roll-in-blurred-right { -webkit-animation: roll-in-blurred-right 1s cubic-bezier(0.175, 0.885, 0.320, 1.275) both; animation: roll-in-blurred-right 1s cubic-bezier(0.175, 0.885, 0.320, 1.275) both; } @-webkit-keyframes roll-in-blurred-right { 0% { -webkit-transform: translateX(1000px) rotate(720deg); transform: translateX(1000px) rotate(720deg); -webkit-filter: blur(50px); filter: blur(50px); opacity: 0; } 100% { -webkit-transform: translateX(0) rotate(0deg); transform: translateX(0) rotate(0deg); -webkit-filter: blur(0); filter: blur(0); opacity: 1; } } @keyframes roll-in-blurred-right { 0% { -webkit-transform: translateX(1000px) rotate(720deg); transform: translateX(1000px) rotate(720deg); -webkit-filter: blur(50px); filter: blur(50px); opacity: 0; } 100% { -webkit-transform: translateX(0) rotate(0deg); transform: translateX(0) rotate(0deg); -webkit-filter: blur(0); filter: blur(0); opacity: 1; } }
JS
$("#vertical-carousel").bind("mousewheel DOMMouseScroll", function (e) { if (e.originalEvent.wheelDelta > 0 || e.originalEvent.detail < 0) { $(this).carousel("prev"); } else { $(this).carousel("next"); } e.preventDefault(); }); $("#vertical-carousel").on("touchstart", function (event) { var yTouchPointStart = event.originalEvent.touches[0].pageY; $(this).on("touchmove", function (event) { var yTouchPointEnd = event.original
相关产品推荐
相关产品推荐

