Zum Inhalt springen

Einleitung

Einige organische Suchergebnisse in Google besitzen zusätzliche Links unterhalb der Meta-Beschreibung. Andere Ergebnisse können vor der Meta-Beschreibung einen Link beinhalten, der mit "Weiter zu <Textabschnitt> —" betitelt ist. Diese Art von Links wird vor allem dann von Google ergänzt, wenn die Suchanfrage sehr spezifisch ist.

Wenn der Nutzer einen dieser Anker-Links verwendet, kommt er direkt zu dem entsprechenden Textabschnitt auf der Zielseite. Es sind URL-Fragmente (#absatz), die dafür verwendet werden.

Diese Anker-Links lohnen sich sowohl für Nutzer als auch Webseitenbetreiber:

  • Google wird die Zwischenüberschriften eurer Webseite als Anker-Texte verwenden. Dadurch kann der Nutzer die Relevanz eurer Seite schon im Suchergebnis besser einschätzen. Dies führt schließlich zu einer höheren Verweildauer auf eurer Seite. Zudem ist die Wahrscheinlichkeit geringer, dass der Nutzer nach dem Besuch eurer Seite zu den Suchergebnissen zurückkehrt (Return-to-SERP-Rate).
  • Dazu kommen die Usability-Vorteile auf der Website selbst: die Inhalte sind gut strukturiert und können durch ein Inhaltsverzeichnis (dazu komme ich gleich) angesteuert werden.
  • Nicht zuletzt ist eure Seite durch die zusätzlichen Links natürlich in der Suchergebnisliste optisch hervorgehoben.
  • Wie erwähnt, führen die Anker-Links den Nutzer direkt zum gewünschten Textabschnitt.

Dieses Feature bietet Google bereits seit 2009. Ich erläutere hier die generellen Kriterien und zeige euch dann, wie ihr dies sinnvoll in TYPO3 umsetzen könnt.

Voraussetzungen

Wie aus der ursprünglichen Meldung von Google hervorgeht, lohnt sich die Einrichtung der Anker besonders für lange, themen­übergreifende Webseiten. Deren Inhalte müssen gut strukturiert und durch Zwischenüberschriften in logische Abschnitte unterteilt sein.
Die Zwischenüberschriften müssen den jeweiligen Inhalt beschreiben – "Abschnitt B" reicht also nicht aus.

Darüber hinaus müsst ihr die folgenden technischen Vorgaben erfüllen, um Anker-Links in Google-Suchergebnissen zu erhalten:

  1. Anker zuweisen: Die URL-Fragmente müssen als id-Attribut direkt den Überschriften zugewiesen sein.
  2. Inhaltsverzeichnis bereitstellen: Die aktuelle Seite muss Links mit Sprungmarken zu den Überschriften enthalten. Gerade bei längeren Artikeln ist so ein Inhalts­verzeichnis generell anwender­freundlich.
  3. Auf URL-Pfade verzichten: die Verweise im Inhalts­verzeichnis dürfen nur die Sprungmarken selbst enthalten.

1. Anker zuweisen

Eine korrekt ausgezeichnete Überschrift kann z. B. so aussehen:

<h2 id="voraussetzungen">Voraussetzungen</h2>
<!-- oder auch: -->
<h2 id="ce123">Voraussetzungen</h2>

Ob der Anker – wie im ersten Beispiel – menschenlesbar ist, spielt für die Ausgabe im Google-Suchergebnis keine Rolle.

In TYPO3 besitzt jedes Inhaltselement einen Wrapper mit id="c123". Dieser Anker im umgebenden <div> reicht aber nicht aus, um Sprungmarken im Suchergebnis zu erhalten.

Nachtrag 07/2023: Google hat seine Hinweise zum Anker-Markup zwischenzeitlich überarbeitet. Empfohlen wird inzwischen die Verwendung von <section>-Elementen:

<section id="voraussetzungen">
  <h2>Voraussetzungen</h2>
  <!-- Inhalt des Textabschnitts -->
</section>

Um semantisch korrekt zu sein, müsste die Section den gesamten (zur Überschrift passenden) Inhalt umfassen. Da dieser sich in TYPO3 durchaus auf mehrere Inhaltselemente verteilen kann, darf man die Section nicht fest im Fluid-Template jedes Inhaltselements definieren. Theoretisch könnte man die umfassende Section z. B. als Container-Element bereitstellen – das würde die Inhaltspflege aber unnötig verkomplizieren.
Laut Google wird die Ergänzung des Ankers direkt an der Überschrift weiterhin akzeptiert. Und genau dieses Vorgehen kann ich euch uneingeschränkt empfehlen.

2. Inhaltsverzeichnis bereitstellen

Ein Inhaltsverzeichnis könnte zum Beispiel aussehen wie in diesem Artikel (etwas nach oben scrollen). Position und Gestaltung sind Google dabei egal. Es kann am Anfang, Mitte oder Ende der Seite bzw. des Quelltextes stehen. Ihr könntet es immer sichtbar mitscrollen lassen oder auch ausklappbar gestalten. Haltet es einfach benutzer­freundlich.

Für Google ist am wichtigsten, dass ein Inhaltsverzeichnis mit Sprungmarken zu den Textabschnitten (sprich: Zwischenüberschriften) der aktuellen Seite existiert.

3. Auf URL-Pfade verzichten

Das Inhaltsverzeichnis darf zur Verlinkung ausschließlich die URL-Fragmente als Sprungmarken verwenden! Relative oder absolute Pfadangaben stören zwar bei der Navigation nicht. Für Google sind sie in diesem Fall aber ein Ausschlusskriterium.

<!-- richtig: -->
<a href="#voraussetzungen">Voraussetzungen</a>
<a href="#ce123">Voraussetzungen</a>

<!-- falsch: -->
<a href="/news/artikel/#voraussetzungen">Voraussetzungen</a>
<a href="https://www.domain.de/news/artikel/#voraussetzungen">Voraussetzungen</a>

Gut zu wissen

  • Das letzte Wort hat wie immer Google. Ob Sprungmarken im Suchergebnis angezeigt werden, hängt vor allem von der aktuellen Suchanfrage ab.
  • Bei der Verwendung von Anker-Links wird kein PageRank weitergegeben. Ihr verteilt euren PageRank also nicht auf die einzelnen Sprungmarken.

Sprungmarken in TYPO3

Um die oben aufgeführten Vorgaben in TYPO3 zu erfüllen, müssen wir ein paar Anpassungen in den Fluid-Templates der Inhaltselemente (fluid_styled_content) vornehmen. Für das Inhaltsverzeichnis erstellen wir gleich ein neues TYPO3-Inhaltselement.

Ich habe diese Arbeiten für euch in einer kleinen Extension zusammengefasst:

SEO-Inhaltsverzeichnis auf GitHub

Überschriften der TYPO3-Inhaltselemente anpassen

Partials/Header/All.html

Hier müssen wir zusätzlich die UID an das Partial Header.html übergeben.

<f:if condition="{data.header_layout} != 100">
    <f:if condition="{data.header} || {data.subheader} || {data.date}">
        <header>
            <f:render partial="Header/Header" arguments="{
                header: data.header,
                layout: data.header_layout,
                positionClass: '{f:if(condition: data.header_position, then: \'ce-headline-{data.header_position}\')}',
                link: data.header_link,
                uid: data.uid,
                default: settings.defaultHeaderType}" />
        </header>
    </f:if>
</f:if>

Partials/Header/Header.html

Jede Überschrift erhält ein id-Attribut mit der UID des Inhaltselement. Da der Präfix "c" bereits im Wrapper jedes Inhaltselements verwendet wird, weichen wir auf "ce" aus.

Im f:defaultCase müssen wir die Variable uid erneut übergeben. Falls ihr das versäumt, fehlt euch dieser Wert bei Überschriften mit dem Layout "Standard".

<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">

<f:if condition="{header}">
    <f:switch expression="{layout}">
        <f:case value="1">
            <h1 id="ce{uid}" class="{positionClass}">
                <f:link.typolink parameter="{link}">{header}</f:link.typolink>
            </h1>
        </f:case>
        <f:case value="2">
            <h2 id="ce{uid}" class="{positionClass}">
                <f:link.typolink parameter="{link}">{header}</f:link.typolink>
            </h2>
        </f:case>
        <f:case value="3">
            <h3 id="ce{uid}" class="{positionClass}">
                <f:link.typolink parameter="{link}">{header}</f:link.typolink>
            </h3>
        </f:case>
        <f:case value="4">
            <h4 id="ce{uid}" class="{positionClass}">
                <f:link.typolink parameter="{link}">{header}</f:link.typolink>
            </h4>
        </f:case>
        <f:case value="5">
            <h5 id="ce{uid}" class="{positionClass}">
                <f:link.typolink parameter="{link}">{header}</f:link.typolink>
            </h5>
        </f:case>
        <f:case value="6">
            <h6 id="ce{uid}" class="{positionClass}">
                <f:link.typolink parameter="{link}">{header}</f:link.typolink>
            </h6>
        </f:case>
        <f:case value="100">
            <f:comment> -- do not show header --</f:comment>
        </f:case>
        <f:defaultCase>
            <f:if condition="{default}">
                <f:render partial="Header/Header" arguments="{
                    header: header,
                    layout: default,
                    positionClass: positionClass,
                    uid: uid,
                    link: link}"/>
            </f:if>
        </f:defaultCase>
    </f:switch>
</f:if>
</html>

Inhaltsverzeichnis in TYPO3 einrichten

Der TYPO3-Kern bietet bereits ein Menü vom Typ "Section Index", mit dem sich Inhaltselemente auflisten lassen. Es ist aber aus drei Gründen nicht empfehlenswert, den Section Index dafür zu verwenden:

  1. Er verlinkt auf den Wrapper des Inhaltselements, z. B. "c123".
  2. Er listet auch Inhaltselemente mit versteckten Überschriften auf. Bei versteckten Überschriften ließe sich logischerweise kein id-Attribut setzen.
  3. Bei der Verlinkung werden immer absolute URLs gesetzt, da man auch die Inhalte von mehr als eine Unterseite auflisten kann.

All dies ließe sich anpassen, würde aber die ursprüngliche Funktionsweise dieses Menüs zu stark verändern.

Stattdessen nehmen wir Section Index als Grundlage für ein neues Menü-Inhaltselement, das genau auf die Anforderungen zugeschnitten wird.

Wie man eigene Inhaltselemente in TYPO3 erstellt, wird in der offiziellen Dokumentation gut beschrieben.

Im Folgenden zeige ich nur die Teile, die für das Frontend relevant sind. Das benötigte TCA, die Registrierung etc. könnt ihr natürlich in der fertigen Extension einsehen.

TypoScript-Setup

Dies ist eine reduzierte Kopie des Section Index, bei der immer nur die aktuelle Seite verwendet wird (pidInList.data = page:uid). Daher kann im neuen Inhaltselement auch das Auswahlfeld für Seiten komplett entfallen.

In der where-Klausel prüfen wir zusätzlich, ob es einen Wert im Header-Feld gibt und ob diese nicht versteckt ist. Nur unter diesen Voraussetzungen können wir eine Überschrift mit id-Attribut rendern und verlinken.
Da wir weiterhin den Status von sectionIndex abfragen, kann der Redakteur einzelne Inhaltselemente wie gehabt manuell von der Auflistung ausschließen.

tt_content.tx_seotableofcontents_menu_section_seo =< lib.contentElement
tt_content.tx_seotableofcontents_menu_section_seo {
    templateName = MenuSectionSeo
    templateRootPaths {
        1 = EXT:seo_tableofcontents/Resources/Private/Templates/
        10 = {$styles.templates.templateRootPath}
    }
    dataProcessing {
        10 = TYPO3\CMS\Frontend\DataProcessing\DatabaseQueryProcessor
        10 {
            table = tt_content
            pidInList.data = page:uid
            as = content
            where (
                sectionIndex = 1
                AND header != ""
                AND header_layout != 100
            )
            orderBy = sorting
        }
    }
}

Als Link setzen wir ausschließlich das URL-Fragment, identisch zum neuen id-Attribut in Header.html.

<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">

<f:layout name="Default" />
<f:section name="Main">

    <f:if condition="{content}">
        <ul>
            <f:for each="{content}" as="element">
                <li>
                    <a href="#ce{element.data.uid}">
                        {element.data.header}
                    </a>
                </li>
            </f:for>
        </ul>
    </f:if>

</f:section>
</html>

Ergänzung: mit sprechenden URL-Fragmenten

Im April habe ich eine Extension (EXT:content_slug) veröffentlicht, die euch menschenlesbare Sprungmarken in TYPO3 liefert. Diese Sprungmarken könnt ihr selbstverständlich auch im neuen SEO-Inhaltsverzeichnis verwenden.

Die notwendigen Anpassungen in den Fluid-Templates sind hier etwas komplexer. Da die URL-Fragmente vom Redakteur manuell pflegbar sind, müssen wir zusätzlich auf deren Vorhandensein prüfen. Und das logischerweise sowohl bei den Überschriften als auch im Inhaltsverzeichnis.

In EXT:seo_tableofcontents sind bereits alternative Fluid-Templates enthalten, die ihr in Kombination mit EXT:content_slug verwenden könnt. Ihr könnt sie bei Bedarf per TypoScript einbinden (und auf üblichem Wege individualisieren).

Das alternative Header-Template ist so angelegt, dass es voll kompatibel mit den normalen Menüs vom Typ "Section Index" bleibt. Jedes Inhaltselement lässt sich mit diesen Menüs sowie dem neuen SEO-Inhaltsverzeichnis korrekt auflisten:

  • Sofern vorhanden, wird von allen Menüs das lesbare URL-Fragment verwendet.
  • Fallback 1: Der "Section Index" verlinkt alternativ den Anker "c123" im div-Wrapper des Inhaltselements. Diese Verlinkung ist auch das normale Verhalten ohne EXT:content_slug.
  • Fallback 2: Für das SEO-Inhaltsverzeichnis wird in der Überschrift der Anker "ce123" verwendet, falls kein individuelles Fragment im Inhaltselement gesetzt wurde.

Die Aufführung dieser Anpassungen spare ich mir an dieser Stelle. Die Templates in EXT:seo_tableofcontents enthalten aber erläuternde Kommentare.

Fazit

Mit einer sauber strukturierten Seite, sinnvollen Überschriften und einem hilfreichen Inhaltsverzeichnis erleichtern wir das Leben unserer Website-Besucher – er kann gesuchte Inhalte schneller finden und erfassen. Google belohnt unsere Leistung mit der Möglichkeit, Sprungmarken in Suchergebnissen zu erhalten.