Introducción
Hace unos días, mientras escuchaba una canción antigua de mi juventud, se me ocurrió implementar este diseño web que combina tres efectos visuales interessantes: un cielo nocturno con lluvia de meteoros, comentarios en pantalla tipo弹幕y música de fondo. A continuación explico cómo implementar cada componente.
Resultado final
Primer paso: Fondo de lluvia de meteoros
1.1 Configuración del cielo nocturno
html,
body {
width: 100%;
height: 100%;
margin: 0;
overflow: hidden;
background: radial-gradient(ellipse at bottom, #1b2735 0%, #090a0f 100%)
}
1.2 Estructura HTML
<div id="meteor-container">
<div class="meteor" style="top: 0px;left: 500px;"></div>
</div>
1.3 Estilos CSS para los meteoros
#meteor-container {
margin: 0 auto;
width: 100vw;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 2;
}
.meteor {
display: block;
width: 1px;
background: transparent;
position: relative;
opacity: 0;
filter: drop-shadow(0 0 6px #ffffff);
animation: meteor-fall 3.5s linear infinite;
-webkit-animation: meteor-fall 3.5s linear infinite;
-moz-animation: meteor-fall 3.5s linear infinite;
}
.meteor::after {
content: '';
display: block;
border: 0px solid #fff;
border-width: 0px 90px 2px 90px;
border-top-right-radius: 100%;
border-bottom-right-radius: 100%;
border-color: transparent transparent transparent rgba(255, 255, 255, .6);
box-shadow: 0 0 1px 0 rgba(255, 255, 255, .1);
transform: rotate(-45deg) translate3d(1px, 3px, 0);
-webkit-transform: rotate(-45deg) translate3d(1px, 3px, 0);
-moz-transform: rotate(-45deg) translate3d(1px, 3px, 0);
transform-origin: 0% 100%;
-webkit-transform-origin: 0% 100%;
-moz-transform-origin: 0% 100%;
animation: meteor-tail 3.5s linear initial;
-webkit-animation: meteor-tail 3.5s linear initial;
-moz-animation: meteor-tail 3.5s linear initial;
}
@keyframes meteor-fall {
0% {
opacity: 0;
transform: scale(0.5) translate3d(0, 0, 0);
-webkit-transform: scale(0.5) translate3d(0, 0, 0);
-moz-transform: scale(0.5) translate3d(0, 0, 0);
}
50% {
opacity: 1;
transform: translate3d(-300px, 300px, 0);
-webkit-transform: translate3d(-300px, 300px, 0);
-moz-transform: translate3d(-300px, 300px, 0);
}
100% {
opacity: 0;
transform: scale(1.2) translate3d(-500px, 500px, 0);
-webkit-transform: scale(1.2) translate3d(-500px, 500px, 0);
-moz-transform: scale(1.2) translate3d(-500px, 500px, 0);
}
}
@keyframes meteor-tail {
0% {
border-width: 0px 80px 2px 80px;
}
50% {
border-width: 0px 90px 2px 90px;
}
100% {
border-width: 0px 45px 2px 45px;
}
}
1.4 Generación dinámica de meteoros con JavaScript
const container = document.getElementById("meteor-container");
function generarNumeroAleatorio(maximo, minimo) {
return Math.floor(Math.random() * (maximo - minimo + 1) + minimo);
}
// Generar meteoros dinámicamente
for (let i = 0; i < 30; i++) {
const nuevoMeteor = document.createElement("div");
nuevoMeteor.className = "meteor";
nuevoMeteor.style.top = generarNumeroAleatorio(300, -100) + "px";
nuevoMeteor.style.left = generarNumeroAleatorio(1600, 300) + "px";
container.appendChild(nuevoMeteor);
}
const meteoros = document.getElementsByClassName("meteor");
// Aplicar retrasos de animación aleatorios
for (let j = 0; j < meteoros.length; j++) {
meteoros[j].style.animationDelay = j % 6 === 0 ? "0s" : j * 0.8 + "s";
}
Segundo paso: Sistema de comantarios en pantalla
2.1 Estructura HTML
<div class="danmaku-container"></div>
2.2 Estilos CSS
.danmaku-container {
width: 100%;
height: 100%;
position: relative;
z-index: 10;
}
@keyframes scroll-left {
from {
left: 100%;
transform: translateX(0);
}
to {
left: 0;
transform: translateX(-100%);
}
}
.comment-item {
position: absolute;
top: 50%;
left: 100%;
width: 100%;
color: #fff;
}
2.3 Lógica JavaScript para mostrar comentarios
const mensajes = [
"¡Aterrizaje exitoso!",
"Advertencia de tentación",
"Consejo: sube el volumen o usa auriculares",
"¡Escudo de comentarios activado!",
"Aunque talvez no nos volvamos a ver, solo quería decirte que me gustas",
"¡Contenido de alto impacto!",
"Nunca había visto a alguien tan desvergonzado",
"¡Celebración de final!",
"¡Aterrizaje exitoso!",
"Advertencia de tentación",
"Consejo: sube el volumen o usa auriculares"
];
const contenedor = document.querySelector(".danmaku-container");
function obtenerPosicionAleatoria() {
return Math.floor(Math.random() * (700 + 50) - 50);
}
function obtenerDuracionAleatoria() {
return Math.floor(Math.random() * 50);
}
function obtenerRetrasoAleatorio() {
return Math.floor(Math.random() * 60);
}
mensajes.forEach(texto => {
const elemento = document.createElement("div");
elemento.classList.add("comment-item");
elemento.style.top = obtenerPosicionAleatoria() + "px";
elemento.style.animation = `scroll-left ${obtenerDuracionAleatoria()}s linear ${obtenerRetrasoAleatorio()}s`;
elemento.textContent = texto;
contenedor.appendChild(elemento);
});
Tercer paso: Música de fondo, imagen de fondo e interacción con clics
3.1 Reproducción de música
<audio src="musica/fondo.mp3" autoplay loop></audio>
3.2 Imagen de fondo
#meteor-container {
margin: 0 auto;
width: 100vw;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 2;
background-image: url("https://imagen-ejemplo.com/galaxia.jpg");
background-size: contain;
background-repeat: no-repeat;
background-position: 50% 50%;
}
3.3 Efecto de estrelllas al hacer clic
Estilos CSS
.click-star {
position: fixed;
display: block;
color: #fff;
width: 0px;
height: 0px;
border-right: 10px solid transparent;
border-bottom: 7px solid #fff;
border-left: 10px solid transparent;
transform: rotate(35deg);
filter: drop-shadow(0 0 6px #ffffff);
}
.click-star::before {
border-bottom: 8px solid #fff;
border-left: 3px solid transparent;
border-right: 3px solid transparent;
position: absolute;
height: 0;
width: 0;
top: -4.5px;
left: -6.5px;
display: block;
content: '';
transform: rotate(-35deg);
}
.click-star::after {
position: absolute;
display: block;
color: #fff;
top: .3px;
left: -10.5px;
width: 0px;
height: 0px;
border-right: 10px solid transparent;
border-bottom: 7px solid #fff;
border-left: 10px solid transparent;
transform: rotate(-70deg);
content: '';
}
Lógica JavaScript
const estrellasCreadas = [];
let animacionActiva = true;
iniciarBucleAnimacion();
document.addEventListener('click', (evento) => {
generarEstrella(evento);
});
function generarEstrella(evento) {
const elemento = document.createElement("span");
elemento.className = "click-star";
estrellasCreadas.push({
elemento: elemento,
posicionX: evento.clientX - 5,
posicionY: evento.clientY - 5,
escala: 1,
transparencia: 1
});
document.body.appendChild(elemento);
}
function iniciarBucleAnimacion() {
for (let i = 0; i < estrellasCreadas.length; i++) {
if (estrellasCreadas[i].transparencia <= 0) {
document.body.removeChild(estrellasCreadas[i].elemento);
estrellasCreadas.splice(i, 1);
continue;
}
estrellasCreadas[i].escala += 0.04;
estrellasCreadas[i].transparencia -= 0.013;
estrellasCreadas[i].elemento.style.cssText =
"left:" + estrellasCreadas[i].posicionX + "px;" +
"top:" + estrellasCreadas[i].posicionY + "px;" +
"opacity:" + estrellasCreadas[i].transparencia + ";" +
"transform:scale(" + estrellasCreadas[i].escala + "," + estrellasCreadas[i].escala + ");";
}
requestAnimationFrame(iniciarBucleAnimacion);
}