仅使用 CSS 重复交错动画序列

问题描述 投票:0回答:1

无限对角线翻转动画,4x4 网格中的方块消失

我正在创建一个带有 4x4 正方形网格的动画,这些正方形网格逐个对角翻转。这是我到目前为止所取得的成就:

  1. 方块根据需要单独翻转。
  2. 单击两个方块后,它们消失。
  3. 单击其他两个方块后,整个 4x4 网格就会消失。

挑战:我希望动画无限循环,顺序如下:

  1. 显示所有 4 个方块。
  2. 沿对角线(顺时针)翻转图块 1 和 4,然后在延迟后隐藏它们。
  3. 对图块 2 和 3 重复步骤 2 和 3。
  4. 隐藏所有方块后,再次显示所有未翻转的方块并重新启动序列。

问题: 如何在动画中实现带有消失方块的无限循环功能?正如标题中提到的,我不想使用 JavaScript,并且很想知道仅使用 CSS 是否可以实现这一点。

下面是我的代码。

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: system-ui, sans-serif;
  color: black;
  background-color: rgb(19, 18, 18);
}

@keyframes tileFlipShow {
  from {
    backface-visibility: hidden;
  }
  to {
    transform: rotateY(180deg);
    backface-visibility: visible;
  }
}

@keyframes tileFlipHide {
  from {
    transform: rotateY(180deg);
    backface-visibility: visible;
  }
  to {
    backface-visibility: hidden;
  }
}

@keyframes hideTile {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

.grid-container {
  display: grid;
  justify-content: center;
  align-items: center;
  height: 100vh;
}

.tile-grid {
  display: grid;
  grid-gap: 1px;
  grid-template-columns: repeat(2, 1fr);
  max-width: fit-content;
}

.tile-grid>div:nth-child(1) {
  animation-delay: 1.5s;
}

.tile-grid>div:nth-child(1) .flip-card-inner {
  animation-delay: 0s;
}

.tile-grid>div:nth-child(4) {
  animation-delay: 1.5s;
}

.tile-grid>div:nth-child(4) .flip-card-inner {
  animation-delay: 1s;
}

.tile-grid>div:nth-child(2) {
  animation-delay: 3.5s;
}

.tile-grid>div:nth-child(2) .flip-card-inner {
  animation-delay: 2s;
}

.tile-grid>div:nth-child(3) {
  animation-delay: 3.5s;
}

.tile-grid>div:nth-child(3) .flip-card-inner {
  animation-delay: 3s;
}

.flip-card {
  perspective: 1000px;
  margin: 1px;
  cursor: pointer;
  height: 9.375rem;
  width: 9.375rem;
  min-width: 3.125rem;
  min-height: 3.125rem;
  max-height: 9.375rem;
  max-width: 9.375rem;
  font-size: 1em;
  transition: all 0.2s ease-in-out;
  animation: 0.5s hideTile both;
}

.flip-card-inner {
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform 0.5s;
  animation: 0.5s tileFlipShow both;
}

.flip-card-front {
  height: 100%;
  width: 100%;
  position: absolute;
  backface-visibility: hidden;
  background-color: #3498db;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.2rem;
}

.flip-card-front * {
  padding: 0;
  margin: 0;
  max-width: 100%;
  max-height: 100%;
  color: #fff;
}

.flip-card-back {
  height: 100%;
  width: 100%;
  position: absolute;
  backface-visibility: hidden;
  background-image: linear-gradient(-45deg, #ffc796 0%, #ff6b95 100%);
  backdrop-filter: blur(10rem);
  transform: rotateY(180deg);
  display: flex;
  align-items: center;
  justify-content: center;
}

.flip-card-back * {
  padding: 0;
  margin: 0;
  max-width: 100%;
  max-height: 100%;
  color: #fff;
}

.flip-card-back img {
  width: auto;
  height: 90%;
}

.flip-card-back picture {
  width: auto;
  height: 90%;
}

.flip-card-matched {
  visibility: hidden;
}

.flip-counter {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 1;
  font-size: 0.5rem;
  display: none;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <title>Bootstrap 5 example</title>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width" />
  <link rel="stylesheet" href="styles.css" />
</head>

<body>
  <div class="container">
    <div class="grid-container">
      <div class="tile-grid">
        <div class="flip-card">
          <div class="flip-card-inner not-matched">
            <div class="flip-card-front">1</div>
            <div class="flip-card-back">11</div>
          </div>
        </div>
        <div class="flip-card">
          <div class="flip-card-inner not-matched">
            <div class="flip-card-front">2</div>
            <div class="flip-card-back">22</div>
          </div>
        </div>
        <div class="flip-card">
          <div class="flip-card-inner not-matched">
            <div class="flip-card-front">3</div>
            <div class="flip-card-back">22</div>
          </div>
        </div>
        <div class="flip-card">
          <div class="flip-card-inner not-matched">
            <div class="flip-card-front">4</div>
            <div class="flip-card-back">11</div>
          </div>
        </div>
      </div>
    </div>
  </div>
</body>

</html>

html css animation
1个回答
0
投票

我按照以下时间线使用原始动画延迟作为基础为每个方块创建了新的关键帧:

animation start
0   (0%)     card 1 flip start
0.5 (10%)    card 1 flip end
1   (20%)    card 4 flip start
1.5 (30%)    card 4 flip end, card 1+4 fade out start
2   (40%)    card 1+4 fade out end, card 2 flip start
2.5 (50%)    card 2 flip end
3   (60%)    card 3 flip start
3.5 (70%)    card 3 flip end, card 2+3 fade out start
4   (79.99%) card 2+3 fade out end, card 1+2+3+4 unflip start
4   (80%)    card 1+2+3+4 unflip end, card 1+2+3+4 fade in start
4.5 (90%)    card 1+2+3+4 fade in end
5   (100%)   wait after cards fade back in before looping
animation end

关键帧的结构如下:

@keyframes flip_1 {
  0% { /* flip start */
    transform: none;
    backface-visibility: hidden;
  }
  10%, /* flip end */
  79.99% { /* unflip start */
    transform: rotateY(180deg);
    backface-visibility: visible;
  }
  80% { /* unflip end */
    transform: none;
    backface-visibility: hidden;
  }
}

@keyframes fade_1_4 {
  30% { /* fade out start */
    opacity: 1;
  }
  40%, /* fade out end */
  80% { /* fade in start */
    opacity: 0;
  }
  90% { /* fade in end */
    opacity: 1;
  }
}

然后我在

animation-duration: 5s;
animation-iteration-count: infinite;
上设置
.flip-card
.flip-card-inner

如果您希望动画表现不同,请告诉我,我会更新我的答案。

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: system-ui, sans-serif;
  color: black;
  background-color: rgb(19, 18, 18);
}

@keyframes flip_1 {
  0% {
    transform: none;
    backface-visibility: hidden;
  }
  10%,
  79.99% {
    transform: rotateY(180deg);
    backface-visibility: visible;
  }
  80% {
    transform: none;
    backface-visibility: hidden;
  }
}

@keyframes flip_4 {
  20% {
    transform: none;
    backface-visibility: hidden;
  }
  30%,
  79.99% {
    transform: rotateY(180deg);
    backface-visibility: visible;
  }
  80% {
    transform: none;
    backface-visibility: hidden;
  }
}

@keyframes fade_1_4 {
  30% {
    opacity: 1;
  }
  40%,
  80% {
    opacity: 0;
  }
  90% {
    opacity: 1;
  }
}

@keyframes flip_2 {
  40% {
    transform: none;
    backface-visibility: hidden;
  }
  50%,
  79.99% {
    transform: rotateY(180deg);
    backface-visibility: visible;
  }
  80% {
    transform: none;
    backface-visibility: hidden;
  }
}

@keyframes flip_3 {
  60% {
    transform: none;
    backface-visibility: hidden;
  }
  70%,
  79.99% {
    transform: rotateY(180deg);
    backface-visibility: visible;
  }
  80% {
    transform: none;
    backface-visibility: hidden;
  }
}

@keyframes fade_2_3 {
  70% {
    opacity: 1;
  }
  79.99%,
  80% {
    opacity: 0;
  }
  90% {
    opacity: 1;
  }
}

.grid-container {
  display: grid;
  justify-content: center;
  align-items: center;
  height: 100vh;
}

.tile-grid {
  display: grid;
  grid-gap: 1px;
  grid-template-columns: repeat(2, 1fr);
  max-width: fit-content;
}

.flip-card:nth-child(1) .flip-card-inner {
  animation-name: flip_1;
}

.flip-card:nth-child(4) .flip-card-inner {
  animation-name: flip_4;
}

.flip-card:nth-child(1), .flip-card:nth-child(4) {
  animation-name: fade_1_4;
}

.flip-card:nth-child(2) .flip-card-inner {
  animation-name: flip_2;
}

.flip-card:nth-child(3) .flip-card-inner {
  animation-name: flip_3;
}

.flip-card:nth-child(2), .flip-card:nth-child(3) {
  animation-name: fade_2_3;
}

.flip-card {
  perspective: 1000px;
  margin: 1px;
  cursor: pointer;
  height: 9.375rem;
  width: 9.375rem;
  min-width: 3.125rem;
  min-height: 3.125rem;
  max-height: 9.375rem;
  max-width: 9.375rem;
  font-size: 1em;
  transition: all 0.2s ease-in-out;
  animation-duration: 5s;
  animation-iteration-count: infinite;
}

.flip-card-inner {
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform 0.5s;
  animation-duration: 5s;
  animation-iteration-count: infinite;
}

.flip-card-front {
  height: 100%;
  width: 100%;
  position: absolute;
  backface-visibility: hidden;
  background-color: #3498db;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.2rem;
}

.flip-card-front * {
  padding: 0;
  margin: 0;
  max-width: 100%;
  max-height: 100%;
  color: #fff;
}

.flip-card-back {
  height: 100%;
  width: 100%;
  position: absolute;
  backface-visibility: hidden;
  background-image: linear-gradient(-45deg, #ffc796 0%, #ff6b95 100%);
  backdrop-filter: blur(10rem);
  transform: rotateY(180deg);
  display: flex;
  align-items: center;
  justify-content: center;
}

.flip-card-back * {
  padding: 0;
  margin: 0;
  max-width: 100%;
  max-height: 100%;
  color: #fff;
}

.flip-card-back img {
  width: auto;
  height: 90%;
}

.flip-card-back picture {
  width: auto;
  height: 90%;
}

.flip-card-matched {
  visibility: hidden;
}

.flip-counter {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 1;
  font-size: 0.5rem;
  display: none;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <title>Bootstrap 5 example</title>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width" />
  <link rel="stylesheet" href="styles.css" />
</head>

<body>
  <div class="container">
    <div class="grid-container">
      <div class="tile-grid">
        <div class="flip-card">
          <div class="flip-card-inner not-matched">
            <div class="flip-card-front">1</div>
            <div class="flip-card-back">11</div>
          </div>
        </div>
        <div class="flip-card">
          <div class="flip-card-inner not-matched">
            <div class="flip-card-front">2</div>
            <div class="flip-card-back">22</div>
          </div>
        </div>
        <div class="flip-card">
          <div class="flip-card-inner not-matched">
            <div class="flip-card-front">3</div>
            <div class="flip-card-back">22</div>
          </div>
        </div>
        <div class="flip-card">
          <div class="flip-card-inner not-matched">
            <div class="flip-card-front">4</div>
            <div class="flip-card-back">11</div>
          </div>
        </div>
      </div>
    </div>
  </div>
</body>

</html>

© www.soinside.com 2019 - 2024. All rights reserved.