Quiero dibujar una línea en la pantalla desde la parte superior de la página hasta la parte inferior cuando el usuario se desplaza por la página y tiene una flecha en la parte inferior. No quiero usar una posición fija para que siempre esté en el mismo lugar, quiero que indique dónde están en la página determinando la longitud de la página, etc.

Tengo el siguiente código que funciona hasta cierto punto. El problema con esto es que la flecha desaparece de la parte inferior de la página cuando me desplazo justo después de la mitad.

He intentado diferentes variaciones de este código pero ninguno funciona. ¿Alguien puede ayudar?

//Draw dotted line on scroll - works to certain extent but scrolls off page
    $( window ).scroll(function() {
        if ( $.windowScrollTop() > 10 ) {
            var pos = $.windowScrollTop();
            var scrollHeight = $(window).innerHeight();
            var element = $('#dashes');
            $( '#line' ).css( 'height', pos - scrollHeight / 4 );
            $( '#arrow' ).css( 'top', pos - scrollHeight / 4 );
        } else {
            $( '#line' ).css( 'height', '6px' );
            $( '#arrow' ).css( 'top', '-150px' );
        }
    });

//also tried the below

    $(window).on("scroll", function() {
        var scrollHeight = $(document).height();
        var scrollPosition = $(window).height() + $(window).scrollTop();
        if ((scrollHeight - scrollPosition) / scrollHeight === 0) {
            // when scroll to bottom of the page
            alert('bottom');
        } else {
                $( '#line' ).css( 'height', $(window).scrollTop() );
                $( '#arrow' ).css( 'top', $(window).scrollTop() );      
        }
    });
11
LeeTee 27 feb. 2018 a las 15:54

3 respuestas

La mejor respuesta

Lo que estamos tratando de hacer aquí es reflejar la altura del documento en un elemento de altura de ventana. Entonces, la altura real del documento desplazable será

    var actualScrollHeight = $(document).height() - $(window).height();
    /* This is the distance we actually scroll */

Y nuestro #line tendrá una altura máxima posible de

    var lineMaxHeight = $(window).height() - topMargin - bottomMargin - arrowHeight;
    /* #arrow is inside #line but we positioned it outside it's height */

No para reflejar el progreso del desplazamiento en #line altura de elementos, lo que debemos hacer es

    var lineHeight = $(document).scrollTop() / actualScrollHeight * lineMaxHeight;
    /* Super Easy, isn't it? */

El resultado final:

No necesita posicionar tanto #line como #arrow. Fije el #arrow en la parte inferior de #line y luego simplemente cambiar la altura de #line funciona bien. Agregué las funciones topMargin y bottomMargin para personalizar más el ajuste de la pantalla.

$(function(){
  var topMargin = 15, bottomMargin = 5;
  var arrowHeight = $('#arrow').height();
  var $lineElement = $('#line');
  $lineElement.height(topMargin);
  $(window).scroll(function() {
    var winHeight = $(window).height();
    var actualScrollHeight = $(document).height() - winHeight;
    var lineMaxHeight = winHeight - topMargin - bottomMargin - arrowHeight;
    var scrollTop = $(document).scrollTop();
    var lineHeight = scrollTop / actualScrollHeight * lineMaxHeight;
    $lineElement.height(topMargin + lineHeight);
  });
});
#logo {
  width: 80px;
  background-color: #53befd;
  padding: 20px;
}

#line {
  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAMCAYAAABBV8wuAAAAFklEQVR42mNgoB74OEXzPzY8sBLUAwB6PmBV1D+CIAAAAABJRU5ErkJggg==);
  position: fixed;
  top: 0px;
  right: 19px;
  z-index: 20;
  width: 3px;
}

#arrow {
  background-color: #f28323;
  height: 40px;
  width: 40px;
  position: absolute;
  bottom: -40px;
  left: -18px;
  border-radius: 20px;
  color: white;
  text-align: center;
  font-size: 32px;
  line-height: 35px;
  padding-top: 3px;
  cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="logo">LOGO </div>
<p>  Page content go here<br /> and here<br /> and here<br /> and here<br /> and here</p><p>  Page content go here<br /> and here<br /> and here<br /> and here<br /> and here</p><p>  Page content go here<br /> and here<br /> and here<br /> and here<br /> and here</p><p>  Page content go here<br /> and here<br /> and here<br /> and here<br /> and here</p><p>  Page content go here<br /> and here<br /> and here<br /> and here<br /> and here</p><p>  Page content go here<br /> and here<br /> and here<br /> and here<br /> and here</p><p>  Page content go here<br /> and here<br /> and here<br /> and here<br /> and here</p><p>  Page content go here<br /> and here<br /> and here<br /> and here<br /> and here</p><p>  Page content go here<br /> and here<br /> and here<br /> and here<br /> and here</p><p>  Page content go here<br /> and here<br /> and here<br /> and here<br /> and here</p>
<div id="line"><div id="arrow">V</div></div>
7
Munim Munna 2 mar. 2018 a las 06:39

Aquí hay una solución más fácil con menos código:

$(function() {
  $(window).scroll(function() {
    var p = ($('body').height() - $(window).height()) / ($(window).height() - 43);
    var scrollTop = $(document).scrollTop() / p;
    $(':root').css('--scroll-top', scrollTop + 43 + "px");
  });
});
:root {
  --scroll-top: 43px;
}

#logo {
  width: 80px;
  background-color: #53befd;
  padding: 20px;
}

.content {
  height: 210vh;
  background: red;
  margin-right: 50px;
}

#line:before {
  content: "V";
  background-color: #f28323;
  height: 40px;
  width: 40px;
  display: inline-block;
  position: absolute;
  right: 0;
  bottom: 0;
  border-radius: 20px;
  color: white;
  text-align: center;
  font-size: 32px;
  line-height: 35px;
  padding-top: 3px;
  cursor: pointer;
}

#line {
  position: fixed;
  top: 0;
  right: 0;
  height: var(--scroll-top);
  width: 40px;
  background: linear-gradient(to bottom, #f28323 50%, transparent 50%) 50% 0/3px 12px repeat-y;
}
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<div id="logo">LOGO </div>
<div class="content"></div>

<div id="line"></div>
3
Temani Afif 2 mar. 2018 a las 09:14

Tus enfoques parecen que lo estás pensando demasiado. Veo un elemento HTML progress que gira 180 grados para lo visual. Luego, configure su atributo value dinámicamente con JS a medida que el usuario se desplaza y la línea esencialmente se verá como si estuviera animando hacia abajo.

// PROGRESS INDICATOR
// Calculate height of main object and the window, set max attr of progress accordingly
var winHeight = $(window).height(),
    sectionHeight = $('#line').height(),
    progressBar = $('progress'),
    max,
    value;

// Set the maximum scrollable area
max = sectionHeight - winHeight;
progressBar.attr('max', sectionHeight);

// Set value attr of progress, changes as user scrolls
$(document).on('scroll', function(){
  value = $(window).scrollTop();
  progressBar.attr('value', value);
});

CSS para el elemento de progreso se vería más o menos así, donde coloca la barra como un elemento fijo en la página y la anima para cubrir progresivamente más de la página con el JS anterior.

Ejemplo de CSS:

progress {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  background-color: transparent;
  border: none; //firefox fix
  color: green;
  height: 2.5rem;
  margin-top: 20vw;
  position: fixed;
  top: 8rem;
  width: 100vh;

  @media (min-width: 768px) and (max-width: 1200px) {
    display: block;
    transform: rotate(90deg) translateY(1800%);
  }

  @media (min-width: 1200px) {
    display: block;
    transform: rotate(90deg) translateY(1200%); // matches content shift to smaller column
  }
}

Construí esto en uno de mis sitios cliente si quieres ver si trabajas en la naturaleza (solo funciona a aproximadamente 1000 px y más, así que asegúrese de que su ventana sea lo suficientemente ancha).

3
serraosays 1 mar. 2018 a las 16:44