pagina otra enlaces ejemplos desplazamiento bootstrap animado animadas animada anclas ancla html5 css3

html5 - otra - smooth scroll



Desplazarse a un ancla usando Transition/CSS3 (8)

Tengo una serie de enlaces que usan un mecanismo de anclaje:

<div class="header"> <p class="menu"><a href="#S1">Section1</a></p> <p class="menu"><a href="#S2">Section2</a></p> ... </div> <div style="width: 100%;"> <a name="S1" class="test">&nbsp;</a> <div class="curtain"> Lots of text </div> <a name="S2" class="test">&nbsp;</a> <div class="curtain"> lots of text </div> ... </div>

Estoy usando el siguiente CSS:

.test { position:relative; margin: 0; padding: 0; float: left; display: inline-block; margin-top: -100px; /* whatever offset this needs to be */ }

Está funcionando bien. Pero, por supuesto, está saltando de una sección a otra cuando hacemos clic en el enlace. Así que me gustaría tener una transición fluida, usando un desplazamiento de algún tipo al comienzo de la sección seleccionada.

Creo que leí en Stackoverflow que esto no es posible (todavía) con CSS3, pero me gustaría obtener una confirmación y también me gustaría saber cuál podría ser la solución. Me complace usar JS pero no puedo usar jQuery. Traté de usar una función de hacer clic en el enlace, recuperar la "posición vertical" del div que se debe mostrar pero no tuve éxito. Todavía estoy aprendiendo JS y no lo sé lo suficientemente bien como para encontrar una solución propia.

Cualquier ayuda / ideas sería muy apreciada.


Usando la propiedad CSS de scroll-behavior :

(que es supported con los navegadores modernos pero no con Edge ):

a { display: inline-block; padding: 5px 7%; text-decoration: none; } nav, section { display: block; margin: 0 auto; text-align: center; } nav { width: 350px; padding: 5px; } section { width: 350px; height: 130px; overflow-y: scroll; border: 1px solid black; font-size: 0; scroll-behavior: smooth; /* <----- THE SECRET ---- */ } section div{ display: flex; align-items: center; justify-content: center; height: 100%; font-size: 8vw; }

<nav>   <a href="#page-1">1</a>   <a href="#page-2">2</a>   <a href="#page-3">3</a> </nav> <section>   <div id="page-1">1</div>   <div id="page-2">2</div>   <div id="page-3">3</div> </section>


Aquí hay una solución de CSS pura que usa unidades de visualización y variables que se ajusta automáticamente al dispositivo (y funciona en el tamaño de la ventana). Agregué lo siguiente a la solución de Alex:

html,body { width: 100%; height: 100%; position: fixed;/* prevents scrolling */ --innerheight: 100vh;/* variable 100% of viewport height */ } body { overflow: hidden; /* prevents scrolling */ } .panel { width: 100%; height: var(--innerheight); /* viewport height */ a[ id= "galeria" ]:target ~ #main article.panel { -webkit-transform: translateY( calc(-1*var(--innerheight)) ); transform: translateY( calc(-1*var(--innerheight)) ); } a[ id= "contacto" ]:target ~ #main article.panel { -webkit-transform: translateY( calc(-2*var(--innerheight)) ); transform: translateY( calc(-2*var(--innerheight)) );


Implementé la respuesta sugerida por @ user18490 pero encontré dos problemas:

  • Primer bouncing cuando el usuario hace clic varias pestañas / enlaces varias veces en una sucesión corta
  • Segundo, el error undefined mencionado por @krivar

Desarrollé la siguiente clase para evitar los problemas mencionados, y funciona bien:

export class SScroll{ constructor(){ this.delay=501 //ms this.duration=500 //ms this.lastClick=0 } lastClick delay duration scrollTo=(destID)=>{ /* To prevent "bounce" */ /* https://.com/a/28610565/3405291 */ if(this.lastClick>=(Date.now()-this.delay)){return} this.lastClick=Date.now() const dest=document.getElementById(destID) const to=dest.offsetTop if(document.body.scrollTop==to){return} const diff=to-document.body.scrollTop const scrollStep=Math.PI / (this.duration/10) let count=0 let currPos const start=window.pageYOffset const scrollInterval=setInterval(()=>{ if(document.body.scrollTop!=to){ count++ currPos=start+diff*(.5-.5*Math.cos(count*scrollStep)) document.body.scrollTop=currPos }else{clearInterval(scrollInterval)} },10) } }

ACTUALIZAR

Hay un problema con Firefox como se menciona here . Por lo tanto, para que funcione en Firefox, implementé el siguiente código. Funciona bien en los navegadores basados ​​en Chromium y también en Firefox.

export class SScroll{ constructor(){ this.delay=501 //ms this.duration=500 //ms this.lastClick=0 } lastClick delay duration scrollTo=(destID)=>{ /* To prevent "bounce" */ /* https://.com/a/28610565/3405291 */ if(this.lastClick>=(Date.now()-this.delay)){return} this.lastClick=Date.now() const dest=document.getElementById(destID) const to=dest.offsetTop if((document.body.scrollTop || document.documentElement.scrollTop || 0)==to){return} const diff=to-(document.body.scrollTop || document.documentElement.scrollTop || 0) const scrollStep=Math.PI / (this.duration/10) let count=0 let currPos const start=window.pageYOffset const scrollInterval=setInterval(()=>{ if((document.body.scrollTop || document.documentElement.scrollTop || 0)!=to){ count++ currPos=start+diff*(.5-.5*Math.cos(count*scrollStep)) /* https://.com/q/28633221/3405291 */ /* To support both Chromium-based and Firefox */ document.body.scrollTop=currPos document.documentElement.scrollTop=currPos }else{clearInterval(scrollInterval)} },10) } }


Puede encontrar la respuesta a su pregunta en la siguiente página:

https://.com/a/17633941/2359161

Aquí está el JSFiddle que se le dio:

http://jsfiddle.net/YYPKM/3/

Tenga en cuenta la sección de desplazamiento al final de la CSS, específicamente:

/* *Styling */ html,body { width: 100%; height: 100%; position: relative; } body { overflow: hidden; } header { background: #fff; position: fixed; left: 0; top: 0; width:100%; height: 3.5rem; z-index: 10; } nav { width: 100%; padding-top: 0.5rem; } nav ul { list-style: none; width: inherit; margin: 0; } ul li:nth-child( 3n + 1), #main .panel:nth-child( 3n + 1) { background: rgb( 0, 180, 255 ); } ul li:nth-child( 3n + 2), #main .panel:nth-child( 3n + 2) { background: rgb( 255, 65, 180 ); } ul li:nth-child( 3n + 3), #main .panel:nth-child( 3n + 3) { background: rgb( 0, 255, 180 ); } ul li { display: inline-block; margin: 0 8px; margin: 0 0.5rem; padding: 5px 8px; padding: 0.3rem 0.5rem; border-radius: 2px; line-height: 1.5; } ul li a { color: #fff; text-decoration: none; } .panel { width: 100%; height: 500px; z-index:0; -webkit-transform: translateZ( 0 ); transform: translateZ( 0 ); -webkit-transition: -webkit-transform 0.6s ease-in-out; transition: transform 0.6s ease-in-out; -webkit-backface-visibility: hidden; backface-visibility: hidden; } .panel h1 { font-family: sans-serif; font-size: 64px; font-size: 4rem; color: #fff; position:relative; line-height: 200px; top: 33%; text-align: center; margin: 0; } /* *Scrolling */ a[ id= "servicios" ]:target ~ #main article.panel { -webkit-transform: translateY( 0px); transform: translateY( 0px ); } a[ id= "galeria" ]:target ~ #main article.panel { -webkit-transform: translateY( -500px ); transform: translateY( -500px ); } a[ id= "contacto" ]:target ~ #main article.panel { -webkit-transform: translateY( -1000px ); transform: translateY( -1000px ); }

<a id="servicios"></a> <a id="galeria"></a> <a id="contacto"></a> <header class="nav"> <nav> <ul> <li><a href="#servicios"> Servicios </a> </li> <li><a href="#galeria"> Galeria </a> </li> <li><a href="#contacto">Contacta nos </a> </li> </ul> </nav> </header> <section id="main"> <article class="panel" id="servicios"> <h1> Nuestros Servicios</h1> </article> <article class="panel" id="galeria"> <h1> Mustra de nuestro trabajos</h1> </article> <article class="panel" id="contacto"> <h1> Pongamonos en contacto</h1> </article> </section>


Si alguien es como yo dispuesto a usar jQuery, pero aún así se encuentra buscando esta pregunta, entonces esto puede ayudarlos a ustedes:

https://html-online.com/articles/animated-scroll-anchorid-function-jquery/

$(document).ready(function () { $("a.scrollLink").click(function (event) { event.preventDefault(); $("html, body").animate({ scrollTop: $($(this).attr("href")).offset().top }, 500); }); });

<a href="#anchor1" class="scrollLink">Scroll to anchor 1</a> <a href="#anchor2" class="scrollLink">Scroll to anchor 2</a> <p id="anchor1"><strong>Anchor 1</strong> - Lorem ipsum dolor sit amet, nonumes voluptatum mel ea.</p> <p id="anchor2"><strong>Anchor 2</strong> - Ex ignota epicurei quo, his ex doctus delenit fabellas.</p>


Si bien algunas de las respuestas fueron muy útiles e informativas, pensé que escribiría la respuesta que se me ocurrió. La respuesta de Alex fue muy buena, sin embargo es limitada en el sentido de que la altura del div debe estar codificada en CSS.

Así que la solución que se me ocurrió utiliza JS (no jQuery) y en realidad es una versión simplificada (casi al mínimo) de soluciones para resolver problemas similares que encontré en Statckoverflow:

HTML

<div class="header"> <p class="menu"><a href="#S1" onclick="test(''S1''); return false;">S1</a></p> <p class="menu"><a href="#S2" onclick="test(''S2''); return false;">S2</a></p> <p class="menu"><a href="#S3" onclick="test(''S3''); return false;">S3</a></p> <p class="menu"><a href="#S4" onclick="test(''S4''); return false;">S3</a></p> </div> <div style="width: 100%;"> <div id="S1" class="curtain"> blabla </div> <div id="S2" class="curtain"> blabla </div> <div id="S3" class="curtain"> blabla </div> <div id="S4" class="curtain"> blabla </div> </div>

NOTA EL "RETORNO FALSO"; en la llamada al hacer clic. Esto es importante si quiere evitar que su navegador salte al enlace mismo (y deje que el efecto sea manejado por su JS).

Código JS:

<script> function scrollTo(to, duration) { if (document.body.scrollTop == to) return; var diff = to - document.body.scrollTop; var scrollStep = Math.PI / (duration / 10); var count = 0, currPos; start = element.scrollTop; scrollInterval = setInterval(function(){ if (document.body.scrollTop != to) { count = count + 1; currPos = start + diff * (0.5 - 0.5 * Math.cos(count * scrollStep)); document.body.scrollTop = currPos; } else { clearInterval(scrollInterval); } },10); } function test(elID) { var dest = document.getElementById(elID); scrollTo(dest.offsetTop, 500); } </script>

Es increíblemente simple. Encuentra la posición vertical del div en el documento utilizando su ID única (en la prueba de función). Luego llama a la función scrollTo pasando por la posición de inicio (document.body.scrollTop) y la posición de destino (dest.offsetTop). Realiza la transición utilizando algún tipo de curva de facilidad de entrada.

Gracias a todos por su ayuda.

Conocer un poco de codificación puede ayudarlo a evitar bibliotecas (a veces pesadas) y a darle a usted (el programador) más control.


Solo mozzila implementa una propiedad simple en css: http://caniuse.com/#search=scroll-behavior

deberás usar JS al menos.

Personalmente uso esto porque es fácil de usar (usa JQ pero puedo adaptarlo, supongo):

/*Scroll transition to anchor*/ $("a.toscroll").on(''click'',function(e) { var url = e.target.href; var hash = url.substring(url.indexOf("#")+1); $(''html, body'').animate({ scrollTop: $(''#''+hash).offset().top }, 500); return false; });

solo agregue el toque de clase a su etiqueta


Supongo que es posible establecer algún tipo de transición hardcore al estilo top de un #container div para mover toda tu página en la dirección deseada al hacer clic en tu delimitador. Algo así como agregar una clase que tiene la top:-2000px .

Usé JQuery porque también soy perezoso y uso JS nativo, pero no es necesario para lo que hice.

Probablemente esta no sea la mejor solución posible porque el contenido superior simplemente se mueve hacia la parte superior y no puede recuperarlo fácilmente, definitivamente debe usar JQuery si realmente necesita esa animación de desplazamiento.

DEMO