jQuery / Hacer aparecer elementos en orden

.delay(index * gap).fadeIn(duration) escalona los inicios. Si la duración supera el intervalo, los efectos se solapan. Para esperar al final completo, inicie el siguiente elemento desde el callback de finalización anterior.

Intervalo de inicio y orden de finalización

.delay() espera en la cola de cada elemento, no una cola compartida de la colección. Igual demora inicia aproximadamente a la vez; index crea el escalonado. No bloquea todo JavaScript.

Intervalo 200ms y .fadeIn() 400ms permiten que Beta empiece antes de terminar Alpha. En serie espera al final y otros 200ms. Son objetivos de planificación, no tiempos exactos garantizados.

.each() sigue la colección, aquí Alpha, Beta y Gamma directos de #items. Ordenaciones y CSS pueden diferir del orden visual; defina el apropiado para leer.

Ejemplo completo de comparación

Guarde UTF-8 appearance-demo.html y abra. Internet carga la versión completa oficial 4.0.0. Efectos temporizados requieren effects, no Slim. No necesita servidor ni paquetes. Orden, reinicio y repetición se comprobaron en Edge para Windows con 3.7.1 y 4.0.0.

HTML empieza visible y el script listo lo oculta. Un fallo de carga no deja contenido oculto permanentemente por CSS. La salida es posterior a inicializar.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Staggered versus strictly sequential appearance</title>
  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
  <style>
    body { font: 16px/1.6 sans-serif; max-width: 760px; margin: 20px; }
    button, select { font: inherit; margin: 4px; }
    .item { border: 2px solid teal; padding: 12px; margin: 12px 0; background: #e7f5f1; }
    pre { white-space: pre-wrap; overflow-wrap: anywhere; }
  </style>
</head>
<body>
  <label>Mode <select id="mode"><option value="stagger">Staggered starts</option><option value="serial">Wait for completion</option></select></label>
  <button type="button" id="start">Start</button>
  <button type="button" id="reset">Reset</button>
  <div id="items"><div class="item" id="alpha">Alpha</div><div class="item" id="beta">Beta</div><div class="item" id="gamma">Gamma</div></div>
  <pre id="result" aria-live="polite"></pre>
  <pre id="events"></pre>
  <script>
    jQuery(function ($) {
      const $items = $("#items > .item"), gap = 200, duration = 400;
      let generation = 0, busy = false, state = "ready", completed = [], events = [];
      function report() {
        $("#result").text(`mode=${$("#mode").val()}\nstate=${state}\nvisible=${$items.filter(":visible").length}/${$items.length}\ncompleted=${completed.join(",") || "(none)"}`);
        $("#events").text(events.join("\n") || "(none)");
      }
      function reset() {
        generation++; // Invalidate callbacks before settling old effects.
        $items.stop(true, true).hide();
        busy = false; state = "ready"; completed = []; events = [];
        $("#start").prop("disabled", false); report();
      }
      function start() {
        if (busy) return;
        reset(); busy = true; state = "running"; $("#start").prop("disabled", true);
        const run = generation, mode = $("#mode").val();
        const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
        if (reduce) {
          $items.show(); completed = $items.map(function () { return this.id; }).get();
          events = ["Reduced motion: shown immediately"];
          busy = false; state = "done"; $("#start").prop("disabled", false); report(); return;
        }
        function reveal(index, wait) {
          const $item = $items.eq(index), id = $item[0].id;
          $item.delay(wait).queue(function (next) {
            if (run !== generation) return;
            events.push("start " + id); next(); report();
          }).fadeIn(duration, function () {
            if (run !== generation) return;
            completed.push(id); events.push("done " + id);
            if (completed.length === $items.length) {
              busy = false; state = "done"; $("#start").prop("disabled", false);
            } else if (mode === "serial") reveal(index + 1, gap);
            report();
          });
        }
        if (!$items.length) { busy = false; state = "done"; $("#start").prop("disabled", false); report(); return; }
        if (mode === "stagger") $items.each(function (index) { reveal(index, index * gap); });
        else reveal(0, 0);
        report();
      }
      $("#start").on("click", start);
      $("#reset").on("click", reset);
      $("#mode").on("change", reset);
      reset();
    });
  </script>
</body>
</html>

Al inicio, cero visibles y ninguno terminado.

mode=stagger
state=ready
visible=0/3
completed=(none)
  1. Start en Staggered starts: start beta puede preceder a done alpha.
  2. Final: state=done, visible=3/3 y completed=alpha,beta,gamma. Start vuelve a habilitarse.
  3. Wait for completion reinicia. Después start alpha → done alpha → start beta → done beta → start gamma → done gamma.
  4. Reset durante ejecución vuelve al estado oculto. Esperar no debe revivir efectos anteriores. Inicie otra vez.
  5. Con movimiento reducido en sistema o herramientas, aparece todo inmediatamente y Reduced motion: shown immediately.

Clics múltiples y reinicio

Start se deshabilita y la función comprueba busy. Las llamadas programadas tampoco apilan secuencias. Se cuentan finales por elemento; un callback no significa final de toda la colección.

.stop(true, true) vacía espera y lleva el efecto actual al final. Reset cambia primero generation para invalidar callbacks antiguos, luego termina y oculta. jumpToEnd puede llamar finalización: no lo haga antes de invalidar.

Evita reutilizar estados y colas residuales. clearQueue solo no detiene el efecto activo. setTimeout separados necesitarían cancelación aparte; aquí delay usa fx.

.queue() registra y llama next() para continuar a fadeIn. Sin next(), la cola se atasca. En serie, solo la finalización inicia el siguiente índice.

Preferencias y disposición real

prefers-reduced-motion reduce omite espera y fundido y establece el final inmediatamente. Solo afecta al ejemplo, no a efectos globales. La decoración no debe retrasar información importante.

Mostrar desde display:none crea espacio y mueve lo posterior. Reserve espacio o elija otra técnica si necesita estabilidad. Controles ocultos también requieren diseño de teclado y foco.

Con añadidos dinámicos, redefina colección y cuenta de finales. $items guarda los tres iniciales, sin incorporar nuevos automáticamente. Decida repetir todo o animar nuevos y adapte colas y reinicio.