Be KreaTief

Sticky Navigation (oder Header) ohne Jump ✤✤(✤)

Ich wurde letztens gefragt, wie ich denn meine Navigation sticky gemacht habe und habe versprochen, dass ich dazu einen Post schreibe.
Eigentlich wollte ich euch das Script präsentieren, das ich für mein Menu geschrieben habe. Da ich dieses in letzter Zeit für mehrer Projekte verwendet habe, ist mir aber aufgefallen, dass es ein bisschen Probleme macht. Das ist nicht das Problem meines sticky scripts, es ist das Problem von vielen Scripten. Nach Recherche und viel Trial und Error, habe ich nun ein Script zusammengestellt, dass das Problem nicht aufweist.


Das Problem vieler dieser Scripte ist, dass es einen Sprung gibt, sobald man runterscrollt und die Navigation oben fixiert bleibt. Das äussert sich ausserdem darin, dass der Content, der unterhalb der Navigation platziert ist durch das Ändern der Positionierung plötzlich von der Navigation verdeckt wird. Hat man nur eine dünne Navigation, fällt das kaum auf, doch wenn ihr bei folgendem Beispiel ganz langsam scrollt, werdet ihr sehen, dass sobald das Menu die Oberkante erreicht, der Titel darunter verdeckt wird. Das ist der Sprung von dem ich gesprochen habe und das ist das, was wir vermeiden wollen.

See the Pen HvtgD by Myri (@bekreatief) on CodePen.



Bei einem klassischen Script, braucht ihr nur einen Container, hier brauchen wir etwas mehr Markup.
Die Idee ist, einen Platzhalter hinter dem Menu zu platzieren, mit der gleichen Höhe, Dieser Platzhalter wird nicht aus dem Kontext geworfen, sondern scrollt einfach weiter. Das heisst kein Sprung, weil das Element, das wir entfernen, über einem anderen Element liegt, das wir nicht entfernen.
Dieser Container braucht die gleiche Höhe wie unser Menu. Da man meist keine Höhe definiert, lassen wir das jQuery machen.

Nehmen wir ein Beispiel.

Unser Markup sieht wie folgt aus:

<div class="fix_wrap">
  <div class="fix_hold"></div>
  <nav class="fix_nav">
    <a href="#">Link 1</a>
    <a href="#">Link 2</a>
    <a href="#">Link 3</a>
    <a href="#">Link 4</a>
    <a href="#">Link 5</a>
  </nav>
</div>

Unser Style dazu ist ganz simpel:

.fix_wrap {
  position: relative;
  left: 0;
  top: 0;
}
.fix_wrap .fix_nav {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  text-align: center;
  background: #8c4698;
  padding: 10px 0px;
}

Jetzt müssen wir nur noch etwas jQuery schreiben, dass die Höhe der Navigation liest und diese Höhe dem Platzhalter zuweist. Und dann ändern wir die Position des Menus von absolute zu fixed, sobald das Menu die Oberkante des Fensters erreicht hat.

$(function(){
  var gluetube = $('.fix_wrap');
  var glue = $('.fix_nav');        
  var grease = $('.fix_hold');        
  var h = (glue).height();        
  var offset = glue.offset();        
  var glueTop = offset.top;        
  var windowTop = $(window).scrollTop();        
  
  function sticky(){            
    grease.css({'height':h});            
    windowTop = $(window).scrollTop();            
    return glue.css({position: windowTop>glueTop ? "fixed": "absolute" });        
  }        
  
  $(window).on("load resize scroll",function(e){            
    sticky();        
  });    
});

Das ganze würden wir dann in einem Gadget oder direkt im Code des Menus platzieren. Vergesst dabei nicht jQuery zu integrieren, am beste direkt vor dem schliessenden body-tag und drunter dieses Script.
Wollt ihr es in ein Gadget kopieren, würde das so aussehen:

<div class="fix_wrap">
  <div class="fix_hold"></div>
  <nav class="fix_nav">
    <a href="#">Link 1</a>
    <a href="#">Link 2</a>
    <a href="#">Link 3</a>
    <a href="#">Link 4</a>
    <a href="#">Link 5</a>
  </nav>
</div>

<style>
.fix_wrap {
  position: relative;
  left: 0;
  top: 0;
}
.fix_wrap .fix_nav {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  text-align: center;
  background: #8c4698;
  padding: 10px 0px;
}
</style>

<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<script>
$(function(){
  var gluetube = $('.fix_wrap');
  var glue = $('.fix_nav');        
  var grease = $('.fix_hold');        
  var h = (glue).height();        
  var offset = glue.offset();        
  var glueTop = offset.top;        
  var windowTop = $(window).scrollTop();        
  
  function sticky(){            
    grease.css({'height':h});            
    windowTop = $(window).scrollTop();            
    return glue.css({position: windowTop>glueTop ? "fixed": "absolute" });        
  }        
  
  $(window).on("load resize scroll",function(e){            
    sticky();        
  });    
});
</script>

Zum Vergleich habe ich euch das gleiche Demo wie vorhin noch mit dem neuen Script geschrieben, damit ihr sehen könnt, wie smooth der sticky Effekt verläuft.


See the Pen gHomL by Myri (@bekreatief) on CodePen.

edit