棋盘揭示

Avatar of Geoff Graham
Geoff Graham

DigitalOcean 为您旅程的每个阶段提供云产品。 立即开始使用 价值 200 美元的免费积分!

当我 10 岁的时候,我记得我表弟来我家玩。 他是(现在仍然)一个很酷的孩子,他会在软盘上带他自己的编程象棋游戏。 他的象棋版本和他一样酷,因为棋盘的一块会在每次移动后消失。

更酷的是? 游戏棋盘上消失的每一块都会显示出一张漂亮的照片。

这真是一场很难的游戏。

我认为同样的想法可以制作出一些很酷的 UI。 除了,也许不是需要用户交互来揭示背景,它可以简单地作为动画播放。 这是我最终得到的结果

这个想法很简单,还有很多其他方法可以实现,但这是我遵循的路线……

首先,我创建了一些标记

图像可以在 CSS 中作为背景处理在 <body> 上,或一些设计为特定大小的 <div>。 因此,现在还不需要处理它。

但棋盘很有趣。 这是一个在 CSS 网格上写满了的图案,所以我用一个元素来充当网格容器,里面有一堆 <div> 元素。 我不知道一个真正的棋盘有多少块瓦片/方格/无论什么,所以我只是从空中选择了一个数字 7,然后平方它得到 49 个方格。

<div class="grid">
  <div></div>
  <!-- etc. -->
  <div></div>
</div>

是的,写出所有这些 divs 很痛苦,JavaScript 可以肯定地帮助。 但是如果我只是在实验,并且只需要开发人员的便利,那么使用 Haml 可以帮助解决这个问题

.grid
  - 49.times do
    %div

最终它们都是一样的。 无论哪种方式,它都为我提供了开始样式化所需的所有标记!

设置背景图像

同样,这可以作为 <body> 或其他元素上的 background-image 发生,具体取决于它的使用方法——只要它覆盖整个空间即可。 由于我反正需要一个网格容器,我决定使用它。

.checkerboard {
  background-image: url('walrus.jpg');
  background-size: cover;
  /* Might need other properties to position the image just right */
}

渐变是光栅图像文件的一部分,但我可以用某种类型的覆盖在 <body> 上使用伪元素,如 :after,变得聪明。 哎呀,这是一种广泛使用的技术,就在 CSS-Tricks 的当前设计上。

设置网格样式

是的,我使用了 CSS 网格。 用这种方式制作一个 7×7 网格非常容易。

.checkerboard {
  background-image: url('walrus.jpg');
  background-size: cover;
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  grid-template-rows: repeat(7, 1fr);
}

我想象,一旦我们看到 aspect-ratio 广泛支持,它会好得多,至少如果我正确理解的话。 我现在遇到的问题是,网格没有保持任何比例。 这意味着棋盘的瓦片在不同的视窗大小下会变得很软等等。 嘘。 在此期间,我们可以做一些很小的技巧,如果这非常重要,但我决定保持原样。

设置瓦片样式

它们在白色和深灰色之间交替,因此

.checkerboard > div {
  background-color: #fff;
}
.checkerboard > div:nth-child(even) {
  background-color: #2f2f2f;
}

信不信由你,我们的标记和样式化完成了! 剩下的就是……

为瓦片设置动画

所有动画需要做的就是将每个瓦片的 opacity: 1; 过渡到 opacity: 0;,CSS 动画非常适合此操作。

@keyframes poof {
  to {
    opacity: 0;
  }
}

太棒了! 我甚至不需要设置一个开始关键帧! 我所要做的就是调用瓦片上的动画。

.checkerboard > div {
  animation-name: poof;
  animation-duration: 0.25s;
  animation-fill-mode: forwards;
  background: #fff;
}

是的,我本可以使用 animation 简写属性,但我经常发现将它的组成属性单独拆分出来更容易,因为……好吧,它们太多了,而且在一行上很难阅读和识别。

如果您想知道这里为什么要使用 animation-fill-mode,那是因为它可以防止动画在设置为 forwards 时循环回到动画的开头。 换句话说,每个瓦片在动画结束时会停留在 opacity: 0; 上,而不是重新出现。

我真的很想做一些聪明而巧妙的事情来交错瓦片的 animation-delay,但我碰了一堆墙,最后决定放弃 100% 原生 CSS 的努力,转而使用一些轻量级的 SCSS。 这样,我可以循环遍历所有瓦片,并使用一个非常标准的函数为每个瓦片设置动画偏移。 所以,对于突然的转换感到抱歉! 这只是旅程的一部分。

$columns: 7;
$rows: 7;
$cells: $columns * $rows;

@for $i from 1 through $cells {
  .checkerboard > div:nth-child(#{$i}) {
    animation-delay: (random($cells) / $columns) + s;
  }
}

让我们分解一下

  • 有网格列数 ($columns)、网格行数 ($rows) 和单元格总数 ($cells) 的变量。 最后一个是前两个的乘积。 如果我们知道我们总是在使用一个完美的正方形网格,那么我们可以稍微重构一下,使用指数来计算单元格数量。
  • 然后,对于 1$cells 总数(在本例中为 49)之间的每个单元格实例,每个单独的瓦片都会根据其 :nth-child() 值获得 animation-delay。 因此,第一个瓦片是 div:nth-child(1),然后是 div:nth-child(2),依此类推。 查看演示中的编译 CSS,您将看到它是如何全部分解的。
.checkerboard > div:nth-child(1) {}
.checkerboard > div:nth-child(2) {}
/* etc. */
  • 最后,animation-delay 是一个计算,它取 1$cells 总数之间的随机数,除以 $columns 的数量,并在值后面附加秒。 这是最好的方法吗? 我不知道。 它归结为多尝试一些东西,找到一些感觉“正确”的东西。 对我来说,这感觉“正确”。

我真的很想发挥创意,使用 CSS 自定义属性,而不是求助于 SCSS。 我喜欢自定义属性和值可以在客户端更新,而 SCSS 中的计算值是在构建时编译的,并且一直保持不变。 同样,这正是我非常想使用 JavaScript 的地方。 但是,我已经铺好床了,只能躺在里面。

如果您之前查看过编译的 CSS,那么您将看到计算出的值

/* Yes, Autoprefixer is in there... */
.checkerboard > div:nth-child(1) {
  -webkit-animation-delay: 4.5714285714s;
          animation-delay: 4.5714285714s;
}

.checkerboard > div:nth-child(2) {
  -webkit-animation-delay: 5.2857142857s;
          animation-delay: 5.2857142857s;
}

.checkerboard > div:nth-child(3) {
  -webkit-animation-delay: 2.7142857143s;
          animation-delay: 2.7142857143s;
}

.checkerboard > div:nth-child(4) {
  -webkit-animation-delay: 1.5714285714s;
          animation-delay: 1.5714285714s;
}

嗯,也许那个动画应该可选……

有些人对运动和移动很敏感,所以最好改变一下,让瓦片只有在用户喜欢的情况下才设置样式和动画。 我们为此有一个媒体查询!

@media screen and (prefers-reduced-motion: no-preference) {
  .checkerboard > div {
    animation-name: poof;
    animation-duration: 0.25s;
    animation-fill-mode: forwards;
    background: #fff;
  }
  .checkerboard > div:nth-child(even) {
    background: #2f2f2f;
  }
}

就是这样!

这是那个演示,再来一次