¿Hacer que la barra lateral fija se desplace 290 px desde la parte inferior de la página?

10 minutos de lectura

avatar de usuario
J82

Estoy tratando de crear una barra lateral que funcione como la de Vice.com. Si se desplaza hacia abajo, la barra lateral se fijará en un punto determinado y luego, cuando la barra lateral llegue a un punto determinado cerca de la parte inferior del sitio, continuará desplazándose hacia arriba con el resto del sitio.

En mi sitio, estoy atascado en la segunda parte, que consiste en hacer que la barra lateral continúe desplazándose hacia arriba una vez que llega casi al final. 290px desde abajo para ser exactos.

Esto es lo que tengo hasta ahora:

JavaScript

<script>
jQuery(window).scroll(function () {
    var threshold = 20;
 if (jQuery(window).scrollTop() >= 20)
     jQuery('#sidebar').addClass('fixed');
 else
     jQuery('#sidebar').removeClass('fixed');
});
</script>

CSS

#sidebar {
  margin: 0;
  position: absolute;
  right: 0;
  width: 220px;
}
#sidebar.fixed {
  margin-left: 720px;
  position:fixed;
  right: auto;
  top: 173px;
}

¿Cómo puedo hacer que la barra lateral fija se desplace hacia arriba una vez que llega a cierto punto cerca de la parte inferior?


Editar #1

Aquí está el código actualizado por Adam. Estoy usando una declaración condicional para las páginas que tienen un umbral diferente. No sucede nada cuando uso este código, lo que significa que la barra lateral no obtiene el fixed class agregado y, por lo tanto, se desplaza hacia arriba normalmente como si el código ni siquiera estuviera allí. Además, recibo un error de consola en esta línea. if (scrollTop() >= 236) { diciendo que el “número no es una función”.

if (jQuery(document.body).hasClass("home")) {

    jQuery(window).scroll(function () {
        var sidebarHeight = jQuery('#sidebar').height(),
            containerHeight = jQuery('#container').height() + 173,
            scrollTop = jQuery(window).scrollTop(),
            clientHeight = scrollTop + jQuery(window).height(),
            threshold = 654;
        if (scrollTop() >= 654) {
            jQuery('#sidebar').addClass('fixed');
        } else if (containerHeight - scrollTop <= sidebarHeight) {
            jQuery('#sidebar').removeClass('fixed').addClass('bottom');
        }
    });

} else if (jQuery(document.body).hasClass("single") || jQuery(document.body).hasClass("page")) {

    jQuery(window).scroll(function () {
        var sidebarHeight = jQuery('#sidebar').height(),
            containerHeight = jQuery('#container').height() + 173,
            scrollTop = jQuery(window).scrollTop(),
            clientHeight = scrollTop + jQuery(window).height(),
            threshold = 20;
        if (scrollTop() >= 20) {
            jQuery('#sidebar').addClass('fixed');
        } else if (containerHeight - scrollTop <= sidebarHeight) {
            jQuery('#sidebar').removeClass('fixed').addClass('bottom');
        }
    });

} else {

    jQuery(window).scroll(function () {
        var sidebarHeight = jQuery('#sidebar').height(),
            containerHeight = jQuery('#container').height() + 173,
            scrollTop = jQuery(window).scrollTop(),
            clientHeight = scrollTop + jQuery(window).height(),
            threshold = 236;
        if (scrollTop() >= 236) {
            jQuery('#sidebar').addClass('fixed');
        } else if (containerHeight - scrollTop <= sidebarHeight) {
            jQuery('#sidebar').removeClass('fixed').addClass('bottom');
        }
    });

}

A continuación se muestra la estructura HTML solicitada:

<!-- BEGIN #masthead-->
<div id="masthead">
    <!-- #secondary-menu -->
    <div id="secondary-menu">

        <!-- .centered-menu -->
        <div class="centered-menu">
            <div class="latest-tweets"></div>
            <div id="search-bar"></div>
            <ul class="social-icons sf-js-enabled"></ul>
        </div>
        <!-- /.centered-menu -->

    </div>
    <!-- /#secondary-menu -->

    <!-- BEGIN #header-->
    <div id="header">

        <!-- #header-inner -->
        <div id="header-inner" class="clearfix">
            <div id="logo"></div>

            <!-- BEGIN #primary-menu -->
            <div id="primary-menu" class="clearfix">

                <!-- .left-menu -->
                <div class="left-menu split-menu"></div>
                <!-- /.left-menu -->

                <!-- .right-menu -->
                <div class="right-menu split-menu">
                    <div class="menu-menu-right-container"></div>
                <!-- /.right-menu -->   

            <!-- END #primary-menu -->
            </div>

        </div>
        <!-- /#header-inner -->

    <!-- END #header -->

    <!-- BEGIN #mobile-menu -->
    <div id="mobile-menu">
        <div id="mobile-inner"></div>
    </div>
    <!-- END #mobile-menu -->

    </div>

    <div id="categories-bar"></div>

</div>
<div id="masthead-space"></div>
<!-- END #masthead -->

<!-- BEGIN #wrapper-->
<div id="wrapper">

    <!-- BEGIN #page-->
    <div id="page">

        <div id="main" class="clearfix">

            <div id="container" class="clearfix">

                <!--BEGIN #content -->
                <div id="content">
                    <div id="sidebar"></div><!-- #sidebar --> 
                </div>

            </div>

        <!--END #main -->
        </div>

    <!--END #page -->
    </div>

<!--END #wrapper -->
</div>

<!--BEGIN #bottom -->
<div id="bottom">

    <!--BEGIN #footer -->
    <div id="footer"></div>

</div>

  • No estoy seguro de la estructura de su página, por lo que mi respuesta puede estar un poco fuera de lugar, pero intentaré que funcione. Si puedes hacerme un violín, podría ser más preciso.

    – Adam Merrifield

    21 de marzo de 2014 a las 3:09

avatar de usuario
aramil rey

Mi consejo:

Cree 2 clases CSS con las características que desee y alterne ambas después de llegar al punto de interrupción, 1 debe estar activa al principio.

VIOLÍN

JS

var changePoint = $('#reaching_the_top_of_this_element_activates_change').offset().top;

$(window).scroll(function ()  {
if ($(window).scrollTop() >= changePoint) {
    $('#sidebar').removeClass('blackStatic');
    $('#sidebar').addClass('redFixed');
}
else {
    $('#sidebar').addClass('blackStatic');
    $('#sidebar').removeClass('redFixed');
}

});

CSS

.blackStatic {
    position: static;
    background-color: black;
    color: red;
}
.redFixed {
    position: fixed;
    top: 0;
    background-color: red;
    color: black;
}

Como dije en mi comentario, esto puede estar apagado porque no puedo ver la estructura del html en este momento. Pero algo como esto debería funcionar. Obtenemos la altura de la scrollbar, container(+ la altura del encabezado), y la altura del área visible para el usuario o el client. Así que usando las matemáticas, podemos decir que cuando el containerscrollTop es menor que la altura del scrollbar necesitamos que la barra de desplazamiento deje de estar arreglada. En este punto, eliminamos la clase fija y agregamos la clase inferior que solo tiene 1 propiedad. bottom: 0. Ahora, siempre que la barra de desplazamiento esté dentro del contenedor y el contenedor tenga position: relative su fondo se fijará al fondo del contenedor.

JavaScript:

jQuery(window).scroll(function(){
    var sidebarHeight = jQuery('#sidebar').height(),
        containerHeight = jQuery('#container').height() + 173,
        scrollTop = jQuery(window).scrollTop(),
        clientHeight = scrollTop + jQuery(window).height(),
        threshold = 20;
    if(scrollTop >= 20){
        jQuery('#sidebar').addClass('fixed');
    }else if(containerHeight - scrollTop <= sidebarHeight){
        jQuery('#sidebar').removeClass('fixed').addClass('bottom');
    }
});

CSS:

#sidebar.bottom {
    bottom: 0;
}

Avíseme si esto no funciona para usted y actualice su pregunta para tener el html para que pueda adaptarse más a sus necesidades. También tendrá que lidiar con un usuario que se desplaza hacia atrás en la página, lo que actualmente no tiene en cuenta, pero no sería difícil de agregar.

echa un vistazo a bootstrap-affix.js http://getbootstrap.com/2.3.2/javascript.html#affix

Hace exactamente lo que está pidiendo, y puede usar atributos de datos html5 para agregar los comportamientos:

<div data-spy="affix" data-offset-top="200">...</div>

  • He investigado esto y no puedo resolverlo. Desafortunadamente, no sé mucho sobre bootstrap, pero parece que hace lo que estoy pidiendo.

    – J82

    21 de marzo de 2014 a las 11:23

  • Lo siento, no puedo mejorar la respuesta por ahora, estoy en mi móvil, el enlace es para una versión anterior de bootstrap, para la última con instrucciones, vea esto getbootstrap.com/javascript

    – Lee Gary

    21/03/2014 a las 15:30

prueba este código (utilicé ID de acuerdo con tu marcado):

function sidebarScroll()
{
  var tmpWindow = $(window),
      wrapper = $('#wrapper').height(),
      header = $('#header').height(),
      sidebar = $('#sidebar'),
      offsetTop = sidebar.offset().top,
      offsetBottom;

  tmpWindow.scroll(function(){

    offsetBottom = (wrapper + header) - sidebar.height();

    if (tmpWindow.scrollTop() < offsetTop) {
      sidebar.removeClass('fixed bottom');
    } else if (tmpWindow.scrollTop() > offsetBottom) {
      sidebar.removeClass('fixed').addClass('bottom');
    } else {
      sidebar.removeClass('bottom').addClass('fixed');
    }
  });
}

sidebarScroll();

y estas son las clases que necesitas:

#wrapper {
  position: relative;
}
#sidebar {
  width: 220px;
  position: absolute;
  right: 0;
}

#sidebar.fixed {
  position: fixed;
  top: 0;
}

#sidebar.bottom {
  position: absolute;
  bottom: 0;
}

MANIFESTACIÓN

avatar de usuario
Impresionante

El código que tomaste prestado de Adam se copió mal. Utiliza scrollTop() en lugar de scrollTop. scrollTop está configurado en un número, por lo que esencialmente, está tratando de hacer 20 () (o cualquier número en el que esté configurado scrollTop)

Editar: para reducir la redundancia con su código, lo reescribí solo para establecer el umbral a través de declaraciones ternarias if:

jQuery(window).scroll(function () {
    var sidebarHeight = jQuery('#sidebar').height(),
    containerHeight = jQuery('#container').height() + 173,
    scrollTop = jQuery(window).scrollTop(),
    clientHeight = scrollTop + jQuery(window).height(),
    threshold = (jQuery(document.body).hasClass("home"))?654:((jQuery(document.body).hasClass("single") || jQuery(document.body).hasClass("page"))?20:236);
});

avatar de usuario
Fantasma

<div class="main">
</div>
<div class="foot">
</div>
<div id="float">
<div class="float_content_head">
I was sending javascript to display
</div><div class="float_content">
d my issue was that I was sending javascript to display console messages. Even when I looked at the file in my browser (not through the application) it showed exactly as I expected it to (eg the extra tags weren't showing), but there were showing in the html/text output and were trying to be parsed. Hope this helps someone!I had a similar problem, and my issue was that I was sending tags we
</div>
</div>

Css
<style type="text/css">
#float{
    background: #fff;
    position:absolute;
    right:30px;
    top:20px;
    width:250px;
    padding:10px;
    border-radius: 6px;
    -webkit-box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.43);
-moz-box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.43);
box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.43);
}
.float_content_head{
    padding:10px;
    border-bottom: 1px solid #efefef;
    text-align:center;
}
.float_content{
    padding-top:10px;
}
.main{
    width: 800px;
    height: 800px;
    margin: 0 auto;
    border:1px solid #efefef;
    padding: 10px;
    background:#ccc;
}
.foot{
    width: 100%;
    height: 800px;
    margin: 0 auto;
    border:1px solid #efefef;
    padding: 10px;
    background:#096;
}
#box p{
    margin:0;
    padding:0;
}
</style>

JS
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script type="text/javascript"> 
$(document).ready(function() {
var starting_position = $('#float').offset();
var top_padding = 50;
var bottom_limit = $('.foot').offset();
var box_height = $('#float').height() + 20;
$(window).scroll(function(){
var top_window = $(window).scrollTop();
if (top_window > starting_position.top && top_window < bottom_limit.top - box_height){
$('#float').stop().animate({top: top_window - starting_position.top + top_padding}, 400);
} else if (top_window > bottom_limit.top - starting_position.top - box_height){
$('#float').stop().animate({top: bottom_limit.top - starting_position.top - box_height }, 400);
} else { $('#float').stop().animate({top: 10 }, 400);           
}
});
});
</script>

avatar de usuario
timmah

Suena como esto es lo que buscas (disculpe mis identificaciones):

$(document).ready(function() {
// Get the inital position of the menu
    var initialPos = $('#mainnav').offset().top;

//Bind scrolling or resizing
$(window).bind('scroll resize', function() {

// Get the distance from the top of the page to the top of the footer
    var footerTop = $('#footer').length > 0 ? $('#footer').offset().top : $('#footer').offset().top;

// Get the distance from the top of the page to the bottom of the menu
    var navBottom = $(window).scrollTop() + $('#mainnav').height() + 22;

// If the user scrolls further than the height of the header (this method allows for resizing with a max-width layout)
    if ($(window).scrollTop() > initialPos) {
        $('#mainnav').css({
            'position': 'fixed',

           // move the menu based on how far the user has scrolled, and if it exceed the height of the footer
            'top': (footerTop - navBottom > 0 ? 0 : footerTop - navBottom) + 'px',
            'left': ($('#wrapper02').offset().left - $(window).scrollLeft()) + 'px'
        });
    } else {
        $('#mainnav').css({
            'position': 'static'
        });
    }
});
});

¿Ha sido útil esta solución?