Cuando tenía 10 años, recuerdo que mi primo visitó nuestra casa. Era (y sigue siendo) un chico genial, del tipo que traería su propio juego de ajedrez autoprogramado en un disquete. Y su versión del ajedrez era tan genial como él porque una pieza del tablero desaparecía después de cada movimiento.
¿Incluso más genial? Cada pieza que desaparecía del tablero de juego revelaba una imagen bastante elegante.
Fue un juego realmente difícil.
Pensé que el mismo tipo de idea sería una interfaz de usuario bastante ingeniosa. Excepto que, tal vez, en lugar de requerir la interacción del usuario para revelar el fondo, simplemente podría reproducirse como una animación. Aquí es donde aterricé:
La idea es bastante simple y hay muchas otras formas de hacerlo, pero aquí está el rastro de conejo que seguí…
Primero, creé un marcado
La imagen se puede manejar como fondo en CSS en el <body>
, o algunos <div>
que está diseñado para ser de un tamaño específico. Entonces, no hay necesidad de lidiar con eso todavía.
Pero el tablero de ajedrez es interesante. Ese es un patrón que tiene CSS Grid escrito por todas partes, así que elegí un elemento para que actuara como un contenedor de cuadrícula con un montón de otros <div>
elementos en su interior. No sé cuántas fichas/cuadrados/lo que sea que tenga un tablero de ajedrez legítimo, así que elegí el número siete de la nada y lo cuadré para obtener un total de 49 cuadrados.
<div class="grid">
<div></div>
<!-- etc. -->
<div></div>
</div>
Sí, escribir todos esos divs es una molestia y JavaScript ciertamente podría ayudar. Pero si solo estoy experimentando y solo necesito la comodidad del desarrollador, ahí es donde el uso de Haml puede ayudar:
.grid
- 49.times do
%div
Todo sale igual al final. De cualquier manera, ¡eso me dio todo el marcado que necesitaba para comenzar a diseñar!
Configuración de la imagen de fondo
Una vez más, esto puede suceder como un background-image
sobre el <body>
o algún otro elemento, dependiendo de cómo se utilice, siempre y cuando cubra todo el espacio. Como necesitaba un contenedor de cuadrícula de todos modos, decidí usar eso.
.checkerboard {
background-image: url('walrus.jpg');
background-size: cover;
/* Might need other properties to position the image just right */
}
El degradado es parte del archivo de imagen de trama, pero podría haber sido inteligente con algún tipo de superposición en el <body>
usando un pseudo-elemento, como :after
. Diablos, esa es una técnica ampliamente utilizada aquí en el diseño actual de CSS-Tricks.
Estilo de la cuadrícula
Y sí, opté por CSS Grid. Hacer una cuadrícula de 7 × 7 es bastante fácil de esa manera.
.checkerboard {
background-image: url('walrus.jpg');
background-size: cover;
display: grid;
grid-template-columns: repeat(7, 1fr);
grid-template-rows: repeat(7, 1fr);
}
Me imagino que esto será mucho mejor una vez que veamos aspect-ratio
ampliamente respaldado, al menos si lo entiendo correctamente. El problema que tengo ahora es que la cuadrícula no se mantiene en ningún tipo de proporción. Eso significa que los mosaicos del tablero de ajedrez se vuelven blandos y similares en diferentes tamaños de ventana gráfica. Abucheo. Hay pequeñas cosas raras que podemos hacer mientras tanto, si eso es muy importante, pero decidí dejarlo como está.
Estilizando los azulejos
Alternan entre el blanco y un tono oscuro de gris, por lo que:
.checkerboard > div {
background-color: #fff;
}
.checkerboard > div:nth-child(even) {
background-color: #2f2f2f;
}
Lo crea o no, ¡nuestro marcado y estilo están listos! Todo lo que queda es…
Animando los mosaicos
Todo lo que la animación necesita hacer es hacer la transición de cada mosaico de opacity: 1;
a opacity: 0;
y las animaciones CSS son perfectas para eso.
@keyframes poof {
to {
opacity: 0;
}
}
¡Estupendo! ¡Ni siquiera necesité establecer un fotograma clave inicial! Todo lo que tenía que hacer era llamar a la animación en los mosaicos.
.checkerboard > div {
animation-name: poof;
animation-duration: 0.25s;
animation-fill-mode: forwards;
background: #fff;
}
Sí, podría haber usado el animation
propiedad abreviada aquí, pero a menudo me resulta más fácil desglosar sus propiedades constituyentes individualmente porque… bueno, hay tantas malditas de ellas y las cosas se vuelven difíciles de leer e identificar en una sola línea.
Si te preguntas por qué animation-fill-mode
es necesario aquí, es porque evita que la animación vuelva al inicio de la animación cuando se establece en forwards
. En otras palabras, cada mosaico permanecerá en opacity: 0;
cuando finaliza la animación en lugar de volver a aparecer.
Realmente, realmente quería hacer algo inteligente e inteligente para tambalear el animation-delay
de los mosaicos, pero me topé con un montón de paredes y, finalmente, decidí deshacerme de mi esfuerzo de usar CSS 100% vainilla por un poco de SCSS ligero. De esa manera, podría recorrer todos los mosaicos y compensar la animación de cada uno con una función bastante estándar. Entonces, ¡perdón por el cambio abrupto! Eso fue solo parte del viaje.
$columns: 7;
$rows: 7;
$cells: $columns * $rows;
@for $i from 1 through $cells {
.checkerboard > div:nth-child(#{$i}) {
animation-delay: (random($cells) / $columns) + s;
}
}
Vamos a desglosarlo:
- Hay variables para el número de columnas de la cuadrícula (
$columns
), filas de cuadrícula ($rows
) y el número total de celdas ($cells
). Ese último es el producto de multiplicar los dos primeros. Si sabemos que siempre estamos trabajando con una cuadrícula que es un cuadrado perfecto, entonces podríamos refactorizar eso un poco para calcular las celdas numéricas con exponentes. - Luego, para cada instancia de celdas entre
1
y el número total de$cells
(que es 49 en este caso), cada ficha individual recibe unaanimation-delay
basado en su:nth-child()
valor. Entonces, el primer mosaico esdiv:nth-child(1)
, entoncesdiv:nth-child(2)
, y así. Vea el CSS compilado en la demostración y verá cómo funciona todo.
.checkerboard > div:nth-child(1) {}
.checkerboard > div:nth-child(2) {}
/* etc. */
- Finalmente, el
animation-delay
es un cálculo que toma un número aleatorio entre1
y el número total de$cells
, dividido por el número de$columns
con segundos añadidos al valor. ¿Es esta la mejor manera de hacerlo? No se. Se trata de jugar un poco con las cosas y aterrizar en algo que te parezca “correcto”. Esto me pareció “correcto”.
Tenía muchas ganas de ser creativo y usar las propiedades personalizadas de CSS en lugar de recurrir a SCSS. Me gusta que las propiedades y los valores personalizados se puedan actualizar en el lado del cliente, a diferencia de SCSS, donde los valores calculados se compilan en la compilación y permanecen así. Nuevamente, aquí es exactamente donde estaría muy tentado de buscar JavaScript en su lugar. Pero, hice mi cama y tengo que acostarme en ella.
Si echaste un vistazo al CSS compilado anteriormente, habrías visto los valores calculados:
/* 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;
}
Hmm, tal vez esa animación debería ser opcional…
Algunas personas son sensibles al movimiento y al movimiento, por lo que probablemente sea una buena idea cambiar las cosas para que los mosaicos solo tengan estilo y animación si, y solo si, el usuario lo prefiere. ¡Tenemos una consulta de medios para eso!
@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;
}
}
¡Ahí tienes!
Aquí está esa demostración una vez más: