Técnicas CSS para el efecto dominó material

Una guía sobre diferentes técnicas para el efecto dominó usando CSS y JavaScript

Recientemente tuve que implementar el efecto dominó del diseño de materiales en una aplicación web. Y luego me di cuenta de que no tenía idea de cómo se implementó. Esto me llevó a un viaje para estudiar las implementaciones existentes, e incluso idear una nueva técnica que podría serle útil.

¿Qué es este efecto dominó?

Espera, ¿no conoces el efecto dominó del diseño de materiales de Google? ¿Cuántos años llevas viviendo en una cueva?

El efecto dominó se usa cuando presiona un botón. Funciona de la misma manera para las interacciones de mouse o táctil.

La posición en la que hace clic o toca el botón se denomina punto de contacto. A partir de ahí, se envía una onda que se mueve hacia afuera, perdiendo opacidad a medida que crece hasta llenar todo el botón. Luego desaparece por completo.

La dinámica de este efecto dominó es similar a las ondas que se producen al tocar una superficie líquida o al arrojar una roca a un lago.

Las ondas que encontrarás en la web

Después de investigar un poco, pude encontrar dos técnicas principales que se utilizan para implementar el efecto dominó en las aplicaciones web.

Usando :: después del pseudo-elemento

Usando esta técnica, el pseudo-elemento :: after del botón se diseña como un círculo semitransparente y se anima a crecer y desvanecerse. El botón del contenedor debe tener desbordamiento: oculto para que el círculo nunca se desborde fuera de la superficie del botón, y posición: relativa para facilitar la colocación del círculo dentro del botón. Puede leer más detalles de esta técnica en este artículo de Ionuț Colceriu.

Una de las mejores cosas de esta técnica es que es una solución CSS pura para el efecto dominó. Sin embargo, el efecto dominó siempre comienza desde el centro del botón, en lugar del punto de contacto. Esa no es la respuesta más natural.

Podría mejorarse usando JavaScript para almacenar el punto de contacto y usarlo para posicionar la onda. Eso es exactamente lo que ha hecho material.io para su componente de ondulación web. Utiliza variables CSS para almacenar el punto de contacto, y el pseudo-elemento :: after usa estas variables para el posicionamiento.

Usar elementos secundarios

En esencia, esta técnica utiliza la misma estrategia que antes. Pero en lugar de un pseudo-elemento, agrega un elemento span dentro del botón, que luego se puede colocar a través de JavaScript. Esta técnica se describe en este artículo por Jhey Tompkins.

La implementación más simple crea un espacio para cada clic en el botón y usa la posición del mouse en el evento de clic para cambiar la posición del espacio. Una animación CSS hace que el lapso crezca y se desvanezca hasta volverse completamente transparente. Podemos optar por eliminar el lapso del DOM una vez que finalice la animación, o simplemente dejarlo allí debajo de la alfombra; nadie notará realmente un lapso transparente dando vueltas.

Encontré otra variación de esto, en la que el elemento hijo es un svg en lugar de un intervalo, y el svg está animado a través de JavaScript. Dennis Gaebel explica esta variación, pero en esencia parece ser la misma, y ​​quizás permite utilizar formas y efectos SVG complejos.

Un problema con las entradas de envío

Ambas técnicas descritas anteriormente parecen geniales. Pero esto es lo que sucede cuando intenté aplicarlos en los elementos de entrada con type = submit:

¿Por qué no funcionan?

El elemento de entrada es un elemento reemplazado. En resumen, eso significa que es muy poco lo que puedes hacer con esos elementos, con respecto a DOM y CSS. Específicamente, no pueden tener elementos secundarios, y tampoco pseudoelementos. Ahora está claro por qué estas técnicas fallan.

Por lo tanto, si está utilizando Diseño de materiales, es mejor mantenerse alejado de la entrada [type = submit] y atenerse a los elementos del botón. O simplemente sigue leyendo.

Agregar ondas para enviar entradas

En la aplicación web en la que estaba trabajando, ya teníamos muchos botones de envío. Cambiarlos para que se conviertan en un elemento diferente requeriría mucho trabajo y un alto riesgo de romper las hojas de estilo y la lógica de JavaScript. Así que tuve que descubrir cómo agregar ondas a los botones de envío existentes.

Usando un contenedor de envoltura

Rápidamente me di cuenta de que podía envolver el botón de enviar dentro de un elemento de bloque en línea y usar el elemento de bloque en línea como la superficie de ondulación. Aquí hay una demostración rápida:

Si bien me gusta esta solución por su simplicidad, todavía me obligaba a cambiar el marcado en demasiados lugares. Y sabía que sería una solución frágil: los nuevos desarrolladores entrarían en el proyecto y crearían botones de envío sin envolverlos adecuadamente en una superficie ondulada. Así que seguí buscando otras soluciones que no requerían cambiar el DOM.

Gradientes radiales

La sintaxis de degradado radial me permite controlar tanto el centro como el tamaño del degradado. Por supuesto, también me permite controlar el color del degradado, incluidos los colores semitransparentes. Y nunca desborda el elemento al que se aplica. ¡Parece que ya hace todo lo que necesito!

No tan rápido ... falta una cosa: la propiedad de imagen de fondo no es animable. No pude hacer que el gradiente crezca y se desvanezca a transparente usando animaciones CSS. Logré hacerlo crecer animando la propiedad de tamaño de fondo, pero eso fue todo lo que pude hacer.

Intenté algunas otras cosas, como tener un círculo de desvanecimiento como imagen animada (usando el formato apng), y lo apliqué como imagen de fondo. Pero luego no pude controlar cuándo comenzó y terminó el bucle de imágenes.

Finalmente, una solución con JavaScript.

Lo que no puedes hacer en CSS, puedes hacerlo en JavaScript. Después de pasar más tiempo del que estoy dispuesto a admitir tratando de hacer que este efecto funcione usando animaciones CSS, simplemente me di por vencido y decidí escribir la animación en JavaScript.

Comencé con la solución de gradiente radial anterior, y usé window.requestAnimationFrame para hacer una animación fluida del gradiente radial, creciendo y desvaneciéndose. Aquí está mi solución final:

Conclusión

Por lo tanto, es posible tener efectos de onda en los botones de envío, pero no solo con CSS.

No pude encontrar esta técnica documentada en ninguna parte de la web, así que la llamo mía. La técnica de ondulación de Leonardo no requiere cambios en DOM, y funciona para cualquier elemento porque no se basa en pseudoelementos o elementos secundarios. Sin embargo, no es una solución perfecta.

Primero, hay rendimiento. Al animar el gradiente con JavaScript, pierde muchas optimizaciones del navegador. Pero, dado que la única propiedad que se cambia es la imagen de fondo, sospecharía que los navegadores no necesitarían refluir, y solo requerirían volver a aplicar los estilos y volver a pintar el elemento. En la práctica, eso es exactamente lo que sucede, y el rendimiento es realmente bueno. La excepción a esa declaración es Firefox Mobile, que por alguna razón no se mantiene al día con la animación. (editar: la animación es fluida en las versiones modernas de Firefox Mobile)

En segundo lugar, la técnica utiliza la propiedad de imagen de fondo del botón. Si su diseño requiere que sus botones tengan una imagen aplicada a su fondo, el efecto dominó lo anularía. Si realmente necesita esa imagen en su diseño, entonces el JavaScript podría modificarse para dibujar el degradado radial en la parte superior de la imagen de fondo existente.

Tercero, esto no parece funcionar en Internet Explorer. Sin embargo, no veo ninguna razón por la que no debería funcionar con IE10 y superior. Tal vez sea porque IE usa una sintaxis diferente para el degradado radial. Pero, ¿a quién le importa IE hoy en día? (editar: este método funciona sin problemas en Internet Explorer 11)