You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何动态居中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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 09:37:01