El diseño de cascada, o disposición en casccada, es una técnica de maquetación web que organiza los elemetnos en múltiples columnas con alturas variables, creando un efecto visual irregular. A medida que el usuario se despalza verticalmente, se insertan nuevos elementos en la posición de menor altura acumulada, optimizando el espacio y ofreciendo una experiencia continua.
La implementación se basa en cálculos dinámicos con JavaScript puro. Se determina el número de columnas según el ancho del contenedor y la ventana del navegador. Luego, se almacenan las alturas de cada columna y se asigna cada nuevo elemento a la columna con la altura mínima, actualizando el registro tras cada inserción.
Estructura HTML de ejemplo:
<div id="contenedor-galeria">
<div class="tarjeta">
<div class="contenido">
<img src="imagenes/1.jpg" alt="Ejemplo">
<p>Texto descriptivo</p>
</div>
</div>
<!-- Elementos adicionales omitidos por brevedad -->
</div>
Estilos CSS correspondientes:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: #eaeaea;
font-family: sans-serif;
}
#contenedor-galeria {
position: relative;
margin: 20px;
}
#contenedor-galeria .tarjeta {
padding: 10px;
position: absolute;
}
#contenedor-galeria .contenido {
border: 1px solid #ccc;
background-color: #fff;
padding: 10px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
#contenedor-galeria .contenido img {
max-width: 100%;
display: block;
}
#contenedor-galeria .contenido p {
text-align: center;
margin-top: 8px;
font-weight: bold;
color: #333;
}
Lógica JavaScript para el posicionamiento y carga:
document.addEventListener('DOMContentLoaded', () => {
const datosSimulados = [
{ ruta: '1.jpg' },
{ ruta: '2.jpg' },
{ ruta: '3.jpg' },
{ ruta: '4.jpg' }
];
inicializarDiseñoCascada('contenedor-galeria', 'tarjeta');
window.addEventListener('scroll', () => {
if (verificarCondicionCarga()) {
insertarNuevosElementos(datosSimulados);
inicializarDiseñoCascada('contenedor-galeria', 'tarjeta');
}
});
});
function inicializarDiseñoCascada(idContenedor, claseElemento) {
const contenedor = document.getElementById(idContenedor);
const elementos = contenedor.querySelectorAll(`.${claseElemento}`);
const anchoElemento = elementos[0] ? elementos[0].offsetWidth : 200;
const anchoViewport = window.innerWidth;
const numColumnas = Math.max(1, Math.floor(anchoViewport / anchoElemento));
const alturasColumnas = Array(numColumnas).fill(0);
elementos.forEach((elemento, indice) => {
const alturaActual = elemento.offsetHeight;
if (indice < numColumnas) {
elemento.style.top = '0';
elemento.style.left = `${anchoElemento * indice}px`;
alturasColumnas[indice] = alturaActual;
} else {
const alturaMinima = Math.min(...alturasColumnas);
const indiceMin = alturasColumnas.indexOf(alturaMinima);
elemento.style.top = `${alturaMinima}px`;
elemento.style.left = `${anchoElemento * indiceMin}px`;
alturasColumnas[indiceMin] += alturaActual;
}
});
}
function verificarCondicionCarga() {
const contenedor = document.getElementById('contenedor-galeria');
const ultimoElemento = contenedor.querySelector('.tarjeta:last-child');
if (!ultimoElemento) return false;
const limiteInferior = ultimoElemento.offsetTop + ultimoElemento.offsetHeight;
const desplazamientoVertical = window.pageYOffset || document.documentElement.scrollTop;
const alturaVisible = window.innerHeight;
return limiteInferior < desplazamientoVertical + alturaVisible;
}
function insertarNuevosElementos(datos) {
const contenedor = document.getElementById('contenedor-galeria');
datos.forEach(dato => {
const nuevaTarjeta = document.createElement('div');
nuevaTarjeta.className = 'tarjeta';
const nuevoContenido = document.createElement('div');
nuevoContenido.className = 'contenido';
const imagen = document.createElement('img');
imagen.src = `imagenes/${dato.ruta}`;
nuevoContenido.appendChild(imagen);
const parrafo = document.createElement('p');
parrafo.textContent = 'Contenido dinámico';
nuevoContenido.appendChild(parrafo);
nuevaTarjeta.appendChild(nuevoContenido);
contenedor.appendChild(nuevaTarjeta);
});
}
El código anterior calcula dinámicamente la disposición y activa la carga de nuevos elementos cuando el usuario se acerca al final de la página visible.