Cómo arreglar un encabezado en scroll


Estoy creando un encabezado que una vez desplazado a una cierta cantidad de píxeles se corrige y permanece en su lugar.

¿Puedo hacer esto usando solo css y html o necesito jquery también?

He creado una demo para que puedas entender. Cualquier ayuda sería genial!

Http://jsfiddle.net/gxRC9/4 /

body{
    margin:0px;
    padding:0px;
}
.clear{
    clear:both;
}
.container{
    height:2000px;
}
.cover-photo-container{
width:700px;
height: 348px;
margin-bottom: 20px;
background-color:red;
}

.small-box{
    width:163px;
    height:100px;
    border:1px solid blue;
    float:left;
}

.sticky-header{
    width:700px;
    height:50px;
    background:orange;
    postion:fixed;
}
Author: Paul Designer, 2013-10-03

10 answers

Necesita algunos JS para hacer eventos de desplazamiento. La mejor manera de hacer esto es establecer una nueva clase CSS para la posición fija que se asignará al div relevante cuando el desplazamiento pase un cierto punto.

HTML

<div class="sticky"></div>

CSS

.fixed {
    position: fixed;
    top:0; left:0;
    width: 100%; }

JQuery

$(window).scroll(function(){
  var sticky = $('.sticky'),
      scroll = $(window).scrollTop();

  if (scroll >= 100) sticky.addClass('fixed');
  else sticky.removeClass('fixed');
});

Ejemplo de violín: http://jsfiddle.net/gxRC9/501 /


EDITAR: Ejemplo extendido

Si el punto de activación es desconocido, pero debe ser siempre que el sticky element llega a la parte superior de la pantalla, offset().top se puede utilizar.

var stickyOffset = $('.sticky').offset().top;

$(window).scroll(function(){
  var sticky = $('.sticky'),
      scroll = $(window).scrollTop();

  if (scroll >= stickyOffset) sticky.addClass('fixed');
  else sticky.removeClass('fixed');
});

Fiddle ejemplo extendido: http://jsfiddle.net/gxRC9/502 /

 88
Author: Coop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-08 11:30:40

He modificado la respuesta de la Cooperativa. Por favor, compruebe el ejemplo FIDDLE Aquí están mis ediciones:

$(window).scroll(function(){
  if ($(window).scrollTop() >= 330) {
    $('.sticky-header').addClass('fixed');
   }
   else {
    $('.sticky-header').removeClass('fixed');
   }
});
 11
Author: Mobeen Abdullah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-08 11:39:03

Sé que Coop ya ha respondido a esta pregunta, pero aquí hay una versión que también rastrea dónde está el div en el documento, en lugar de confiar en un valor estático:

Http://jsfiddle.net/gxRC9/16 /

Javascript

var offset = $( ".sticky-header" ).offset();
var sticky = document.getElementById("sticky-header")

$(window).scroll(function() {

    if ( $('body').scrollTop() > offset.top){
        $('.sticky-header').addClass('fixed');
    } else {
         $('.sticky-header').removeClass('fixed');
    } 

});

CSS

.fixed{
     position: fixed;
    top: 0px;
}
 8
Author: Rich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-03 12:14:33

La respuesta de Coop es excelente.
Sin embargo, depende de jQuery, aquí hay una versión que no tiene dependencias:

HTML

<div id="sticky" class="sticky"></div>

CSS

.sticky {
  width: 100%
}

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

JS
(Esto usa la respuesta de la ausencia de párpados para encontrar compensaciones en Vanilla JS.)

function findOffset(element) {
  var top = 0, left = 0;

  do {
    top += element.offsetTop  || 0;
    left += element.offsetLeft || 0;
    element = element.offsetParent;
  } while(element);

  return {
    top: top,
    left: left
  };
}

window.onload = function () {
  var stickyHeader = document.getElementById('sticky');
  var headerOffset = findOffset(stickyHeader);

  window.onscroll = function() {
    // body.scrollTop is deprecated and no longer available on Firefox
    var bodyScrollTop = document.documentElement.scrollTop || document.body.scrollTop;

    if (bodyScrollTop > headerOffset.top) {
      stickyHeader.classList.add('fixed');
    } else {
      stickyHeader.classList.remove('fixed');
    }
  };
};

Ejemplo

Https://jsbin.com/walabebita/edit?html,css,js, output

 6
Author: RubenSandwich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-31 16:54:40

Simplemente construyendo sobre la respuesta de Rich, que usa desplazamiento.

Modifiqué esto de la siguiente manera:

  • No había necesidad de var $sticky en el ejemplo de Rich, no estaba haciendo nada
  • He movido el cheque de desplazamiento a una función separada, y lo llamé en documento listo, así como en desplazamiento por lo que si la página se actualiza con el desplácese a la mitad de la página, cambia de tamaño de inmediato sin tener que esperar un disparador de desplazamiento

    jQuery(document).ready(function($){
        var offset = $( "#header" ).offset();
        checkOffset();
    
        $(window).scroll(function() {
            checkOffset();
        });
    
        function checkOffset() {
            if ( $('body').scrollTop() > offset.top){
                $('#header').addClass('fixed');
            } else {
                $('#header').removeClass('fixed');
            } 
        }
    
    });
    
 4
Author: crdunst,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:02:26

La respuesta de Coops es una solución buena y simple, sin embargo, una vez que se aplica la clase fija, la página se vuelve mucho más corta y el contenido "saltará" hacia arriba, y si la página es de una longitud donde la distancia de desplazamiento es menor que la altura del elemento de encabezado, parecerá saltar y no le permitirá ver la parte inferior de la página.

La respuesta que encontré fue agregar un div espaciador por encima del elemento que se convertirá en fijo (elemento nav en mi caso), y establecerlo a la misma altura que el elemento nav, y establecer para mostrar ninguno.

Al agregar el .clase fija al nav, mostrar el .nav-div espaciador, y al quitarlo, ocultarlo. Dado que la altura de la página cambia instantáneamente, he establecido la duración en 0.

HTML

<header>the element above the element that will become fixed</header>
<div class="nav-spacer"></div>
<nav></nav>

CSS

nav {
    position: relative;    
    height: 100px;
}
.nav-spacer{
    position: relative;
    height: 100px;
    display: none;
}
.fixed {
    position: fixed;
    top:0;
    left:0;
    width: 100%;
    /* I like to add a shadow on to the fixed element */
    -webkit-box-shadow: 0px 5px 10px 1px rgba(0,0,0,0.25);
    -moz-box-shadow: 0px 5px 10px 1px rgba(0,0,0,0.25);
    box-shadow: 0px 5px 10px 1px rgba(0,0,0,0.25);
}

JavaScript

var stickyOffset = $('nav').offset().top;

$(window).scroll(function(){
    if ($(window).scrollTop() >= stickyOffset){
        $('nav').addClass('fixed');
        //this makes the page length equal to what it was before fixing nav
        $('.nav-spacer').show(0); 
    }
    else {
        $('nav').removeClass('fixed');
        $('.nav-spacer').hide(0);
    }
});
 4
Author: Craig Jacobs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-29 04:12:01
 $(document).ready(function(){

    var div=$('#header');
    var start=$(div).offset().top;

    $.event.add(window,'scroll',function(){
        var p=$(window).scrollTop();
        $(div).css('position',(p>start)?'fixed':'static');
        $(div).css('top',(p>start)?'0px':'');

    }); 
});

Funciona perfectamente.

 1
Author: arjun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-04 13:07:08

La solución elegida no encajaba bien en mi página. Así que esta es una versión más avanzada que funciona con bootstrap.

El javascript

var stickyOffset = $('.sticky-header').offset().top;

$(window).scroll(function () {
    var sticky = $('.sticky-header'),
        scroll = $(window).scrollTop(),
        header = $('.fixed-header-background');
    sticky.each(function() {
        var left = $(this).offset().left;
        $(this).data('left', left);//I store the left offset
    });

    if (scroll >= stickyOffset) {
        sticky.addClass('fixed');
        header.css('display', 'block');
        sticky.each(function() {
            $(this).css('left', $(this).data('left'));//I set the left offset
        });
    } else {
        sticky.removeClass('fixed');
        header.css('display', 'none');
        sticky.each(function () {
            $(this).css('left', '');//I remove the left offset
        });
    }
});

El CSS

.fixed-header-background {
    display: none;
     position: fixed;
    top: 50px;
    width: 100%;
    height: 30px;
    background-color: #fff;
    z-index: 5;
    border-bottom-style: solid;
    border-bottom-color: #dedede;
    border-bottom-width: 2px;
}

.fixed{
     position: fixed;
    top: 52px;
    z-index: 6;
}

Y el HTML

    <div class="fixed-header-background"></div>
<table class="table table-hover table-condensed">
        <thead>
            <tr>
                <th></th>
                <th><span class="sticky-header">My header 1</span></th>
                <th><span class="sticky-header">My header 2</span></th>
            </tr>
        </thead>
        <tbody>
[....]

        </tbody>
    </table>
 1
Author: Daniel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-05 09:37:33

O simplemente agregue una etiqueta span con la altura del encabezado fijo establecido como su altura y luego insértela junto al encabezado adhesivo:

$(function() {
  var $span_height = $('.fixed-header').height;
  var $span_tag = '<span style="display:block; height:' + $span_height + 'px"></span>';

  $('.fixed-header').after($span_tag);
});
 1
Author: user3721605,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-16 11:18:46

Esperemos que esta pieza de una solución alternativa sea tan valiosa para alguien más como lo fue para mí.

Situación:
En una página HTML5 tenía un menú que era un elemento nav dentro de un encabezado (no EL encabezado sino un encabezado en otro elemento).
Quería que la navegación se adhiriera a la parte superior una vez que un usuario se desplazó hacia ella, pero antes de esto, el encabezado estaba posicionado de forma absoluta (para que pudiera superponer algo más ligeramente).
Las soluciones anteriores nunca desencadenaron una cambiar porque .offsetTop no iba a cambiar ya que este era un elemento posicionado absoluto. Además el .La propiedad scrollTop era simplemente la parte superior del elemento más superior... es decir, 0 y siempre sería 0.
Cualquier prueba que realicé utilizando estos dos (y lo mismo con los resultados de getBoundingClientRect) no me diría si la parte superior de la barra de navegación alguna vez se desplazó a la parte superior de la página visible (de nuevo, como se informó en la consola, simplemente se mantuvieron los mismos números mientras se desplazaba ocurrir).

Solución
La solución para mí estaba utilizando

window.visualViewport.pageTop

El valor de la propiedad pageTop refleja la sección visible de la pantalla, lo que me permite rastrear dónde está un elemento en referencia a los límites del área visible.
Esto permitió que una función simple asignada al evento de desplazamiento de la ventana detectara cuando la parte superior de la barra de navegación se cruzaba con la parte superior del área visible y aplicara el estilo para hacerlo quédate arriba.

Probablemente innecesario decir, cada vez que estoy tratando con desplazamiento espero usar esta solución para responder programáticamente al movimiento de los elementos que se desplazan.
Espero que ayude a alguien más.

 0
Author: MER,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-24 19:41:01