Animierte Link-Liste mit CSS erstellen

CSS HTML

In diesem Tutorial erstellen wir eine einfache animierte Linkliste anhand einer Schritt-für-Schritt-Anleitung. Die Linkliste ist für Artikel die aus mehreren Teilseiten bestehen geiegnet und kann dabe als Navigationselement eingesetzt werden. Diese Liste wird mit HTML und CSS umgesetzt und wird mit CSS Transitions animiert.

Das Endergebnis sieht so aus:

Demo auf Codepen

1) Das Markup definieren

Zuerst müssen wir uns überlegen wie das HTML-Markup der Linkliste aussehen soll. Dafür gibt es verschiedene Möglichkeiten. Denkbar wäre eine Ordered List (<ol>) in der die einzelnen Links innerhalb von (<li>)-Elementen hängen. Auch eine verschachtelte Struktur von Div-Containern (<div>) wäre machbar. Beide Elemente haben jedoch keinen semantischen Mehrwert für unsere Linkliste. Wir entscheiden uns für das Element <nav> da unsere Liste als Navigations-Objekt agieren soll. Im Gegensatz zu normalen Textlinks des Artikelinhalts haben die Links der Linklsite einen logischen Zusammenhang. Sie sind Teile einer Artikelserie. Daher sind sie auf der Website in einem eigenem Element hervorgehoben. Innerhalb der Nav-Elementes definierien wir die HTML-Links (<a>). Das <nav>-Element bekommt die CSS-Klasse .nav-list die wir dann im CSS stylen können.

Das finale Markup wie oben abgebildet sieht dann so aus:

<nav class="nav-list">
    <a class="nav-list-link" href="#link-article-part-01">
        <span class="icon-caret"></span>
        <span class="title"><span>Teil 1: Welches Shampoo hilft gegen Nikoläuse?</span></span>
    </a>
    <a class="nav-list-link is-highlighted" href="#link-article-part-02">
        <span class="icon-caret"></span>
        <span class="title"><span>Teil 2: Wieviel blaue Flecken muss man sich prügeln lassen um als Schlumpf durchzugehen?</span></span>
    </a>
    <a class="nav-list-link" href="#link-article-part-03">
        <span class="icon-caret"></span>
        <span class="title"><span>Teil 3: Fressen Kartoffelkäfer am Liebsten normale Kartoffeln oder lieber Süßkartoffeln?</span></span>
    </a>
    <a class="nav-list-link" href="#link-article-part-04">
        <span class="icon-caret"></span>
        <span class="title"><span>Teil 4: Was muss ein Kater fressen um Muskelkater zu werden?</span></span>
    </a>
    <a class="nav-list-link" href="#link-article-part-05">
        <span class="icon-caret"></span>
        <span class="title"><span>Teil 5: Warum gibt es angeblich keine dummen Fragen, wenn es doch offenkundig dumme Fragen gibt?</span></span>
    </a>
</nav>

Die einzelnen Links enhalten das Icon-Element .icon-caret und einen span mit der Klasse .title. Darin ist noch ein span enthalten. Diesen benötigen wir als Inline-Element, damit die Animation korrekt funktioniert. Dazu später mehr.

2) Das CSS definieren

Im zweiten Schritt erstellen wir die CSS-Eigenschaften der Linkliste und definieren auch das CSS für die Links. Wir nutzen dafür CSS Custom Properties um die Farbwerte zu definieren. Die Links werden per Flexbox (display: flex;) definiert, damit der Pfeil und das Text-Element nebeneinander erscheinen. Außerdem definieren wir eine CSS Transition für den Margin


:root {
    --linkColor: #00a175;
    --borderColor: #c0c0c0;
}
.nav-list {
    margin: 20px auto;
}
.nav-list-link {
    width: auto;
    display: flex;
    align-items: flex-start;
    justify-content: flex-start;
    margin: 6px 0;
    padding: 6px 0;
    color: var(--linkColor);
    text-decoration: none;
}

3) Ein Pfeil-Icon hinzufügen

Für unsere Linkliste wollen wir ein grafisches Element einfügen. Ein Icon dient der visuellen Unterstützung des Links und hebt die Linkliste von anderen Link-Elementen der Seite ab. Wir könnten es uns einfach machen und zum Beispiel irgend ein SVG-Icon aus dem Internet nehmen oder ein Icon aus von einer Icon-Bibliothek benutzen wie zum Beispiel "Font-Awesome" oder ähnliches. Unsere Linkliste soll jedoch unabhängig von externen Abhängigkeiten bleiben. Wir benutzen ein einfaches Caret-Symbol für den Pfeil. Das ist visuell selbsterklärend und ansprechend und das reicht völlig aus. Wir erstellen das Icon per CSS selbst - das geht recht einfach und ist bei Bedarf super schnell anzupassen.

Zuerst definieren wir das HTML als Inline-Element (span) mit der entsprechenden CSS-Klasse .icon-caret

<span class="icon-caret"></span>

Im CSS erstellen wir die Eigenschaften der CSS-Klasse. Die per CSS-Pseudo-Elemente :before und :after positioniert werden.

.icon-caret {
    margin-right: 15px;
    width: 24px;
    height: 24px;
    min-width: 24px;
    line-height: 24px;
    color: var(--borderColor);
    border-radius: 50%;
    border: 1px solid var(--borderColor);
    transition: all var(--transitionTime) ease-in-out;
}
.icon-caret:before,
.icon-caret:after {
    content: '';
    width: 9px;
    height: 0;
    display: block;
    margin-left: 7px;
    margin-top: 8px;
    border-top: 1px solid var(--borderColor);
    transform: rotate(45deg);
    transform-origin: 50% 50%;
}
.icon-caret:after {
    margin-top: 5px;
    transform: rotate(-45deg);
}

4) Einfache Animationen hinzufügen (CSS Transitions)

Um die Linkliste ansprechender zu machen wollen wir die Linkliste animieren. Dafür nutzen wir CSS Transitions und definieren eine CSS Custom Property --transitionTime: 150ms; für die Animationszeit.


:root {
    --transitionTime: 150ms;
}
.nav-list-link {
    transition: margin var(--transitionTime) ease-in-out;
}

4.1) Animation des Pfeil-Icons

Die Effekte sollen per Mouseover sichtbar sein. In CSS kann der Mouseover-Zustand eines Elements via :hover definiert werden. Zuerst für das Icon:

.nav-list-link:hover .icon-caret {
    margin-left: 3px;
    color: var(--linkColor);
    border-color: var(--linkColor);
}

Der Besucher soll sich auf den Link-Inhalt konzentrieren und nicht auf die Animation. Und mit CSS Transitions kann heute im Internet eh keiner mehr angeben.

Wichtig ist das die beiden das gleiche Transition-Timing haben, damit die Animation flüssig wirkt. Animation hat sehr viel mit visueller Wahrnehmung des Menschen zu tun und sollte daher möglichst wenig dezent erscheinen.

Das Problem: Die CSS-Eigenschaft text-decoration: underline; lässt sich nicht mit CSS Transitions animieren da es keinen Zahlenwert enthält und daher nicht interpolierbar ist. Die Lösung: Ein background-image mit animierter background-size.

Animation der Background-Size für den Linktext:

.nav-list-link .title span {
    display: inline;
    background-image: linear-gradient(var(--linkColor), var(--linkColor));
    background-size: 0 2px;
    background-position: 0 100%;
    background-repeat: no-repeat;
    transition: all var(--transitionTime) ease-in-out;
}
.nav-list-link:hover .title span {
    background-size: 100% 2px;
}

Block-Element vs. Inline-element

Der Ansatz mit der animierten background-size funktioniert nur für Inline-Elemente innerhalb des Links die dem normalen Textfluss entsprechen. Deshalb benötigen wir ein span-Element innerhalb von .title. Andernfalls würde die animierte background-size nur einzeilig funktionieren, was schlecht für das responsive Verhalten der Links wäre.

Linkliste mit Zeilenumbrüchen und mehrzeilig animierten background-sizes:

5) Einen Active-State per CSS-Klasse hinzufügen

In der Linkliste soll der Link hervorgehoben werden auf dem der Besucher gerade ist. Dafür benötigen wir einen Active-State. Wir definieren eine CSS-Klasse .is-highlighted der die gleichen CSS-Eigenschaften bekommt wie der Mouseover-Effekt mit :hover.

Active-State für das Pfeil-Icon:

.nav-list-link:hover .icon-caret,
.nav-list-link.is-highlighted .icon-caret {
    margin-left: 3px;
    color: var(--linkColor);
    border-color: var(--linkColor);
}

Active-State für den Link:

.nav-list-link:hover .title span,
.nav-list-link.is-highlighted .title span {
    background-size: 100% 2px;
}

6) Der gesamte Quellcode

Das Markup der Linkliste:

<nav class="nav-list">
    <a class="nav-list-link" href="#link-article-part-01">
        <span class="icon-caret"></span>
        <span class="title"><span>Teil 1: Welches Shampoo hilft gegen Nikoläuse?</span></span>
    </a>
    <a class="nav-list-link is-highlighted" href="#link-article-part-02">
        <span class="icon-caret"></span>
        <span class="title"><span>Teil 2: Wieviel blaue Flecken muss man sich prügeln lassen um als Schlumpf durchzugehen?</span></span>
    </a>
    <a class="nav-list-link" href="#link-article-part-03">
        <span class="icon-caret"></span>
        <span class="title"><span>Teil 3: Fressen Kartoffelkäfer am Liebsten normale Kartoffeln oder lieber Süßkartoffeln?</span></span>
    </a>
    <a class="nav-list-link" href="#link-article-part-04">
        <span class="icon-caret"></span>
        <span class="title"><span>Teil 4: Was muss ein Kater fressen um Muskelkater zu werden?</span></span>
    </a>
    <a class="nav-list-link" href="#link-article-part-05">
        <span class="icon-caret"></span>
        <span class="title"><span>Teil 5: Warum gibt es angeblich keine dummen Fragen, wenn es doch offenkundig dumme Fragen gibt?</span></span>
    </a>
</nav>

Das komplette CSS der Linkliste:


:root {
    --linkColor: #00a175;
    --borderColor: #c0c0c0;
    --transitionTime: 150ms;
}
.nav-list {
    margin: 20px auto;
}
.nav-list-link {
    width: auto;
    display: flex;
    align-items: flex-start;
    justify-content: flex-start;
    margin: 6px 0;
    padding: 6px 0;
    color: var(--linkColor);
    transition: margin var(--transitionTime) ease-in-out;
    text-decoration: none;
}
.nav-list-link .title {
    transition: all var(--transitionTime) ease-in-out;
}
.nav-list-link .title span {
    display: inline;
    background-image: linear-gradient(var(--linkColor), var(--linkColor));
    background-size: 0 2px;
    background-position: 0 100%;
    background-repeat: no-repeat;
    transition: all var(--transitionTime) ease-in-out;
}
.nav-list-link:hover {
    text-decoration: none;
}
.nav-list-link:hover .title span,
.nav-list-link.is-highlighted .title span {
    background-size: 100% 2px;
}
.nav-list-link:hover .icon-caret,
.nav-list-link.is-highlighted .icon-caret {
    margin-left: 3px;
    color: var(--linkColor);
    border-color: var(--linkColor);
}
.nav-list-link:hover .icon-caret:before,
.nav-list-link:hover .icon-caret:after,
.nav-list-link.is-highlighted .icon-caret:before,
.nav-list-link.is-highlighted .icon-caret:after {
    border-top: 1px solid var(--linkColor);
}
.nav-list-link:hover .title,
.nav-list-link.is-highlighted .title {
    margin-left: -3px;
}

.icon-caret {
    margin-right: 15px;
    width: 24px;
    height: 24px;
    min-width: 24px;
    line-height: 24px;
    color: var(--borderColor);
    border-radius: 50%;
    border: 1px solid var(--borderColor);
    transition: all var(--transitionTime) ease-in-out;
}
.icon-caret:before,
.icon-caret:after {
    content: '';
    width: 9px;
    height: 0;
    display: block;
    margin-left: 7px;
    margin-top: 8px;
    border-top: 1px solid var(--borderColor);
    transform: rotate(45deg);
    transform-origin: 50% 50%;
    transition: all var(--transitionTime) ease-in-out;
}
.icon-caret:after {
    margin-top: 5px;
    transform: rotate(-45deg);
}


Die animierte Liste lässt sich praktischerweise auch am Ende des Artikelinhalts darstellen. So können Besucher nach dem Lesen des Artikels bequem zum nächsten Teil navigieren.



Artikel teilen