Desplácese hasta un elemento con jQuery

2510

Tengo este inputelemento:

<input type="text" class="textfield" value="" id="subject" name="subject">

Luego tengo algunos otros elementos, como otras entradas de texto, áreas de texto, etc.

Cuando el usuario hace clic en eso inputcon #subject, la página debe desplazarse hasta el último elemento de la página con una bonita animación. Debe ser un desplazamiento hacia abajo y no hacia arriba.

El último elemento de la página es un submitbotón con #submit:

<input type="submit" class="submit" id="submit" name="submit" value="Ok, Done.">

La animación no debe ser demasiado rápida y debe ser fluida.

Estoy ejecutando la última versión de jQuery. Prefiero no instalar ningún complemento, sino usar las funciones predeterminadas de jQuery para lograrlo.

2
4276

Suponiendo que tiene un botón con la identificación button, pruebe este ejemplo:

$("#button").click(function() {
    $([document.documentElement, document.body]).animate({
        scrollTop: $("#elementtoScrollToID").offset().top
    }, 2000);
});

Obtuve el código del artículo Desplácese suavemente a un elemento sin un complemento jQuery . Y lo he probado en el siguiente ejemplo.

<html>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
    <script>
        $(document).ready(function (){
            $("#click").click(function (){
                $('html, body').animate({
                    scrollTop: $("#div1").offset().top
                }, 2000);
            });
        });
    </script>
    <div id="div1" style="height: 1000px; width 100px">
        Test
    </div>
    <br/>
    <div id="div2" style="height: 1000px; width 100px">
        Test 2
    </div>
    <button id="click">Click me</button>
</html>
3
552

Método jQuery .scrollTo ()

jQuery .scrollTo (): Ver - Demostración, API, Fuente

Escribí este complemento liviano para facilitar el desplazamiento de la página / elemento. Es flexible donde puede pasar un elemento de destino o un valor especificado. Quizás esto podría ser parte del próximo lanzamiento oficial de jQuery, ¿qué opinas?


Ejemplos de uso:

$('body').scrollTo('#target'); // Scroll screen to target element

$('body').scrollTo(500); // Scroll screen 500 pixels down

$('#scrollable').scrollTo(100); // Scroll individual element 100 pixels down

Opciones:

scrollTarget : elemento, cadena o número que indica la posición de desplazamiento deseada.

offsetTop : un número que define un espacio adicional por encima del objetivo de desplazamiento.

duración : una cadena o número que determina cuánto tiempo se ejecutará la animación.

easing : una cadena que indica qué función de aceleración se debe utilizar para la transición.

complete : una función para llamar una vez que se completa la animación.

2
419

Si no está muy interesado en el efecto de desplazamiento suave y solo está interesado en desplazarse a un elemento en particular, no necesita ninguna función jQuery para esto. Javascript tiene su caso cubierto:

https://developer.mozilla.org/en-US/docs/Web/API/element.scrollIntoView

Entonces todo lo que necesitas hacer es: $("selector").get(0).scrollIntoView();

.get(0) se utiliza porque queremos recuperar el elemento DOM de JavaScript y no el elemento DOM de JQuery.

4
  • dieciséis
    ¿Podrías usar también $(selector)[0]? RobW 17 de marzo de 2014 a las 19:02
  • 19
    RobW, sí, puedes usar [0], pero get (0) te protege contra índices indefinidos o negativos. Ver la fuente: james.padolsey.com/jquery/#v=1.10.2&fn=jQuery.fn.getcorbacho 2/04/2014 a las 14:16
  • 25
    Si no desea usar jQuery en absoluto, solo use document.getElementById('#elementID').scrollIntoView(). No sirve de nada cargar una biblioteca de ~ 100k solo para seleccionar un elemento y luego convertirlo a JavaScript normal. Gavin 23/06/2014 a las 18:59
  • 73
    @Gavin, estoy seguro de que querías decir que era:document.getElementById('elementID').scrollIntoView()Brian 18 de septiembre de 2014 a las 21:40
90

Esto se puede lograr sin jQuery:

document.getElementById("element-id").scrollIntoView();
1
  • Deje de editar su pregunta para introducir charlas irrelevantes. Millones de respuestas siguen dando representación a sus autores "años después". No necesitamos que se mencione esto, no agrega nada de valor a la pregunta o al sitio. meagar 27 de agosto a las 3:23
55

Usando este sencillo script

if($(window.location.hash).length > 0){
        $('html, body').animate({ scrollTop: $(window.location.hash).offset().top}, 1000);
}

Haría en orden que si se encuentra una etiqueta hash en la URL, el scrollTo se anima a la ID. Si no se encuentra la etiqueta hash, ignore el script.

0
43

jQuery(document).ready(function($) {
  $('a[href^="#"]').bind('click.smoothscroll',function (e) {
    e.preventDefault();
    var target = this.hash,
        $target = $(target);

    $('html, body').stop().animate( {
      'scrollTop': $target.offset().top-40
    }, 900, 'swing', function () {
      window.location.hash = target;
    } );
  } );
} );
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


<ul role="tablist">
  <li class="active" id="p1"><a href="#pane1" role="tab">Section 1</a></li>
  <li id="p2"><a href="#pane2" role="tab">Section 2</a></li>
  <li id="p3"><a href="#pane3" role="tab">Section 3</a></li>
</ul>

<div id="pane1"></div>
<div id="pane2"></div>
<div id="pane3"></div>
1
  • 1
    Para que sea más universal y para eliminar la colocación innecesaria de hashtag en la ventana de enlace del navegador acabo pellizcado el código de la siguiente manera:jQuery(document).ready(function($) { $(document).on( "click", 'a[href^="#"]', function( e ) { e.preventDefault(); var target = this.hash, $target = $(target); $('html, body').stop().animate({ scrollTop: $target.offset().top - 100}, 1000); }); });bubencode 12/08/18 a las 14:27
37

La solución de Steve y Peter funciona muy bien.

Pero en algunos casos, es posible que deba convertir el valor a un número entero. Curiosamente, el valor devuelto de a $("...").offset().topveces está en formato float.
Usar:parseInt($("....").offset().top)

Por ejemplo:

$("#button").click(function() {
    $('html, body').animate({
        scrollTop: parseInt($("#elementtoScrollToID").offset().top)
    }, 2000);
});
35

Esta es la forma en que lo hago.

document.querySelector('scrollHere').scrollIntoView({ behavior: 'smooth' })

Funciona en cualquier navegador.

Se puede envolver fácilmente en una función.

function scrollTo(selector) {
    document.querySelector(selector).scrollIntoView({ behavior: 'smooth' })
}

Aquí hay un ejemplo de trabajo.

$(".btn").click(function() {
  document.getElementById("scrollHere").scrollIntoView( {behavior: "smooth" })
})
.btn {margin-bottom: 500px;}
.middle {display: block; margin-bottom: 500px; color: red;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<button class="btn">Scroll down</button>

<h1 class="middle">You see?</h1>

<div id="scrollHere">Arrived at your destination</div>

Docs

2
  • 6
    Bastante corto y dulce. Una cosa a tener en cuenta: creo que esto solo lo desplaza hacia la vista (podría estar en la parte inferior de la ventana gráfica) en lugar de desplazarse hacia la parte superior de la ventana gráfica, como lo hace la configuración de scrollTop. OG Sean 4 de agosto de 2019 a las 2:19
  • También utilicé esta solución, pero al menos la versión 92 de Chrome por alguna razón tiene el desplazamiento suave deshabilitado de forma predeterminada, por lo que esta solución ya no funciona (al momento de escribir esto). En realidad, bastante decepcionante. Todavía se puede habilitar manualmente seleccionando " Habilitado " (en lugar de "Predeterminado") para la chrome://flags/#smooth-scrollingconfiguración. informatik01 31 de julio a las 4:45
23

Una versión compacta de la solución "animada".

$.fn.scrollTo = function (speed) {
    if (typeof(speed) === 'undefined')
        speed = 1000;

    $('html, body').animate({
        scrollTop: parseInt($(this).offset().top)
    }, speed);
};

Uso básico: $('#your_element').scrollTo();

0
19

Con esta solución , no necesita ningún complemento y no se requiere configuración además de colocar el script antes de su </body>etiqueta de cierre .

$("a[href^='#']").on("click", function(e) {
  $("html, body").animate({
    scrollTop: $($(this).attr("href")).offset().top
  }, 1000);
  return false;
});

if ($(window.location.hash).length > 1) {
  $("html, body").animate({
    scrollTop: $(window.location.hash).offset().top
  }, 1000);
}

Al cargar, si hay un hash en la dirección, lo desplazamos.

Y, cada vez que hace clic en un aenlace con un hrefhash #top, por ejemplo , nos desplazamos hasta él.

## Editar 2020

Si desea una solución de JavaScript pura: tal vez podría usar algo como:

var _scrollToElement = function (selector) {
  try {
    document.querySelector(selector).scrollIntoView({ behavior: 'smooth' });
  } catch (e) {
    console.warn(e);
  }
}

var _scrollToHashesInHrefs = function () {
  document.querySelectorAll("a[href^='#']").forEach(function (el) {
    el.addEventListener('click', function (e) {
      _scrollToElement(el.getAttribute('href'));
      return false;
    })
  })
  if (window.location.hash) {
    _scrollToElement(window.location.hash);
  }
}

_scrollToHashesInHrefs();
0
18

Si solo está manejando el desplazamiento a un elemento de entrada, puede usar focus(). Por ejemplo, si desea desplazarse hasta la primera entrada visible:

$(':input:visible').first().focus();

O la primera entrada visible en un contenedor con clase .error:

$('.error :input:visible').first().focus();

¡Gracias a Tricia Ball por señalar esto!

10

Si desea desplazarse dentro de un contenedor de desbordamiento (en lugar de la $('html, body')respuesta anterior), trabajando también con posicionamiento absoluto, esta es la forma de hacerlo:

var elem = $('#myElement'),
    container = $('#myScrollableContainer'),
    pos = elem.position().top + container.scrollTop() - container.position().top;

container.animate({
  scrollTop: pos
}
0
10

Manera fácil de lograr el desplazamiento de la página para apuntar div id

var targetOffset = $('#divID').offset().top;
$('html, body').animate({scrollTop: targetOffset}, 1000);
9

Animaciones:

// slide to top of the page
$('.up').click(function () {
    $("html, body").animate({
        scrollTop: 0
    }, 600);
    return false;
});

// slide page to anchor
$('.menutop b').click(function(){
    //event.preventDefault();
    $('html, body').animate({
        scrollTop: $( $(this).attr('href') ).offset().top
    }, 600);
    return false;
});

// Scroll to class, div
$("#button").click(function() {
    $('html, body').animate({
        scrollTop: $("#target-element").offset().top
    }, 1000);
});

// div background animate
$(window).scroll(function () {

    var x = $(this).scrollTop();

    // freezze div background
    $('.banner0').css('background-position', '0px ' + x +'px');

    // from left to right
    $('.banner0').css('background-position', x+'px ' +'0px');

    // from right to left
    $('.banner0').css('background-position', -x+'px ' +'0px');

    // from bottom to top
    $('#skills').css('background-position', '0px ' + -x + 'px');

    // move background from top to bottom
    $('.skills1').css('background-position', '0% ' + parseInt(-x / 1) + 'px' + ', 0% ' + parseInt(-x / 1) + 'px, center top');

    // Show hide mtop menu  
    if ( x > 100 ) {
    $( ".menu" ).addClass( 'menushow' );
    $( ".menu" ).fadeIn("slow");
    $( ".menu" ).animate({opacity: 0.75}, 500);
    } else {
    $( ".menu" ).removeClass( 'menushow' );
    $( ".menu" ).animate({opacity: 1}, 500);
    }

});

// progres bar animation simple
$('.bar1').each(function(i) {
  var width = $(this).data('width');  
  $(this).animate({'width' : width + '%' }, 900, function(){
    // Animation complete
  });  
});
8

En la mayoría de los casos, sería mejor utilizar un complemento. Seriamente. Voy a promocionar el mío aquí . Por supuesto que también hay otros. Pero compruebe si realmente evitan las trampas para las que desearía un complemento en primer lugar, no todos lo hacen.

He escrito sobre las razones para usar un complemento en otros lugares . En pocas palabras, el trazador de líneas que sustenta la mayoría de las respuestas aquí

$('html, body').animate( { scrollTop: $target.offset().top }, duration );

es una mala experiencia de usuario.

  • La animación no responde a las acciones del usuario. Continúa incluso si el usuario hace clic, toca o intenta desplazarse.

  • Si el punto de inicio de la animación está cerca del elemento de destino, la animación es tremendamente lenta.

  • Si el elemento de destino se coloca cerca de la parte inferior de la página, no se puede desplazar hasta la parte superior de la ventana. La animación de desplazamiento se detiene abruptamente entonces, en medio del movimiento.

Para manejar estos problemas (y muchos otros ), puede usar un complemento mío, jQuery.scrollable . La llamada entonces se convierte en

$( window ).scrollTo( targetPosition );

y eso es. Por supuesto, hay más opciones .

Con respecto al puesto de destino, $target.offset().topcumple su función en la mayoría de los casos. Pero tenga en cuenta que el valor devuelto no tiene en cuenta un borde en el htmlelemento ( consulte esta demostración ). Si necesita que la posición de destino sea precisa bajo cualquier circunstancia, es mejor usar

targetPosition = $( window ).scrollTop() + $target[0].getBoundingClientRect().top;

Eso funciona incluso si se establece un borde en el htmlelemento.

0
7

Después de encontrar la manera de hacer que mi código funcione, creo que debería dejar las cosas un poco claras: para usar:

$('html, body').animate({
   scrollTop: $("#div1").offset().top
}, 2000);

debe estar en la parte superior de la página, ya $("#div1").offset().topque devolverá diferentes números para las diferentes posiciones a las que se desplaza. Si ya se desplazó fuera de la parte superior, debe especificar el pageYvalor exacto (consulte la pageYdefinición aquí: https://javascript.info/coordinates ).

Entonces, ahora, el problema es calcular el pageYvalor de un elemento. A continuación se muestra un ejemplo en caso de que el contenedor de desplazamiento sea el cuerpo:

function getPageY(id) {
    let elem = document.getElementById(id);
    let box = elem.getBoundingClientRect();
    var body = document.getElementsByTagName("BODY")[0];
    return box.top + body.scrollTop; // for window scroll: box.top + window.scrollY;
}

La función anterior devuelve el mismo número incluso si se desplazó en algún lugar. Ahora, para volver a ese elemento:

$("html, body").animate({ scrollTop: getPageY('div1') }, "slow");
6

Este es mi enfoque abstrayendo los ID y href, usando un selector de clase genérico

$(function() {
  // Generic selector to be used anywhere
  $(".js-scroll-to").click(function(e) {

    // Get the href dynamically
    var destination = $(this).attr('href');

    // Prevent href=“#” link from changing the URL hash (optional)
    e.preventDefault();

    // Animate scroll to destination
    $('html, body').animate({
      scrollTop: $(destination).offset().top
    }, 500);
  });
});
<!-- example of a fixed nav menu -->
<ul class="nav">
  <li>
    <a href="#section-1" class="nav-item js-scroll-to">Item 1</a>
  </li>
  <li>
    <a href="#section-2" class="nav-item js-scroll-to">Item 2</a>
  </li>
  <li>
    <a href="#section-3" class="nav-item js-scroll-to">Item 3</a>
  </li>
</ul>
6

Complemento jQuery personalizado muy simple y fácil de usar. Simplemente agregue el atributo scroll=a su elemento en el que se puede hacer clic y establezca su valor en el selector al que desea desplazarse.

De este modo: <a scroll="#product">Click me</a>. Se puede utilizar en cualquier elemento.

(function($){
    $.fn.animateScroll = function(){
        console.log($('[scroll]'));
        $('[scroll]').click(function(){
            selector = $($(this).attr('scroll'));
            console.log(selector);
            console.log(selector.offset().top);
            $('html body').animate(
                {scrollTop: (selector.offset().top)}, //- $(window).scrollTop()
                1000
            );
        });
    }
})(jQuery);

// RUN
jQuery(document).ready(function($) {
    $().animateScroll();
});

// IN HTML EXAMPLE
// RUN ONCLICK ON OBJECT WITH ATTRIBUTE SCROLL=".SELECTOR"
// <a scroll="#product">Click To Scroll</a>
4
$('html, body').animate({scrollTop: 
  Math.min( 
    $(to).offset().top-margintop, //margintop is the margin above the target
    $('body')[0].scrollHeight-$('body').height()) //if the target is at the bottom
}, 2000);
4
var scrollTo = function($parent, $element) {
    var topDiff = $element.position().top - $parent.position().top;

    $parent.animate({
        scrollTop : topDiff
    }, 100);
};
4

Esta es la respuesta de Atharva de: https://developer.mozilla.org/en-US/docs/Web/API/element.scrollIntoView . Solo quería agregar si su documento está en un iframe, puede elegir un elemento en el marco principal para desplazarse a la vista:

 $('#element-in-parent-frame', window.parent.document).get(0).scrollIntoView();
4

$('html, body').animate(...) no me funciona en los navegadores iPhone, Android, Chrome o Safari.

Tuve que apuntar al elemento de contenido raíz de la página.

$('#cotnent').animate(...)

Esto es lo que he terminado con:

if (navigator.userAgent.match(/(iPod|iPhone|iPad|Android)/)) {
    $('#content').animate({
    scrollTop: $("#elementtoScrollToID").offset().top
   }, 'slow');
}
else{
    $('html, body').animate({
    scrollTop: $("#elementtoScrollToID").offset().top
    }, 'slow');
}

Todo el contenido corporal conectado con un div #content

<html>
    ....
    <body>
        <div id="content">
        ...
        </div>
    </body>
</html>
2
3

Escribí una función de propósito general que se desplaza a un objeto jQuery, un selector CSS o un valor numérico.

Uso de ejemplo:

// scroll to "#target-element":
$.scrollTo("#target-element");

// scroll to 80 pixels above first element with class ".invalid":
$.scrollTo(".invalid", -80);

// scroll a container with id "#my-container" to 300 pixels from its top:
$.scrollTo(300, 0, "slow", "#my-container");

El código de la función:

/**
* Scrolls the container to the target position minus the offset
*
* @param target    - the destination to scroll to, can be a jQuery object
*                    jQuery selector, or numeric position
* @param offset    - the offset in pixels from the target position, e.g.
*                    pass -80 to scroll to 80 pixels above the target
* @param speed     - the scroll speed in milliseconds, or one of the
*                    strings "fast" or "slow". default: 500
* @param container - a jQuery object or selector for the container to
*                    be scrolled. default: "html, body"
*/
jQuery.scrollTo = function (target, offset, speed, container) {

    if (isNaN(target)) {

        if (!(target instanceof jQuery))
            target = $(target);

        target = parseInt(target.offset().top);
    }

    container = container || "html, body";
    if (!(container instanceof jQuery))
        container = $(container);

    speed = speed || 500;
    offset = offset || 0;

    container.animate({
        scrollTop: target + offset
    }, speed);
};
3

When the user clicks on that input with #subject, the page should scroll to the last element of the page with a nice animation. It should be a scroll to bottom and not to top.

The last item of the page is a submit button with #submit

$('#subject').click(function()
{
    $('#submit').focus();
    $('#subject').focus();
});

Esto primero se desplazará hacia abajo para #submitluego restaurar el cursor a la entrada en la que se hizo clic, que imita un desplazamiento hacia abajo y funciona en la mayoría de los navegadores. Tampoco requiere jQuery, ya que se puede escribir en JavaScript puro.

¿Puede esta manera de usar la focusfunción imitar la animación de una mejor manera, a través del encadenamiento de focusllamadas? No he probado esta teoría, pero se vería así:

<style>
  #F > *
  {
    width: 100%;
  }
</style>

<form id="F" >
  <div id="child_1"> .. </div>
  <div id="child_2"> .. </div>
  ..
  <div id="child_K"> .. </div>
</form>

<script>
  $('#child_N').click(function()
  {
    $('#child_N').focus();
    $('#child_N+1').focus();
    ..
    $('#child_K').focus();

    $('#child_N').focus();
  });
</script>
3

Configuré un elemento de desplazamiento del módulo npm install scroll-element. Funciona así:

import { scrollToElement, scrollWindowToElement } from 'scroll-element'

/* scroll the window to your target element, duration and offset optional */
let targetElement = document.getElementById('my-item')
scrollWindowToElement(targetElement)

/* scroll the overflow container element to your target element, duration and offset optional */
let containerElement = document.getElementById('my-container')
let targetElement = document.getElementById('my-item')
scrollToElement(containerElement, targetElement)

Escrito con la ayuda de las siguientes publicaciones de SO:

Aquí está el código:

export const scrollToElement = function(containerElement, targetElement, duration, offset) {
  if (duration == null) { duration = 1000 }
  if (offset == null) { offset = 0 }

  let targetOffsetTop = getElementOffset(targetElement).top
  let containerOffsetTop = getElementOffset(containerElement).top
  let scrollTarget = targetOffsetTop + ( containerElement.scrollTop - containerOffsetTop)
  scrollTarget += offset
  scroll(containerElement, scrollTarget, duration)
}

export const scrollWindowToElement = function(targetElement, duration, offset) {
  if (duration == null) { duration = 1000 }
  if (offset == null) { offset = 0 }

  let scrollTarget = getElementOffset(targetElement).top
  scrollTarget += offset
  scrollWindow(scrollTarget, duration)
}

function scroll(containerElement, scrollTarget, duration) {
  let scrollStep = scrollTarget / (duration / 15)
  let interval = setInterval(() => {
    if ( containerElement.scrollTop < scrollTarget ) {
      containerElement.scrollTop += scrollStep
    } else {
      clearInterval(interval)
    }
  },15)
}

function scrollWindow(scrollTarget, duration) {
  let scrollStep = scrollTarget / (duration / 15)
  let interval = setInterval(() => {
    if ( window.scrollY < scrollTarget ) {
      window.scrollBy( 0, scrollStep )
    } else {
      clearInterval(interval)
    }
  },15)
}

function getElementOffset(element) {
  let de = document.documentElement
  let box = element.getBoundingClientRect()
  let top = box.top + window.pageYOffset - de.clientTop
  let left = box.left + window.pageXOffset - de.clientLeft
  return { top: top, left: left }
}
3

Respuesta actualizada a 2019:

$('body').animate({
    scrollTop: $('#subject').offset().top - $('body').offset().top + $('body').scrollTop()
}, 'fast');
1
  • Debe utilizar este selector para el cuerpo: [document.documentElement, document.body] Y No es necesario el desplazamiento del cuerpo en la ecuación. $ ('# subject'). offset (). top es suficiente. ali6p 19/11/19 a las 14:43
3

UN TRAZADOR DE LÍNEAS

subject.onclick = e=> window.scroll({ top: submit.offsetTop, behavior: 'smooth'});

subject.onclick = e=> window.scroll({top: submit.offsetTop, behavior: 'smooth'});
.box,.foot{display: flex;background:#fdf;padding:500px 0} .foot{padding:250px}
<input type="text" class="textfield" value="click here" id="subject" name="subject">

<div class="box">
  Some content
  <textarea></textarea>
</div>

<input type="submit" class="submit" id="submit" name="submit" value="Ok, Done.">

<div class="foot">Some footer</div>
0
2

Para mostrar el elemento completo (si es posible con el tamaño de ventana actual):

var element       = $("#some_element");
var elementHeight = element.height();
var windowHeight  = $(window).height();

var offset = Math.min(elementHeight, windowHeight) + element.offset().top;
$('html, body').animate({ scrollTop: offset }, 500);
2

Por lo que vale, así es como logré lograr tal comportamiento para un elemento general que puede estar dentro de un DIV con desplazamiento. En nuestro caso, no desplazamos el cuerpo completo, sino solo elementos particulares con overflow: auto; dentro de un diseño más grande.

Crea una entrada falsa de la altura del elemento de destino, y luego le pone un foco, y el navegador se ocupará del resto sin importar cuán profundo esté dentro de la jerarquía desplazable. Funciona de maravilla.

var $scrollTo = $('#someId'),
inputElem = $('<input type="text"></input>');

$scrollTo.prepend(inputElem);
inputElem.css({
  position: 'absolute',
  width: '1px',
  height: $scrollTo.height()
});
inputElem.focus();
inputElem.remove();
2

Esto funcionó para mí:

var targetOffset = $('#elementToScrollTo').offset().top;
$('#DivParent').animate({scrollTop: targetOffset}, 2500);