Ein Menü, das beim Scrollen oben stehen bleibt, gehört heute zum Standard. Als ich diesen Beitrag zum ersten Mal geschrieben habe, brauchte es dafür noch JavaScript, das bei jedem Scrollvorgang die Position misst. Das ist inzwischen überflüssig: Zwei Zeilen CSS genügen.
Der heutige Weg: position: sticky
.navigation-main {
position: sticky;
top: 0;
z-index: 100;
}
Mehr ist es nicht. Das Element verhält sich normal, solange es im sichtbaren Bereich liegt, und bleibt am oberen Rand kleben, sobald es hinausgescrollt würde. Kein JavaScript, kein Ruckeln, und die Höhe der Seite ändert sich nicht.
Warum es manchmal trotzdem nicht funktioniert
Wenn position: sticky wirkungslos bleibt, liegt es fast immer an einer dieser drei Ursachen:
Ein Elternelement mit overflow
Steht bei irgendeinem übergeordneten Element overflow: hidden, auto oder scroll, wird das Kleben abgeschaltet. Das ist mit Abstand der häufigste Grund. In Shopware-Themes findet sich so eine Regel gern an einem Wrapper, der eigentlich nur ein Layoutproblem lösen sollte.
Kein Bezugspunkt
Die Angabe top ist Pflicht. Ohne sie weiß der Browser nicht, ab wann geklebt werden soll, und es passiert schlicht nichts.
Ein zu niedriger z-index
Das Menü klebt, verschwindet aber hinter dem Inhalt. Dann fehlt ein ausreichend hoher z-index.
Wenn sich das Menü beim Scrollen verändern soll
Soll der Kopfbereich beim Scrollen zusätzlich schmaler werden oder die Farbe wechseln, braucht es doch ein wenig JavaScript. Ein Scroll-Handler ist dafür aber der schlechteste Weg, weil er bei jeder Bewegung feuert. Besser ist ein IntersectionObserver, der nur meldet, wenn sich der Zustand tatsächlich ändert:
const header = document.querySelector('.navigation-main');
const marke = document.createElement('div');
header.before(marke);
new IntersectionObserver(
([eintrag]) => header.classList.toggle('is-stuck', !eintrag.isIntersecting)
).observe(marke);
Der unsichtbare Marker steht direkt über dem Menü. Sobald er aus dem Bild scrollt, bekommt das Menü die Klasse is-stuck, und der Rest ist wieder CSS. Genau so arbeitet auch der Kopfbereich dieser Website.
Der alte Weg, der Vollständigkeit halber
Für Shopware 5 mit jQuery sah die Lösung so aus. Sie funktioniert weiterhin, ist aber nur noch interessant, wenn ein Projekt aus anderen Gründen ohnehin an dieser Technik hängt:
var menu = $(".navigation-main"),
menuscrolled = "main-nav-scrolled",
headr = $('.header-main').height(),
wdth = $('.container').width();
$(window).scroll(function () {
if ($(this).scrollTop() > headr) {
menu.addClass(menuscrolled);
menu.css('width', wdth + 'px');
} else {
menu.removeClass(menuscrolled);
}
});
Der Nachteil ist gut sichtbar: Die Breite muss von Hand nachgerechnet werden, weil position: fixed das Element aus dem Textfluss nimmt. Bei position: sticky entfällt das ersatzlos.
Hilfe bei Shopware
Wenn Sie an Ihrer Shopware-Installation Anpassungen am Template brauchen, Updates anstehen oder eine Migration von Shopware 5 auf Shopware 6 im Raum steht: Melden Sie sich, ich schaue mir das gern an.