Recrea las animaciones Vision Pro de Apple en CSS
Las animaciones de los productos de Apple, especialmente los desmontajes (término técnico), siempre han sido inspiradoras. Pero estas animaciones de vanguardia siempre utilizan JavaScript y otras tecnologías. Además, no siempre responden (o al menos Apple cambia a imágenes estáticas de un ancho específico).
Me sorprendieron las recientes capacidades de animación de desplazamiento de CSS y me pregunté si era posible recrear una de estas animaciones usando solo CSS. y Hazlo responsivo. (De hecho, CSS ha sido Último intento en esta publicación..) El que voy a probar es de Sitio web profesional visual Para verlo, debes desplazarte hacia abajo hasta encontrar un fondo negro, un poco más abajo en la página. si tu también perezoso Bueno… ve a verlo por ti mismo, y/o deciden cambiar la animación después de que este artículo se publique, puedes ver este video:
notas: Si bien la versión de Apple funciona en todos los principales navegadores, al momento de escribir este artículo, la versión solo CSS no funciona en Firefox.
animación de manzana
Lo primero que debemos hacer es determinar qué sucedió en la animación original. Hay dos etapas principales.
La primera etapa: “explosión” del hardware
Tres componentes electrónicos surgen del dispositivo Vision Pro en la parte inferior de la página. Cada uno de los tres componentes es un conjunto de dos imágenes que se encuentran delante y detrás de los otros componentes, como los subrollos de un panecillo de hot dog que rodea un palito de pan. (Sí, es una analogía extraña, pero entiendes la idea, ¿no?)
El primer componente más externo (subvolumen) contiene las imágenes más adelante y más atrás, lo que hace que parezca como si estuviera delante y detrás de los otros componentes.
El siguiente componente (bollos para hot dogs) se envuelve de manera similar al tercer componente (palitos de pan). Esto proporciona profundidad, interés visual y un efecto 3D, ya que las áreas transparentes en cada imagen permiten que se vea la imagen detrás de ella.
Etapa 2: Voltear al ocular
El segmento final de la animación de Vision Pro gira la unidad con un movimiento suave para revelar el ocular. Apple logra esto con video, usando JavaScript para avanzar el video a medida que el usuario se desplaza.
Recreémoslos, una etapa a la vez.
Hardware “explosivo”
Como Apple ya ha creado seis imágenes para el componente, podemos tomarlas prestadas. Al principio comencé con un montón de img etiquetas en div y usar position: fixed Mantenga la imagen al final de la página y position: absolute Déjelos superponerse entre sí. Sin embargo, cuando hice esto, me encontré con dos problemas: (1) no respondía: al reducir el ancho de la ventana gráfica, la imagen desaparecía de la pantalla y (2) Vision Pro no podía desplazarse para aparecer o desaparecer como lo hace en el sitio web de Apple.
Después de pensar un poco en esta pregunta, volví y miré cómo la construyó Apple. Crearon una imagen de fondo para cada imagen. background-position: bottom centery utilizar background-size: cover para mantener una relación de aspecto consistente. Todavía necesito que puedan superponerse, pero no quiero que se salgan del camino del flujo. position: absolute yo hice esto display: grid en sus elementos principales y asígnalos todos a la misma área de la cuadrícula.
.visionpro { /* the overarching div that holds all the images */
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr;
}
.part { /* each of the images has a part class */
grid-area: 1 / 1 / 2 / 2;
}
Como solía decir mi profesor de lógica en sus primeros años, “¡Ahora cocinamos con gas!” (Realmente no sé cómo se aplica eso aquí, pero parece apropiado. Es un poco ilógico, lo sé).
Luego comencé a animar los componentes. yo vengo de un Desplazarse por la línea de tiempo Esto me permitirá fijar la línea de tiempo de la animación para desplazarse por todo el html elemento, pero me di cuenta de que si Vision Pro (es decir, el elemento que contiene todas las imágenes) debía desplazarse dentro y fuera de la ventana gráfica, entonces debería cambiar a Ver línea de tiempo De esta manera, al desplazar el elemento a la vista se inicia la animación, en lugar de intentar estimar el porcentaje de fotogramas clave para comenzar desde la posición del elemento a la vista (una forma bastante frágil y que no responde de hacer las cosas).
Uso de libros de texto de Vision Pro desplazándose hacia la vista, pausando mientras se reproduce la animación y luego desplazándose fuera de la vista position: sticky. Entonces creé un contenedor div Vision Pro completamente encapsulado div y configúrelo en position: relative. Empujé el contenedor div Baja por la ventana y establece el margen superior. top En Visión Pro div a 0. Luego puede desplazarse hacia arriba hasta position: sticky Sostenga el Vision Pro en su lugar, realice la animación y luego, cuando el contenedor se haya desplazado por completo, llevará el Vision Pro consigo. div Sube y aléjate de la ventana.
Ahora, resolviendo el problema del movimiento de componentes. cuando lo uso por primera vez translate Para mover la imagen hacia arriba, quise aprovechar el orden natural de los elementos para apilar todo ordenadamente dentro de mi pavo empanizado. Por desgracia, el astuto motor de optimización del navegador colocó mi sub roll completamente encima de mi pan de hot dog, que a su vez se colocó completamente sobre mi palito de pan. Afortunadamente, usando z-index Me permite separar capas y superponerlas, lo cual es parte de por qué la versión de Apple se ve tan bien.
Otro problema que tengo es que no puedo mover el componente hacia arriba de manera confiable y rápida cuando el tamaño es menor que el ancho de 960 píxeles de la imagen. Deben estar lo suficientemente lejos como para no interferir con la segunda etapa, pero no tan lejos como para quedar completamente fuera de la ventana gráfica. (¿Dónde están los osos y los Ricitos de oro cuando los necesitas?) Afortunadamente, como suele suceder, el álgebra salvó mis tukus. Como tengo las dimensiones de una imagen de tamaño completo (960 px x 608 px) y el ancho total de la imagen es igual al ancho de la ventana gráfica, puedo escribir una ecuación como la siguiente para obtener la altura y usarla en el cálculo de traducción para calcular qué tan lejos se ha movido cada componente.
--stage2-height: calc(min(100vw, 960px) * 608 / 960);
Sin embargo, cuando la ventana gráfica es más corta que 608px y que 960px Porque el ancho de la imagen ya no es igual a 100vw. Originalmente escribí una ecuación similar para calcular el ancho:
--stage2-width: calc(min(100vh, 608px) * 960 / 608);
Pero es sólo a una altura de 608px o menos, y ninguno funciona cuando se aplica el otro. Esta sería una solución sencilla utilizando una declaración “if”. Aunque CSS tiene una if() Función Mientras escribo esto, no funciona en Safari. Si bien sé que todo esto no funcionará en Firefox, no quiero dejar obsoletos otros navegadores si puedo. Entonces, lo arreglé con consultas de medios:
:root {
--stage2-height: calc(min(100vw, 960px) * 608 / 960);
--stage2-width: calc(min(100vh, 608px) * 960 / 608);
}
@media screen and (max-height: 608px) {
:root {
--stage2-height: calc(var(--vid-width) * 608 / 960);
}
}
Me di una palmadita en la espalda por mi genio matemático y mi capacidad para resolver problemas, hasta que me di cuenta (como ustedes, sabelotodos, habrán descubierto) que si la altura es menor que 608pxentonces es igual a 100vh. (Sí, vh es una unidad complejaespecialmente en iOS, pero para esta prueba de concepto ignoré sus deficiencias).
Entonces, lo que realmente necesito es:
:root {
--stage2-height: calc(min(100vw, 960px) * 608 / 960);
}
@media screen and (max-height: 608px) {
:root {
--stage2-height: 100vh;
}
}
Pero independientemente de mis tangentes matemáticas (¡ja! ¡Horrible juego de palabras matemático!), esto me permite basar la traslación vertical en la altura de la figura de la etapa 2, por ejemplo:
translate: 0 calc(var(--stage2-height) * -1 - 25vh);
…para que no interfieran con la animación de la segunda etapa. Dicho esto, no es perfecto y la ventana gráfica es más pequeña que 410pxtodavía necesito usar consultas de medios para ajustar la altura.
voltear al ocular
Desafortunadamente, no hay forma de iniciar una película usando solo CSS o modificar la velocidad de fotogramas usando solo CSS. Sin embargo, podemos crear un conjunto de fotogramas clave que cambien la imagen de fondo con el tiempo, por ejemplo:
/* ... */
50% {
background-image: url(imgs/video/00037.jpg);
z-index: -1;
}
51% {
background-image: url(imgs/video/00039.jpg);
z-index: -1;
}
52% {
background-image: url(imgs/video/00041.jpg);
z-index: -1;
}
/* ... */
(Dado que se trata de más de 60 imágenes, no te daré el conjunto completo de fotogramas clave, pero puedes echar un vistazo cssvideo fotograma clave completo bolígrafo codificador Para el Monty completo. )
Sin embargo, la desventaja de esto es que en lugar de descargar un archivo de vídeo, tenemos que descargar más de 60 archivos para lograr el mismo efecto. Notarás que la numeración del archivo omite un número entre cada iteración. Reduje el número de fotogramas a la mitad para que no tengamos más de 120 imágenes para descargar. (Es posible que puedas usar sprites para acelerar las cosas, pero como esto es más una prueba de concepto que una solución lista para producción, no tengo la paciencia para unir más de 60 imágenes).
Incluso cuando se ejecuta la demostración localmente, la animación en el desplazamiento inicial está un poco entrecortada.
Entonces agregué:
<link rel="preload" as="image" href="https://css-tricks.com/recreating-apples-vision-pro-animation-in-css/imgs/video/00011.jpg">
….para cada imagen, incluya la imagen componente. Esto es útil porque el servidor no tiene que analizar el CSS antes de descargar todas las imágenes.
Usando la misma línea de tiempo de vista que en la etapa 1, realizamos una animación, la movemos a su lugar y luego cssvideo La animación y el ocular parecen “voltear”.
animation: vpsf-move forwards, cssvideo forwards;
animation-timeline: --apple-vp, --apple-vp;
sintonia FINA
Si bien la vista de la línea de tiempo es excelente, la animación no siempre comienza o termina como quiero. Ingresar animation-range. Aunque utilicé muchas opciones en todos .partSí
animation-range: contain cover;
Esto garantiza que el elemento Vision Pro esté dentro de la ventana gráfica antes de iniciar (contain) y no completa completamente la animación hasta que desaparece de la vista (cover). Esto funciona bien para las piezas porque quiero tenerlas completamente a la vista antes de que los componentes comiencen a elevarse y, dado que sus puntos finales no importan, pueden seguir moviéndose hasta que desaparezcan de la pantalla.
Sin embargo, para la segunda fase, quería asegurarme de que la animación de giro terminara antes de salir de la pantalla, así que para esta fase usé:
animation-range: cover 10% contain;
Ambos cover y 10% Para hacer referencia al comienzo de la animación, utilice cover palabra clave, pero retrasa su hora de inicio en un 10%. este contain Asegúrese de que la animación termine antes de que comience a salir de la pantalla.
Esto es de lo que se trata:
Si su navegador aún no lo admite, mire el vídeo a continuación:
en conclusión
CSS definitivamente ha recorrido un largo camino y, si bien uso algunas funciones de vanguardia, también hay muchas adiciones relativamente recientes que lo hacen posible.
Usando la línea de tiempo de desplazamiento podemos adjuntar animaciones al desplazamiento de todo el elemento o solo cuando el elemento está a la vista. este animation-range Las propiedades nos permiten ajustar la animación a medida que ocurre. position: sticky Nos permite mantener fácilmente algo en la pantalla mientras lo animamos mientras se desplaza. El diseño de cuadrícula permite superponer elementos sin sacarlos del flujo. incluso calc()las unidades de ventana gráfica, las propiedades personalizadas y las consultas de medios desempeñan un papel para que esto sea posible. Esto ni siquiera incluye innovaciones HTML como la precarga. ¡Excelente!
Quizás deberíamos agregar una W después de WWW: The World Wide maravilloso red. Vale, vale, ya puedes dejar de quejarte, pero no me equivoco…