Solo haz una animación muy muy simple:
p { animation: appear 1s linear 1; font-family:monospace; } @keyframes appear { from { opacity: 0; } to { opacity: 1; } } <p>Thank you for any helps!</p> Funciona, pero solo estoy pensando si es posible hacer que la primera letra aparezca primero, después de que aparezca la primera letra, luego la segunda y finalmente la última letra (ahora todo el contenido de p aparecerá al mismo tiempo)
¿CSS tiene selectores para seleccionar todos los caracteres en el elemento y es posible lograr el efecto usando solo CSS?
Solo conozco el selector de first-letter y last-letter en css, pero no estoy seguro si css tiene un selector para cada letra
Si no solo con CSS, ¿también estaría bien con la solución JS?
Agradezco cualquier ayuda brindada ~
Aquí hay un enfoque de vainilla JS. Primero extraemos el texto, vaciamos el elemento y luego lo reconstruimos un carácter a la vez.
let p = document.querySelector('.anim'); // store value let t = p.innerText.split(''), counter = 0 p.innerHTML = ''; let inter = setInterval(() => { if (counter == t.length) clearInterval(inter) else p.insertAdjacentHTML('beforeend', `<span>${t[counter++]}</span>`); }, 100) p.anim span { animation: appear 1s linear 1; } @keyframes appear { from { opacity: 0; } to { opacity: 1; } } <p class='anim'>Thank you for any helps!</p>Si una solución basada en JS es aceptable, puede lograr esto fácilmente usando una combinación de manipulación DOM (envolviendo cada carácter que no sea espacio en un elemento <span> ) y luego alternando secuencialmente una clase que ejecuta la animación.
La parte secuencial se puede lograr simplemente recorriendo el elemento <span> generado y luego esperando que se resuelva una promesa.
En su pregunta, no está claro cómo desea que se calcule un retraso: simplemente asumo que desea un retraso arbitrario/personalizable. En este caso, una simple función de sleep basada en promesas puede hacer el trabajo:
function sleep(ms = 0) { return new Promise(r => setTimeout(r, ms)); } async function fadeInCharacters(el) { // NOTE: Use a custom data- attribute to ensure we only target the <span> elements we generate el.innerHTML = el.textContent.replace(/([^\s])/g, '<span data-animate>$1</span>'); for (const span of el.querySelectorAll('span[data-animate]')) { span.classList.add('animate'); await sleep(100); } } fadeInCharacters(document.querySelector('p')); .animate { animation: appear 1s ease-in-out 1 forwards; } span { opacity: 0; } @keyframes appear { from { opacity: 0; } to { opacity: 1; } } <p>Thank you for any help!</p> Si desea esperar a cada carácter antes de desaparecer en el siguiente , cambie la función await por algo que se conecte al evento animationend , aunque me inclino a creer que esto no es lo que pretende. Solo poniéndolo aquí por el bien de la exhaustividad:
function onAnimationEnd(el) { return new Promise(r => el.addEventListener('animationend', () => r())); } async function fadeInCharacters(el) { // NOTE: Use a custom data- attribute to ensure we only target the <span> elements we generate el.innerHTML = el.textContent.replace(/([^\s])/g, '<span data-animate>$1</span>'); for (const span of el.querySelectorAll('span[data-animate]')) { span.classList.add('animate'); await onAnimationEnd(span); } } fadeInCharacters(document.querySelector('p')); .animate { animation: appear 1s ease-in-out 1 forwards; } span { opacity: 0; } @keyframes appear { from { opacity: 0; } to { opacity: 1; } } <p>Thank you for any help!</p>