Soy nuevo en animaciones pero quiero animar un cargador de esqueleto. Quiero que comience desde la izquierda con un ancho del 0 %, luego vaya hacia la derecha, con un ancho del 100 %, y luego haga que el cargador vaya a cero pero al revés para que termine a la derecha con un ancho del 0 %. Mi problema es que no puedo hacer que la animación salga de izquierda a derecha. Estoy usando reaccionar con componentes con estilo. aquí está mi código:
const reveal = keyframes` 0% { width: 0%; } 50% { width: 100%; } 100% { width: -100%; } `; const StyledSkeleton = styled.div` height: 40px; font-size: 64px; line-height: 70px; overflow: hidden; background-color: ${colors.LOADER_BACKGROUND}; background-size: 100%; animation-name: ${reveal}; animation-duration: 2s; animation-timing-function: ease-in; animation-delay: 0s; animation-iteration-count: infinite; animation-direction: normal; `;
Así es como terminé implementándolo. Alguien más podría tener un caso de uso diferente, pero la respuesta de @yeniv me permitió llegar a esta solución. Estoy usando NextJS con TypeScript y componentes con estilo.
import React from 'react'; import styled, { keyframes } from 'styled-components'; import { colors } from '../../../styles'; interface SkeletonProps { delay?: number; style?: object; children?: React.ReactNode; } export const Skeleton = ({ delay, children, style = {} }: SkeletonProps): JSX.Element => { return ( <div> <Container style={{...style}}> <TextContainer> {children && children} </TextContainer> <StyledSkeleton delay={delay} /> </Container> </div> ); }; export default Skeleton; const reveal = keyframes` 0% { display: none; opacity: 0; } 50% { opacity: 0; } 100% { display: inline-block; opacity: 1; } `; const animate = keyframes` 0% { left: 0; right: 100%; } 50% { left: 0; right: 0; } 100% { left: 100%; right: 0; } `; const Container = styled.div` position: relative; height: 40px; width: 100%; `; interface TextContainerProps { delay?: number; } const TextContainer = styled.span<TextContainerProps>` animation-name: ${reveal}; animation-duration: 2s; animation-delay: ${props => `${props.delay}s`}; animation-timing-function: ease-in; animation-iteration-count: 1; `; interface StyledSkeletonProps { delay?: number; } const StyledSkeleton = styled.div<StyledSkeletonProps>` position: absolute; top: 0; bottom: 0; overflow: hidden; background-color: ${colors.LOADER_BACKGROUND}; background-size: 100%; animation-name: ${animate}; animation-duration: 1.5s; animation-delay: ${props => `${props.delay}s`}; animation-timing-function: ease-in; animation-iteration-count: 1; `;
En lugar de usar el ancho, puede animar el tamaño del cargador usando la posición absoluta.
.container { width: 100%; height: 40px; position: relative; } .loader { position: absolute; top: 0; bottom: 0; background-color: red; animation-name: animate; animation-duration: 2s; animation-timing-function: ease-in; animation-iteration-count: infinite; } @keyframes animate { 0% { left: 0; right: 100%; } 50% { left: 0; right: 0; } 100% { left: 100%; right: 0; } }
<div class='container'> <div class='loader'></div> </div>