宝可梦图鉴3D轮播半透明显示效果优化技术求助
宝可梦图鉴3D轮播显示优化问题
我正在开发一个宝可梦图鉴项目,现有的3D轮播功能可以正常运行,但需要优化显示效果:希望页面仅展示中间的主元素、上方1个50%透明度的元素、下方2个50%透明度的元素,其余元素全部隐藏。目前我只能实现隐藏除主元素外的所有内容,求解决方案。
CSS
* { box-sizing: border-box; } body { margin: 0; padding: 0; text-align: center; display: flex; flex-direction: column; align-items: center; background-image: url("../.img/pokedex/pokedex.png"); background-repeat: no-repeat; background-position: 50%; background-size: 775px; } a, a:visited, a:active { color: inherit; } .sprite { display: block; margin-right: 310px; position: absolute; } .pkmname { display: block; margin-left: 225px; position: absolute; } .carousel { display: flex; align-items: center; position: relative; padding: 130px 0; margin-left: 340px; margin-top: 248px; } .carousel__scene { position: relative; width: 510px; height: 460px; max-width: 95vw; padding-top: 60px; perspective: 100px; /*overflow: hidden;*/ } .carousel__controls { display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 10px; position: absolute; right: 15px; margin-bottom: 190px; margin-right: 20px; } .previous-button, .next-button { margin: 5px 0; width: 50px; height: 50px; font-family: monospace; font-weight: bold; font-size: 2rem; border: 3px solid goldenrod; border-radius: 10px; background-color: #444; } .previous-button:focus, .next-button:focus { outline: none; box-shadow: 0 0 6px 3px goldenrod; } #prev, #next { margin-right: 50px; } .carousel__list { width: 100%; height: 150px; margin: 0; padding: 0; position: absolute; transform: translateZ(-288px); transform-style: preserve-3d; transition: transform 1s; list-style: none; counter-reset: list-counter; } .carousel__cell { position: absolute; width: 400px; height: 140px; max-width: calc(95vw - 20px); left: 10px; top: 10px; font-size: 20px; font-weight: bold; color: white; text-align: center; transition: transform 1s, opacity 1s; display: flex; flex-direction: column; align-items: center; justify-content: center; counter-increment: list-counter; background-image: url("../.img/pokedex/unknown.png"); background-repeat: no-repeat; background-position: center; } .carousel__cell:before { content: counter(list-counter); color: white; text-shadow: 2px 2px black; width: 40px; height: 40px; line-height: 40px; } .carousel__cell.selected { color: goldenrod; border-color: goldenrod; border-width: 5px; /*filter: none;*/ } .carousel__cell.before { opacity: 100%; } .carousel__cell.after { opacity: 50%; } .carousel__cell.hide { opacity: 0%; } .carousel__cell.selected::before { color: goldenrod; } .carousel__cell:nth-child(0) { transform: rotateX(0deg) translateZ(288px); } .carousel__cell:nth-child(1) { transform: rotateX(40deg) translateZ(288px); } .carousel__cell:nth-child(2) { transform: rotateX(80deg) translateZ(288px); } .carousel__cell:nth-child(3) { transform: rotateX(120deg) translateZ(288px); } .carousel__cell:nth-child(4) { transform: rotateX(160deg) translateZ(288px); } .carousel__cell:nth-child(5) { transform: rotateX(200deg) translateZ(288px); } .carousel__cell:nth-child(6) { transform: rotateX(240deg) translateZ(288px); } .carousel__cell:nth-child(7) { transform: rotateX(280deg) translateZ(288px); } .carousel__cell:nth-child(8) { transform: rotateX(320deg) translateZ(288px); }
HTML
<div class="carousel"> <div class="carousel__scene"> <ol class="carousel__list"> <li class="carousel__cell" onClick="location.href='../../dexentries/0001-bulbasaur.html'"><img class="sprite" src="../../../.img/game-sprites/gen1/spr_rb-gb_001.png" alt="Bulbasaur"/><span class="pkmname">Bulbasaur</span></li> <li class="carousel__cell" onClick="location.href='../../dexentries/0002-ivysaur.html'"><img class="sprite" src="../../../.img/game-sprites/gen1/spr_rb-gb_002.png" alt="Ivysaur"/><span class="pkmname">Ivysaur</span></li> <li class="carousel__cell" onClick="location.href='../../dexentries/0003-venusaur.html'"><img class="sprite" src="../../../.img/game-sprites/gen1/spr_rb-gb_003.png" alt="Venusaur"/><span class="pkmname">Venusaur</span></li> <li class="carousel__cell" onClick="location.href='../../dexentries/0004-charmander.html'"><img class="sprite" src="../../../.img/game-sprites/gen1/spr_rb-gb_004.png" alt="Charmander"/><span class="pkmname">Charmander</span></li> <li class="carousel__cell" onClick="location.href='../../dexentries/0005-charmeleon.html'"><img class="sprite" src="../../../.img/game-sprites/gen1/spr_rb-gb_005.png" alt="Charmeleon"/><span class="pkmname">Charmeleon</span></li> <li class="carousel__cell" onClick="location.href='../../dexentries/0006-charizard.html'"><img class="sprite" src="../../../.img/game-sprites/gen1/spr_rb-gb_006.png" alt="Charizard"/><span class="pkmname">Charizard</span></li> <li class="carousel__cell" onClick="location.href='../../dexentries/0007-squirtle.html'"><img class="sprite" src="../../../.img/game-sprites/gen1/spr_rb-gb_007.png" alt="Squirtle"/><span class="pkmname">Squirtle</span></li> <li class="carousel__cell" onClick="location.href='../../dexentries/0008-wartorle.html'"><img class="sprite" src="../../../.img/game-sprites/gen1/spr_rb-gb_008.png" alt="Wartortle"/><span class="pkmname">Wartortle</span></li> <li class="carousel__cell" onClick="location.href='../../dexentries/0009-blastoise.html'"><img class="sprite" src="../../../.img/game-sprites/gen1/spr_rb-gb_009.png" alt="Blastoise"/><span class="pkmname">Blastoise</span></li> <li class="carousel__cell" onClick="location.href='../../dexentries/0010-caterpie.html'"><img class="sprite" src="../../../.img/game-sprites/gen1/spr_rb-gb_010.png" alt="Caterpie"/><span class="pkmname">Caterpie</span></li> <li class="carousel__cell" onClick="location.href='../../dexentries/0011-metapod.html'"><img class="sprite" src="../../../.img/game-sprites/gen1/spr_rb-gb_011.png" alt="Metapod"/><span class="pkmname">Metapod</span></li> <li class="carousel__cell" onClick="location.href='../../dexentries/0012-butterfree.html'"><img class="sprite" src="../../../.img/game-sprites/gen1/spr_rb-gb_012.png" alt="Butterfree"/><span class="pkmname">Butterfree</span></li> </ol> </div> <div class="carousel__controls"> <button class="previous-button" style="background: url('../../../.img/pokedex/prev.png'); background-repeat: no-repeat; background-position: center;" onClick="plusSlides(-1)"></button> <button class="next-button" style="background: url('../../../.img/pokedex/next.png'); background-repeat: no-repeat; background-position: center;" onClick="plusSlides(1)"></button> </div> <script type="text/javascript" src="../../../.js/pokedex.js"></script> </div>
JavaScript
// JavaScript Document const carousel = document.querySelector('.carousel__list'); const cells = carousel.querySelectorAll('.carousel__cell'); const cellWidth = carousel.offsetWidth; const cellHeight = carousel.offsetHeight; const cellSize = cellHeight; const cellCount = 151; const radius = Math.round((cellSize / 2) / Math.tan(Math.PI / cellCount)); const theta = 360 / cellCount; var selectedIndex = 0; function rotateCarousel() { const angle = theta * selectedIndex * -1; carousel.style.transform = 'translateZ(' + -radius + 'px) ' + 'rotateX(' + -angle + 'deg)'; const cellIndex = selectedIndex < 0 ? (cellCount - ((selectedIndex * -1) % cellCount)) : (selectedIndex % cellCount); const cells = document.querySelectorAll('.carousel__cell'); cells.forEach((cell, index) => { if(cellIndex === index) { if(!cell.classList.contains('selected')) cell.classList.add('selected'); } else { if(cell.classList.contains('selected')) { cell.classList.remove('selected'); } } }); } function selectPrev() { selectedIndex--; rotateCarousel(); } function selectNext() { selectedIndex++; rotateCarousel(); } var prevButton = document.querySelector('.previous-button'); prevButton.addEventListener('click', selectPrev); var nextButton = document.querySelector('.next-button'); nextButton.addEventListener('click', selectNext); function initCarousel() { for(let i = 0; i < cells.length; i++) { const cell = cells[i]; const cellAngle = theta * i; cell.style.transform = 'rotateX(' + -cellAngle + 'deg) translateZ(' + radius + 'px)'; } rotateCarousel(); } initCarousel();
解决方案
核心是根据每个元素与当前选中元素的索引位置关系,动态控制透明度:
- 调整CSS规则
移除全局设置非选中元素透明度的代码,避免干扰动态逻辑:
/* 删除这条规则 */ .carousel__cell:not(.selected) { opacity: 50%; }
- 重写rotateCarousel函数
更新JavaScript中的rotateCarousel函数,添加位置判断逻辑:
function rotateCarousel() { const angle = theta * selectedIndex * -1; carousel.style.transform = 'translateZ(' + -radius + 'px) ' + 'rotateX(' + -angle + 'deg)'; const cellIndex = selectedIndex < 0 ? (cellCount - ((selectedIndex * -1) % cellCount)) : (selectedIndex % cellCount); const totalCells = cells.length; cells.forEach((cell, index) => { // 计算相对位置,处理循环轮播的边界情况 const relativePos = (index - cellIndex + totalCells) % totalCells; // 重置所有状态类 cell.classList.remove('selected', 'show-half', 'hide'); if (relativePos === 0) { // 中间主元素:100%透明度 cell.classList.add('selected'); cell.style.opacity = '1'; } else if (relativePos === 1 || relativePos === 2) { // 下方2个元素:50%透明度 cell.classList.add('show-half'); cell.style.opacity = '0.5'; } else if (relativePos === totalCells - 1) { // 上方1个元素:50%透明度 cell.classList.add('show-half'); cell.style.opacity = '0.5'; } else { // 其余元素:完全隐藏 cell.classList.add('hide'); cell.style.opacity = '0'; } }); }
- 确保过渡效果平滑
确认.carousel__cell的过渡属性包含opacity,保证透明度变化有动画:
.carousel__cell { transition: transform 1s, opacity 1s; }
修改后,轮播时只会显示选中的主元素、上方1个半透明元素、下方2个半透明元素,其余元素完全隐藏,符合需求。
内容的提问来源于stack exchange,提问作者GamingLegion
相关产品推荐
相关产品推荐

