5 Webdesign-Trends für deine One-Page-Website zum Nachprogrammieren
- Parallax-Scrolling: Erzeugt beim Herunterscrollen die Illusion räumlicher Tiefe.
- Scrollbasierte Fade-In-Animationen: animierte Übergänge (etwa Einblenden, Einschweben), mit denen bestimmte Seitenelemente allmählich sichtbar gemacht werden. Die Animation startet, sobald der Nutzer den betreffenden Abschnitt durch Scrollen erreicht hat.
- Scrollbasierte Menü-Hervorhebungen: Beim Scrollen der Seite wird der aktuell sichtbare Seitenabschnitt im Menü hervorgehoben.
- Bild-Overlays: Beim Anklicken oder Berühren eines Bildes mit der Maus wird direkt über dem Bild Text eingeblendet. Overlays eignen sich etwa für Bildergalerien: Für jedes Bild können zusätzliche Informationen bereitgestellt werden, ohne die Website mit Text zu überladen.
- Preloading-Screen: Eine Lade-Animation, die in der Regel den ganzen Bildschirm ausfüllt und erst ausgeblendet wird, nachdem alle Seiteninhalte vollständig geladen worden sind.
Diese Merkmale moderner One-Page-Websites können zu einem verbesserten Nutzererlebnis und zu einer verbesserten Ästhetik der Seite beitragen. Mit geeigneten Animationen kann das Scrollen der Seite interessant und unterhaltsam gestaltet werden. Außerdem lässt sich die Aufmerksamkeit der Nutzer gezielt auf bestimmte Seitenelemente lenken.
Anhand einer einfachen, aufs Allerwesentliche reduzierten Beispielseite soll nun gezeigt werden, wie sich diese fünf Gestaltungsmerkmale mit wenig Programmieraufwand in CSS und JavaScript umsetzen lassen.
Parallax-Scrolling
Hier ist die Basis-Version unserer Beispielseite zu sehen.
Die Seite enthält einen Header mit einem fixierten Hintergrundbild. Im nächsten Schritt wird auf dem Hintergrundbild ein weiteres Bild eingefügt, in diesem Fall ein transparentes Seifenblasen-Bokeh. Ein parallaktischer Effekt soll dadurch erzeugt werden, dass sich während des Scrollens die Seifenblasen mit einer geringeren Geschwindigkeit bewegen als der Header-Text.
Abbildung 1: Parallaktischer Effekt beim Scrollen des Headers
Zur Umsetzung wird die CSS-Eigenschaft perspective benötigt. Sie bestimmt die Entfernung zwischen der Ebene z=0 und dem Nutzer. Die Eigenschaft ist die Voraussetzung dafür, dass alle nachfolgenden perspektivischen Transformationen tatsächlich Wirkung zeigen.
Wir führen also ein Div-Element mit der Klasse „wrapper“ ein, die abgesehen vom Menü den kompletten Seiteninhalt umschließt. Das Div bekommt die Eigenschaft perspective: 1px zugewiesen. Anschließend fügen wir das zweite Hintergrundbild ein. Mit der Einstellung transform: translateZ(-1px) scale(2) wird es entlang der z-Achse um 1px räumlich nach hinten versetzt. Die unterschiedliche räumliche Tiefe zwischen den Seifenblasen und dem Header-Text macht sich beim Scrollen bemerkbar – wir erhalten den gewünschten parallaktischen Effekt. Da das Bild aufgrund der größeren Entfernung auch kleiner dargestellt wird, muss zum Ausgleich eine Skalierung auf die doppelte Größe vorgenommen werden.
.wrapper {
height: 100vh;
overflow-x: hidden;
scroll-behavior: smooth;
transform-style: preserve-3d;
perspective: 1px;
}
header{
transform-style: inherit;
}
header::after {
content: " ";
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
transform: translateZ(-1px) scale(2);
background-size: cover;
background-position: bottom;
z-index:-1;
background-image: url('https://blaustern.eu/bokeh.png');
background-repeat: no-repeat;
}
Das erweiterte Beispiel findet ihr hier.
Scrollbasierte Fade-in-Animationen
In der Beispiel-Website wird nun folgende Animationen umgesetzt:
- Beim Öffnen der Seite wird der Header-Text in einer zweisekündigen Animation von unten nach oben eingeblendet (fade up).
- Der Text der ersten Section und die Listenelemente der zweiten Section werden in einer einsekündigen Animation von unten nach oben eingeblendet, sobald der Nutzer die jeweilige Position durch Scrollen erreicht hat.
- Die Bilder werden abwechselnd in einer gemeinsamen Reihe von links nach rechts beziehungsweise von rechts nach links eingeblendet.
Abbildung 2: Verschiedene Scroll-Animationen
Im ersten Schritt müssen die betreffenden HTML-Elemente in den Ausgangszustand versetzt werden, sie sind also unsichtbar (opacity: 0) und um einen bestimmten Grad nach unten (zum Beispiel transform: translateY(50%) für den Header-Text) beziehungsweise nach links oder rechts versetzt (zum Beispiel transform: translateX(-50%) für die Bilder-Galerie (siehe auch: Klassen header_transformed, item_transformed, grid_transformed).
Im zweiten Schritt werden die jeweiligen Animationen definiert (vergleiche: Klassen header_animated, text_animated, grid_animated). Dabei werden sowohl die Eigenschaften der Animation wie die Animationsdauer als auch der Zielzustand (beispielsweise transform: translateY(0); opacity: 0 für den Header-Text) festgelegt. Die Listenelemente erhalten eine individuelle Verzögerung der Animation (animation-delay).
Für die Bildergalerie gibt es eine besondere Anforderung: Bei mittleren und großen Bildschirmen sollen die ungeraden Bildreihen von links nach rechts und die geraden Bildreihen von rechts nach links animiert werden. Gleichzeitig passt sich das Layout der Galerie flexibel an die Bildschirmgröße an, bei mittleren Bildschirmen befinden sich in jeder Reihe zwei, bei großen Bildschirmen in jeder Reihe drei Bilder. Innerhalb der Media-Queries wird der nth-child-Selektor verwendet, um diese Anforderungen zu formulieren.
Im Gegensatz zur Klasse header_animated können die Klassen „text_animated“ und „grid_animated“ den einzelnen HTML-Elementen nicht statisch zugewiesen werden, denn die jeweiligen Animationen sollen erst ablaufen, sobald die Elemente durch Scrollen sichtbar gemacht worden sind. Die Überprüfung der Sichtbarkeit wird mithilfe von JavaScript realisiert. Mit dem Intersection-Observer steht neuerdings eine Technologie zur Verfügung, die scrollbasierte Implementierungen sehr einfach macht (die Intersection-Observer-API befindet sich noch im Status „Working Draft“). Im folgenden Code-Beispiel wird gezeigt, wie zwei Instanzen des Intersection-Observers mit entsprechenden Callback-Funktionen initialisiert werden. Die Observer werden den Elementen mit der Klasse „item_transformed“ beziehungsweise „grid_transformed“ zugewiesen.
Der erweiterte CSS-Code:
.header_transformed {
opacity: 0;
transform: translateY(50%);
}
.header_animated {
animation: text_animation 2s ease 0s forwards;
}
@keyframes text_animation {
0% {
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
}
.item_transformed {
opacity: 0;
transform: translateY(10%);
}
.item_transformed:nth-child(1) {
animation-delay: 0s;
}
.item_transformed:nth-child(2) {
animation-delay: 100ms;
}
.item_transformed:nth-child(3) {
animation-delay: 200ms;
}
.item_transformed:nth-child(4) {
animation-delay: 300ms;
}
.item_transformed:nth-child(5) {
animation-delay: 400ms;
}
.item_transformed:nth-child(6) {
animation-delay: 500ms;
}
.item_animated {
animation: text_animation 1s ease 0s forwards;
}
Der erforderliche JavaScript-Code:
if (IntersectionObserver) {
let callback = function(entries) {
entries.forEach(entry => {
//wenn das Element sichtbar ist, Klasse „item_animated“ hinzufügen
if (
entry.isIntersecting &&
!entry.target.classList.contains("item_animated")
) {
entry.target.classList.add("item_animated");
}
});
};
let callback2 = function(entries) {
entries.forEach(entry => {
//if the element is visible, add the animated class
if (
entry.isIntersecting &&
!entry.target.classList.contains("grid_animated")
) {
entry.target.classList.add("grid_animated");
}
});
};
let observer = new IntersectionObserver(callback);
let observer2 = new IntersectionObserver(callback2, {
//Callback auslösen, sobald 20% vom Element sichtbar sind
threshold: 0.2
});
//Hole und beobachte alle Elemente mit der Klasse „item_transformed“
let items = document.querySelectorAll(".item_transformed");
items.forEach(item => {
observer.observe(item);
});
//Hole und beobachte alle Elemente mit der Klasse „grid_transformed“
let items2 = document.querySelectorAll(".grid_transformed");
items2.forEach(item => {
observer2.observe(item);
});
}
Das erweiterte Beispiel findet ihr hier.
Scrollbasierte Menü-Hervorhebungen
Das Menü der Beispielseite enthält Links, mit denen zu den einzelnen Abschnitten gesprungen werden kann. Der Abschnitt, der für den Nutzer gerade sichtbar ist, soll im Menü durch eine weiße Unterstreichung hervorgehoben werden. Dafür entwickeln wir die Klasse „active“. Um zu ermitteln, welcher Abschnitt gerade sichtbar ist, wird wieder der Intersection-Observer verwendet. In diesem Fall verknüpfen wir ihn mit den einzelnen Abschnittsüberschriften (Klasse „section_heading“).
Eine kleine Herausforderung ergibt sich daraus, dass mehrere Abschnitte gleichzeitig auf dem Bildschirm sichtbar sein können. Standardmäßig wird der am weitesten unten liegende Abschnitt im Menü hervorgehoben. Das widerspricht jedoch der Nutzererwartung: Beim Scrollen von oben nach unten sollte stattdessen der jeweils oberste sichtbare Abschnitt hervorgehoben werden. Das gewünschte Verhalten kann in der Callback-Funktion leicht umgesetzt werden. Dabei verfolge ich eine bestimmte Strategie: Jedes Mal, wenn die Callback-Funktion durch den Intersection-Observer ausgelöst wird, markieren wir den neu identifizierten sichtbaren Abschnitt (Klasse „visible“). Die vollständige Liste der sichtbaren Abschnitte fragen wir anschließend mit dem Befehl document.querySelector(„.visible“) ab (Funktion „highlightFirst()“). Daraus wählen wir den ersten, also obersten Abschnitt aus und weisen ihm die Klasse „active“ zu.
Der erweiterte CSS-Code:
.active {
border-bottom: 1px solid white;
}
Der erweiterte JavaScript-Code:
let callback3 = function(entries) {
for (let i = 0; i < entries.length; i++) { let entry = entries[i]; let id = entry.target.getAttribute("id"); if (!id) { id = entry.target.parentNode.getAttribute("id"); } let newLink = document.querySelector(`[href="#${id}"]`); if (entry.intersectionRatio >= 0.5 && entry.isIntersecting) {
newLink.classList.add("visible");
} else {
newLink.classList.remove("visible");
}
highlightFirst();
}
};
function highlightFirst() {
//Liste der gerade sichtbaren Abschnitte
let firstVisibleLink = document.querySelector(".visible");
let links = document.querySelectorAll(".active");
if (firstVisibleLink) {
links.forEach(link => {
link.classList.remove("active");
});
firstVisibleLink.classList.add("active");
}
}
let observer3 = new IntersectionObserver(callback3, {
threshold: 0.5
});
let items3 = document.querySelectorAll(".section_heading");
items3.forEach(item => {
observer3.observe(item);
});
Das erweiterte Beispiel findet ihr hier.
Bild-Overlays
In der Bildergalerie werden nun Bildbeschreibungen als Div-Tags ergänzt. Wir nutzen die CSS-Eigenschaft position: absolute, um jede Beschreibung direkt über dem zugehörigen Bild einzublenden. Die Beschreibungen sind zunächst unsichtbar (opacity: 0). Per JavaScript werden Event-Handler definiert, die beim Anklicken eines Bildes die Beschreibung sichtbar (opacity: 1) beziehungsweise wieder unsichtbar machen. Mit der CSS-Einstellung transition: 0.5s wird ein weicher Übergang beim Ein- und Ausblenden erreicht.
Der erweiterte CSS-Code:
.box {
position: relative;
}
.box div {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
opacity: 0;
text-align: center;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
color: white;
transition: 0.5s;
}
Der erweiterte JavaScript-Code:
let active_box;
window.onload = function() {
let boxes = document.querySelectorAll(".box div");
boxes.forEach(box => {
box.onclick = function() {
box.style.opacity = 1;
if (active_box) {
active_box.style.opacity = 0;
}
if (active_box != box) {
active_box = box;
} else {
active_box = null;
}
};
});
};
Das vollständige erweiterte Code-Beispiel wird im nächsten Abschnitt gezeigt.
Preloading-Screen
Bevor nicht alle Bilder und Elemente der Seite vollständig geladen sind, können ihre besonderen Gestaltungseffekte und Animationen noch keine Wirkung entfalten. Daher fügen wir einen Preloading-Screen mit einer kleinen GIF-Animation direkt über dem eigentlichen Seiteninhalt ein (ID „loading“). Im JavaScript-Code nutzen wir das Ereignis window.onload, um den Preloading-Screen zu entfernen, sobald die Seite vollständig geladen wurde (display: none). Die GIF-Animation nimmt danach keine System-Ressourcen mehr in Anspruch.
Der erweiterte CSS-Code:
#loading {
background: url("https://media.giphy.com/media/N256GFy1u6M6Y/giphy.gif")
no-repeat center center;
background-color: black;
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
z-index: 9999999;
}
Der erweiterte JavaScript-Code:
window.onload = function() {
/* Preloading-Screen ausblenden:*/
document.getElementById("loading").style.display = "none";
/*Animation vom Header-Text erst nach dem Preloading-Screen:*/
document
.querySelector(".header_transformed")
.classList.add("header_animated");
...
Das erweiterte Beispiel findet ihr hier.
Fazit
Mit den Basis-Technologien CSS und JavaScript ist es möglich, mit wenig Aufwand eine effektvolle One-Page-Website zu erstellen. Zudem machen die zukünftigen Erweiterungen der JavaScript-Spezifikation (wie etwa die Intersection-Observer-API) insbesondere die Implementierung von scrollbasierten Interaktionen sehr einfach.
Finde es auf jeden Fall cool, dass ihr nicht nur eine Liste mir den Trends gemacht habt, sondern auch gleich die CSS Codeboxen eingebaut habt, gute Idee!
Werde das später mal ausprobieren auf meinem Testserver.. :D
Habe gerade erstmal checken müssen, ob der Beitrag von 2015 ist…
Vielen Dank für die Liste und vor allem den zugehörigen Code!!
Es muss nicht immer gleich ein Onepager sein, denn für viele Themen eignen sie sich nicht wirklich. Sind die Inhalte zu lang, zu komplex oder zu vielseitig, stößt man schnell an seine Grenzen. Auch wenn die Website später inhaltlich wächst, kann es schwierig werden.
Allerdings gibt es ja auch „Mischformen“ bei denen die Starseite, den Character eines Onepagers hat und es trotzdem noch weitere Unterseiten gibt. Hier wurde das so umgesetzt: https://webographen.de/
Danke für die Infos mit Code. So kann man doch recht einfach One-Pager aufwerten oder erstellen
Schön wären noch Infos zum Einsatzzweck von Onepager.
Ich gehe ja davon aus, dass One-Page-Seiten sich in erster Linie anbieten, wenn man ein genau definiertes Thema abbilden möchte.
Ja, das stimmt. Onepager eignen sich, um dem Besucher bzw. potenziellen Kunden einen schnellen Überblick über ein bestimmtes Thema, Produkt oder eine Person zu geben. Ein Beispiel ist unsere Hochschule. Auf hszg.de findet jeder die komplexe Hochschulwebseite mit allen Informationen für Schüler, Studierende und Mitarbeiter. Auf studier-hier.de gibt es dagegen die Einstiegsseite (oder „Landingpage“) für Studieninteressierte, die nur die Aufgabe hat, Interesse zu wecken und neugierig zu machen.
Hallo Anna,
vielen Dank für das interessante Parallaxe-Beispiel. Ich habe mir den html und CSS Code einmal heruntergeladen und ausprobiert. Leider funktioniert er nicht wie erwartet… Die Luftballons bewegen sich in der gleichen Geschwindigkeit wie der Text.
Auf der Beispielsseite funktioniert er nur mit Chrome, nicht aber mit Firefox oder Safari.
Wo könnte der Fehler liegen?
Vielen Dank für Deine Antwort!
Peter
Hallo Peter,
sorry für die späte Antwort! Das Problem mit Firefox habe ich nochmal recherchiert:
https://stackoverflow.com/questions/23080112/css-perspective-not-working-in-firefox
Unter dem Link wird die Ursache für das Problem genannt und die letzte Antwort liefert eine Lösung, die für mich im Firefox funktioniert hat. Ich habe die CodePens gleich nochmal korrigiert:
https://codepen.io/blaustern_fotografie/pen/pooLewy
Viele Grüße,
Anna
Hallo Anna,
vielen Dank für deine Rückmeldung und Anpassung des Codes. Ich wünsche Dir alles Gute für das neue Jahr!
Lg, Peter