如何动态居中GameFrame组件中左右侧player's hand元素?
实现卡牌游戏中左右侧手牌的动态居中

我有一个名为GameFrame的组件,里面包含table和玩家手牌(player's hand)两类元素,它们都位于game-frame-container容器内。我希望实现屏幕(table)左右侧的玩家手牌居中显示,并且需要动态居中:当玩家出牌后,手牌能自动重新居中。目前通过静态CSS实现了部分居中效果,但左右侧的手牌并未正确居中,期望效果如下:

当前代码
HTML结构
<div class="table"> <div style="--rotation-extra-turns: {playerIndex}" class:count-1={players == 1} class:count-2={players == 2} class:count-3={players == 3} class:count-4={players == 4} class:count-5={players == 5} class:count-6={players == 6} class:flipped={game?.tricks?.flipped} class="players cards-large" > {#if game?.players?.length} {#each game.players as player, i} {#if !player.inactive} <div class="player"> <p class="name" class:rotate={i === ourPlayer}> </p> <div class="discard"> {#if turn.type == "bid" && (player.bid || typeof player.bid == "number")} {:else if ["take", "card"].includes(turn.type) && discards[i]} <div class={i === ourPlayer ? "rotate" : ""}> <Card card={discards[i]} {gameframe} /> </div> {/if} </div> </div> {/if} {/each} {/if} </div> </div> {#if watcherIndex !== -1 && turn.type !== "score"} {#if game.players?.length} <div class="all-players"> {#each game.players as player} <div class="player-container"> {#if player.hand?.length} <div class="hand"> {#each player.hand as card} <Card {card} onClick={() => { play(card); }} {gameframe} /> {/each} </div> {/if} </div> {/each} </div> {/if} {/if}
现有CSS
.table { height: var(--players-height); display: flex; margin: auto; } .player-container:nth-child(1) { position: absolute; bottom: 0; transform: translateX(-50%); left: 50%; } .player-container:nth-child(2) { position: absolute; left: var(--history-width); transform-origin: top left; top: calc(100% - 6rem); transform: translateY(-50%) rotate(-90deg); } .player-container:nth-child(2) > div { flex-direction: row-reverse; } .player-container:nth-child(3) { position: absolute; top: 0; left: 50%; transform: translateX(-50%); } .player-container:nth-child(4) { position: absolute; right: var(--chat-width); transform-origin: top right; top: calc(100% - 6rem); transform: translateY(-50%) rotate(90deg); }
解决方案
1. 修正左右侧玩家容器的定位与旋转逻辑
修改左右侧player-container的CSS,调整旋转原点和变换顺序,确保旋转后元素保持居中:
/* 左侧玩家容器 */ .player-container:nth-child(2) { position: absolute; left: var(--history-width); top: 50%; /* 垂直居中对齐 */ transform: translateY(-50%) rotate(-90deg); /* 先平移再旋转,保证居中后调整方向 */ transform-origin: center center; /* 以自身中心为旋转原点 */ } /* 右侧玩家容器 */ .player-container:nth-child(4) { position: absolute; right: var(--chat-width); top: 50%; transform: translateY(-50%) rotate(90deg); transform-origin: center center; }
2. 让手牌容器自适应居中
给.hand添加弹性布局,确保卡牌数量变化时自动居中:
.hand { display: flex; justify-content: center; /* 水平居中卡牌 */ align-items: center; gap: 0.5rem; /* 可根据需求调整卡牌间距 */ }
3. 动态适配说明
从代码的{#each}和条件类绑定语法可以判断这是Svelte组件,当玩家手牌变化时,Svelte会自动更新DOM结构。上述CSS会自动根据新的手牌宽度重新计算居中位置,无需额外JS逻辑。
核心原理
- 将旋转原点改为元素自身中心,避免旋转后出现偏移;
- 先执行垂直平移居中,再进行旋转操作,确保旋转后元素仍处于垂直中间位置;
- 弹性布局的
.hand容器会自动适配卡牌数量,始终保持内部卡牌水平居中。
内容的提问来源于stack exchange,提问作者balaji
相关产品推荐
相关产品推荐

