卡片Hover动画水平移动时闪烁重置问题求助
问题解决:卡组卡片Hover闪烁问题
问题描述
实现卡组动画时,顶部卡片hover通过translateY(-20px)向上位移,但鼠标在卡片底部区域水平移动时,卡片会出现闪烁——动画重置为原始状态后又恢复hover状态。且增大translate偏移量,闪烁触发区域会扩大。尝试调整translate、position、top、transition属性均无效。
原因分析
hover事件绑定在卡片本身,当卡片向上位移后,鼠标原本处于的卡片底部区域会脱离卡片的实际范围,导致hover状态被取消;卡片回到原位后,鼠标又重新触发hover,如此循环造成闪烁。
解决方案
方案1:将hover事件绑定到父容器
把hover触发逻辑转移到卡组容器#deck上,只要鼠标在容器范围内,就控制顶部卡片位移,避免卡片位移后脱离hover范围:
修改CSS部分:
#deck { display: flex; justify-content: space-around; position: relative; /* 给容器设置合适高度,覆盖卡片位移前后的范围 */ height: 120px; } .card { height: 100px; width: 100px; background-color: red; position: absolute; border: 1px solid black; } #deck .card:last-child { transition: transform 0.3s ease; } /* 父容器hover时控制顶部卡片位移 */ #deck:hover .card:last-child { transform: translateY(-20px); }
方案2:用伪元素扩展hover区域
给顶部卡片添加透明伪元素,覆盖卡片位移前的底部区域,确保鼠标移动时始终处于hover触发范围内:
修改CSS部分:
#deck .card:last-child { transition: transform 0.3s ease; position: relative; /* 伪元素需要相对定位 */ } #deck .card:last-child::before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: -20px; /* 偏移量与translateY一致 */ z-index: -1; /* 不干扰卡片本身的交互 */ }
代码优化建议
JavaScript优化
- 封装全局变量,避免污染全局作用域:
// 用IIFE封装代码 (function() { const game = document.getElementById('game'); const deckEl = document.getElementById('deck'); const hand = document.getElementById('hand'); let arr = [{card: 1, text:"Attack"},{card: 2, text:"Attack"},{card: 3, text:"Attack"},{card: 4, text:"Shield"},{card: 5, text:"Shield"},{card: 6, text:"Shield"},{card: 7, text:"Parry"},{card: 8, text:"Parry"},{card: 9, text:"Parry"}]; let cardsInHand = []; // 标准Fisher-Yates洗牌算法,纯函数不修改原数组 function shuffleDeck(array) { const newArr = [...array]; let i = newArr.length; while(i--) { const i2 = Math.floor(Math.random() * (i + 1)); // 修正原算法最后一个元素不参与洗牌的问题 [newArr[i], newArr[i2]] = [newArr[i2], newArr[i]]; } return newArr; } function drawCards(cardAmount) { // 添加边界判断,避免数组为空时报错 if (arr.length === 0) return; const drawCount = Math.min(cardAmount, arr.length); for(let i = 0; i < drawCount; i++) { cardsInHand.push(arr.pop()); } } function generateDeck() { let cardOutline = 200; arr.forEach((card, index) => { const cardEl = document.createElement('div'); cardEl.classList.add('card'); cardOutline -= 3; cardEl.style.top = `${cardOutline}px`; // 显式设置z-index,确保卡片堆叠顺序正确 cardEl.style.zIndex = index; deckEl.appendChild(cardEl); }); } arr = shuffleDeck(arr); // 使用纯函数洗牌后重新赋值 generateDeck(); drawCards(3); })();
CSS优化
- 使用CSS变量统一管理参数,便于维护:
:root { --card-width: 100px; --card-height: 100px; --hover-offset: 20px; --card-gap: 3px; } #deck { display: flex; justify-content: space-around; position: relative; height: calc(var(--card-height) + var(--hover-offset)); } .card { height: var(--card-height); width: var(--card-width); background-color: red; position: absolute; border: 1px solid black; } #deck .card:last-child { transition: transform 0.3s ease; } #deck:hover .card:last-child { transform: translateY(calc(-1 * var(--hover-offset))); }
内容的提问来源于stack exchange,提问作者l00duck
相关产品推荐
相关产品推荐

