
🔧 JQuery: desplazamiento suave a un ancla al navegar desde otra página
Añadió un ancla a la página, puso #section en la URL y espera un desplazamiento suave y agradable. El usuario hace clic desde otra página, el navegador aplica diligentemente el hash... y salta abruptamente al destino. Sin desplazamiento. Solo un salto instantáneo.
El problema es que los navegadores manejan el hash de forma instantánea por defecto, antes de que el DOM esté completamente listo y los scripts tengan oportunidad de interceptar el evento. Cuando un usuario llega mediante un enlace externo, su manejador de click nunca se dispara: no hubo evento de clic, solo una navegación directa por URL.
Hemos recopilado dos soluciones jQuery probadas en combate: un script básico para casos simples y una versión avanzada con manejo de clics, soporte para carga de página y prevención de conflictos. Ambas están probadas en proyectos reales y funcionan con las versiones actuales de jQuery.
💡 Resumen rápido:
- Guarde el hash de la URL en una variable temporal
- Limpie
location.hashpara que el navegador no salte abruptamente - Desplace hasta el ancla mediante
animate()con el desplazamiento deseado - Restaure el hash para tener una URL correcta en la barra de direcciones
Por qué es importante el desplazamiento suave a anclas
Cuando un visitante sigue un enlace como site.com/page/#pricing, espera ver el bloque de precios, no la parte superior de la página. Un salto abrupto desorienta: el usuario no entiende dónde aterrizó ni qué había antes. El desplazamiento suave proporciona contexto: los ojos captan las secciones intermedias y el cerebro traza la ruta desde el origen hasta el destino.
Con la propiedad CSS nativa scroll-behavior: smooth, la cosa es simple: agréguela a su hoja de estilos y el navegador se desplazará al ancla automáticamente. Pero este enfoque falla en el momento en que necesita un desplazamiento personalizado para una cabecera fija. Un desplazamiento de 110 píxeles evita que el bloque se deslice bajo la header y lo posiciona exactamente donde el usuario espera. La solución jQuery le da ese control.
También está la compatibilidad entre navegadores. scroll-behavior: smooth no funciona en Internet Explorer (sí, esos proyectos aún existen), mientras que el método animate() de jQuery se comporta de forma idéntica en todas partes.
Script básico: código mínimo, máximo beneficio
La primera opción es compacta, solo 10 líneas. Resuelve exactamente un problema: desplazarse suavemente a un ancla cuando el usuario llega desde otra página o mediante un enlace directo con hash.
1 jQuery(document).ready(function ($) { 2 var myHash = location.hash; // save the hash 3 location.hash = ''; // clear it — browser stops jerking 4 if (myHash[1] != undefined) { // hash not empty? 5 $('html, body').animate( 6 { scrollTop: $(myHash).offset().top - 110 }, 7 700 // duration in milliseconds 8 ); 9 location.hash = myHash; // restore the hash 10 } 11 });
Desglose paso a paso, porque tres líneas hacen magia, pero entender la mecánica importa:
var myHash = location.hash: lee el hash de la barra de direcciones (por ejemplo,#pricing). En este punto el navegador aún no se ha desplazado.location.hash = '': el truco clave. Limpiar el hash hace que el navegador pierda su objetivo para el salto instantáneo. Sin esta línea, el script «pelearía» contra el comportamiento integrado del navegador y perdería.$(myHash).offset().top - 110: calcula la posición del ancla desde la parte superior del documento y resta 110 píxeles. Este es su desplazamiento para una cabecera fija. Si su cabecera tieneposition: fixedy mide 80px de alto, use 80 (o 90 para un poco de respiro). Si no hay cabecera, elimine la resta por completo.$('html, body').animate(...): se desplaza suavemente durante 700 milisegundos. El selector'html, body'no es un capricho: distintos navegadores desplazanhtmlobody, así que especificamos ambos por fiabilidad.location.hash = myHash: restaura el hash. Ahora la barra de direcciones muestra#pricingde nuevo y la página ya está estacionada correctamente en el bloque de destino.
Inserte el script en el functions.php de su tema, en un archivo JS personalizado o mediante un plugin como Code Snippets. El requisito clave es que debe estar dentro de un bloque jQuery(document).ready().
Versión avanzada: manejo de clics, carga de página y protección contra conflictos
El script básico cubre la mayoría de los escenarios, pero a veces location.hash = '' no funciona a tiempo: el navegador salta antes de que se limpie el hash. En esos casos, use la segunda versión. Es más pesada pero más fiable.
1 jQuery(document).ready(function () { 2 jQuery(window).bind('load', function () { 3 jQuery('a:not(.spu-clickable)[href*="#"]:not([href="#"])').click(function () { 4 if ( 5 location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') || 6 location.hostname == this.hostname 7 ) { 8 var target = jQuery(this.hash); 9 target = target.length ? target : jQuery('[name=' + this.hash.slice(1) + ']'); 10 if (target.length) { 11 jQuery('html, body').animate( 12 { scrollTop: target.offset().top - 37 }, 13 1000 14 ); 15 return false; 16 } 17 } 18 }); 19 }); 20 }); 21 22 jQuery(window).load(function () { 23 function goToByScroll(id) { 24 jQuery('html, body').animate( 25 { scrollTop: jQuery('#' + id).offset().top - 38 }, 26 1000 27 ); 28 } 29 if (window.location.hash != '') { 30 goToByScroll(window.location.hash.substr(1)); 31 } 32 });
Esto es lo que sucede, bloque por bloque:
Bloque uno: un manejador de clics para enlaces internos de ancla. jQuery(window).bind('load', ...) asegura que todos los elementos de la página (incluyendo imágenes e iframes) estén cargados antes de vincular el manejador. El filtro a:not(.spu-clickable) excluye enlaces ya manejados por un plugin de popup (SPU, WordPress PopUp), previniendo conflictos de animación. Agregue sus propias clases de exclusión siguiendo el mismo patrón.
Bloque dos: manejo de la navegación desde una página externa. jQuery(window).load() se dispara más tarde que document.ready y garantiza que todos los elementos, incluida el ancla, estén en el DOM. La función goToByScroll(id) hace exactamente lo que hace el script básico, pero se llama solo después de que la ventana se carga completamente. substr(1) elimina el carácter # del hash.
Nota importante: jQuery(window).load() está obsoleto desde jQuery 3.0. Si su proyecto usa una versión actual de jQuery, sustitúyalo por:
1 jQuery(window).on('load', function () { 2 // code here 3 });
La sintaxis difiere, pero el comportamiento es idéntico.
Ajustes finos: desplazamientos, selectores y trampas
El script funciona, pero cada maquetación es única. Aquí hay tres ajustes comunes que salvaron proyectos reales.
Problema uno: offset().top devuelve coordenadas incorrectas. Esto sucede cuando los elementos padre tienen las propiedades CSS transform, filter o will-change, que crean un nuevo contexto de posicionamiento. offset() entonces calcula relativo a ese contexto en lugar del documento. Solución: use offset({top: -0}):
1 jQuery('html, body').animate( 2 { scrollTop: jQuery('#' + id).offset({ top: -0 }).top }, 3 1000 4 );
El parámetro {top: -0} obliga a jQuery a recalcular la posición desde los límites del documento, ignorando contextos intermedios. Parece magia, pero funciona.
Problema dos: el selector 'html, body' desplaza el elemento equivocado. En algunos temas, el contenedor de desplazamiento no es html o body, sino un bloque específico, por ejemplo, body.home para la página de inicio o .main-content para páginas interiores. Identifique su contenedor mediante DevTools (pestaña Elements → busque overflow: scroll o overflow: auto) y sustitúyalo en el selector:
1 jQuery('body.home').animate( 2 { scrollTop: target.offset().top - 37 }, 3 1000 4 );
Problema tres: el hash contiene caracteres cirílicos o especiales. location.hash devuelve una secuencia codificada en URL en lugar de una cadena legible, y el selector jQuery $(myHash) no encontrará el elemento. Solución: decodifique el hash con decodeURIComponent() antes de usarlo en el selector.
Video: ejemplo en vivo de desplazamiento desde un enlace externo
Una breve demostración de John Smith: desplazamiento suave a anclas mediante animate() de jQuery en una página real con cabecera fija y navegación externa.
⁉️🤔 Preguntas frecuentes
El script funciona en la misma página pero no al navegar desde otra URL. ¿Por qué?
Porque el manejador de
clicknunca se dispara: no hubo clic. El usuario siguió un enlace directo y el navegador procesó el hash antes de que su JS se ejecutara. La solución es la secuencialocation.hash = ''+animate()+location.hash = myHash. Limpiar el hash cancela el salto integrado, la animación se desplaza suavemente y restaurar el hash preserva la URL correcta en la barra de direcciones.
¿Qué desplazamiento debo usar para una cabecera fija?
La altura exacta de la cabecera más unos pocos píxeles de respiro. Abra DevTools (F12), seleccione el elemento
headerde su sitio y compruebe suheighten la pestaña Computed. Por ejemplo, si la cabecera mide 80px, use 90 en su código. Si la versión móvil tiene una altura de cabecera diferente, agregue una media query con un cálculo de desplazamiento dinámico.
¿Sigue siendo relevante jQuery en 2026?
Sí, especialmente dentro del ecosistema WordPress. jQuery permanece en el núcleo de WP, muchos plugins y temas dependen de él, y migrar todo el ecosistema a JS nativo llevará años. Para proyectos nuevos en JavaScript plano, el desplazamiento suave se hace mediante
element.scrollIntoView({ behavior: 'smooth' })oscroll-behavior: smoothen CSS, con significativamente menos líneas de código. Pero si está modificando un sitio WP existente, la solución jQuery sigue siendo fiable y apropiada.
¿Puedo evitar jQuery por completo?
Puede y debería, si el proyecto es nuevo. El equivalente nativo del script básico:
1 document.addEventListener('DOMContentLoaded', () => { 2 const hash = window.location.hash; 3 if (hash) { 4 window.location.hash = ''; 5 const target = document.querySelector(hash); 6 if (target) { 7 window.scrollTo({ 8 top: target.getBoundingClientRect().top + window.pageYOffset - 110, 9 behavior: 'smooth' 10 }); 11 } 12 window.location.hash = hash; 13 } 14 });
Mismo principio: guarde el hash, límpielo, desplace, restáurelo. La diferencia es que
behavior: 'smooth'usa el motor CSS nativo del navegador en lugar de un temporizador jQuery. No puede configurar la velocidad, pero el código pesa 30 KB menos (el peso de jQuery).
¿Por qué $('html, body') en lugar de solo $('html')?
Firefox desplaza
html, Chrome usabodyy Safari depende de la versión. Especificar ambos selectores enanimate()garantiza que funcione en todos los navegadores: jQuery envía la animación al elemento que realmente la aplica.
¿Vale la pena usar jQuery solo para desplazamiento suave en 2026?
Si tiene un sitio WordPress o un proyecto heredado donde jQuery ya está cargado, tome el script de este artículo y no complique las cosas. Diez líneas de código que funcionan en todas partes, en cualquier navegador, sin necesidad de polyfills. Para nuevos desarrollos en JavaScript plano, use scroll-behavior: smooth nativo o scrollIntoView(). Ambos enfoques producen desplazamiento suave, pero el método jQuery le da control sobre la velocidad, el desplazamiento y el selector del contenedor de desplazamiento. Las implementaciones nativas requieren comprobaciones separadas para lograr lo mismo.
La regla principal que hemos aprendido de docenas de proyectos: siempre limpie el hash antes de desplazar. Sin este truco, ningún manejador puede vencer el comportamiento integrado del navegador y los usuarios seguirán experimentando saltos abruptos.



