Mit Textfragmenten können Sie ein Text-Snippet im URL-Fragment angeben. Wenn Sie eine URL mit einem solchen Textfragment aufrufen, kann der Browser das Element hervorheben und/oder auf den Nutzer aufmerksam machen.
Fragmentbezeichner
Chrome 80 wurde veröffentlicht. Es enthielt einige mit Spannung erwartete Features wie ECMAScript-Module in Web Workers, Nullish-Koalescing, optionale Verkettungen und mehr. Der Release wurde wie gewohnt in einem Blogpost im Chromium-Blog angekündigt. Im Screenshot unten sehen Sie einen Auszug aus dem Blogpost.
![](https://web.dev/static/articles/text-fragments/image/egsW6tkKWYI8IHE6JyMZ.png?authuser=6&hl=de)
id
-Attribut.Sie fragen sich wahrscheinlich, was die roten Kästchen bedeuten. Sie sind das Ergebnis der Ausführung des folgenden Snippets in den Entwicklertools. Es werden alle Elemente hervorgehoben, die ein id
-Attribut haben.
document.querySelectorAll('[id]').forEach((el) => {
el.style.border = 'solid 2px red';
});
Dank der Fragment-ID, die ich dann im Hash der Seiten-URL verwende, kann ich einen Deeplink zu jedem mit einem roten Kästchen hervorgehobenen Element platzieren. Wenn ich davor einen Deeplink zum Feld Gib uns Feedback in unseren Produktforen einfügen möchte, könnte ich die URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1
manuell erstellen.
Wie Sie im Bereich „Elemente“ der Entwicklertools sehen können, hat das betreffende Element das Attribut id
mit dem Wert HTML1
.
![](https://web.dev/static/articles/text-fragments/image/whVXhhrYwA55S3i4J3l5.png?authuser=6&hl=de)
id
eines Elements anzeigen.Wenn ich diese URL mit dem URL()
-Konstruktor von JavaScript parsen, werden die verschiedenen Komponenten angezeigt.
Beachten Sie das Attribut hash
mit dem Wert #HTML1
.
new URL('https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1');
/* Creates a new `URL` object
URL {
hash: "#HTML1"
host: "blog.chromium.org"
hostname: "blog.chromium.org"
href: "https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1"
origin: "https://blog.chromium.org"
password: ""
pathname: "/2019/12/chrome-80-content-indexing-es-modules.html"
port: ""
protocol: "https:"
search: ""
searchParams: URLSearchParams {}
username: ""
}
*/
Die Tatsache, dass ich die Entwicklertools öffnen musste, um den id
eines Elements zu finden, sagt Bände über die Wahrscheinlichkeit, dass dieser bestimmte Abschnitt der Seite vom Autor des Blogposts verlinkt werden sollte.
Was kann ich tun, wenn ich etwas ohne id
verlinken möchte? Angenommen, ich möchte einen Link zur Überschrift ECMAScript-Module in Web Workers einfügen. Wie Sie im Screenshot unten sehen können, hat die betreffende <h1>
kein id
-Attribut. Daher kann ich keine Links zu dieser Überschrift erstellen. Das ist das Problem,
das Textfragmente lösen.
![](https://web.dev/static/articles/text-fragments/image/1g4rTS1q5LKHEHnDoF9o.png?authuser=6&hl=de)
id
.Textfragmente
Der Vorschlag Textfragmente unterstützt die Angabe eines Text-Snippets im URL-Hash. Wenn zu einer URL mit einem solchen Textfragment navigiert wird, kann der User-Agent es hervorheben und/oder auf den Nutzer aufmerksam machen.
Browserkompatibilität
Aus Sicherheitsgründen müssen Links in einem noopener
-Kontext für die Funktion geöffnet werden.
Deshalb musst du rel="noopener"
in dein <a>
-Anker-Markup einfügen oder noopener
in die Window.open()
-Liste der Fensterfunktionsfunktionen aufnehmen.
start
In ihrer einfachsten Form lautet die Syntax von Textfragmenten: Das Hash-Symbol #
gefolgt von :~:text=
und schließlich start
, das für den prozentcodierten Text steht, auf den ich verlinken möchte.
#:~:text=start
Wenn Sie zum Beispiel einen Link zur Überschrift ECMAScript-Module in Web Workers in einem Blogpost zu Funktionen in Chrome 80 einfügen möchten, lautet die URL in diesem Fall:
Das Textfragment wird auf diese Weise hervorgehoben. Wenn Sie in einem Browser wie Chrome, der dies unterstützt, auf den Link klicken, wird das Textfragment markiert und es wird in den sichtbaren Bereich gescrollt:
![](https://web.dev/static/articles/text-fragments/image/D3jwPrJlvN3FmJo3pADt.png?authuser=6&hl=de)
start
und end
Wie gehe ich vor, wenn ich zum gesamten Abschnitt mit dem Titel ECMAScript-Module in Web Workers und nicht nur zu dessen Überschrift verlinken möchte? Eine Prozentcodierung des gesamten Textes des Abschnitts würde die resultierende URL unpraktisch lang machen.
Zum Glück gibt es eine bessere Lösung. Statt des gesamten Textes kann ich den gewünschten Text mithilfe der start,end
-Syntax umrahmen. Daher gebe ich am Anfang des gewünschten Textes einige prozentcodierte Wörter und am Ende des gewünschten Textes einige prozentcodierte Wörter an, die durch ein Komma (,
) getrennt sind.
Das sieht so aus:
Für start
habe ich ECMAScript%20Modules%20in%20Web%20Workers
, gefolgt von einem Komma ,
, gefolgt von ES%20Modules%20in%20Web%20Workers.
als end
. Wenn Sie auf einen Browser wie Chrome klicken, der dies unterstützt, wird der gesamte Abschnitt markiert und in den sichtbaren Bereich gescrollt:
![](https://web.dev/static/articles/text-fragments/image/2yTYmKnjHTnqXkcmHF1F.png?authuser=6&hl=de)
Jetzt fragen Sie sich vielleicht, was ich für start
und end
ausgewählt habe. Die etwas kürzere URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=ECMAScript%20Modules,Web%20Workers.
mit nur zwei Wörtern auf jeder Seite hätte auch funktioniert. Vergleichen Sie start
und end
mit den vorherigen Werten.
Wenn ich einen Schritt weiter gehe und jetzt nur ein Wort für start
und end
verwende, siehst du, dass es ein Problem gibt. Die URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=ECMAScript,Workers.
ist jetzt noch kürzer, das hervorgehobene Textfragment ist jedoch nicht mehr das ursprünglich gewünschte. Das Hervorheben endet an der ersten Stelle des Wortes Workers.
. Das ist richtig, aber nicht das, was ich hervorheben wollte. Das Problem besteht darin, dass der gewünschte Abschnitt nicht durch die aktuellen Ein-Wort-Werte start
und end
eindeutig identifiziert wird:
![](https://web.dev/static/articles/text-fragments/image/GGbbtHBpsoFyubnISyZw.png?authuser=6&hl=de)
prefix-
und -suffix
Ausreichend lange Werte für start
und end
sind eine Möglichkeit, einen eindeutigen Link zu erhalten.
In einigen Situationen ist dies jedoch nicht möglich. Übrigens: Warum habe ich den Blogpost
zu Chrome 80 als Beispiel ausgewählt? Die Antwort lautet, dass in dieser Version
Textfragmente eingeführt wurden:
![Blogpost-Text: Text-URL-Fragmente. Nutzer oder Autoren können jetzt mithilfe eines in einer URL bereitgestellten Textfragments auf einen bestimmten Teil einer Seite verlinken. Wenn die Seite geladen wird, hebt der Browser den Text hervor und scrollt das Fragment in den sichtbaren Bereich. Mit der folgenden URL wird beispielsweise eine Wiki-Seite für "Cat" geladen und zu dem im Parameter "text" aufgeführten Inhalt gescrollt.](https://web.dev/static/articles/text-fragments/image/blog-post-text-text-url-67d2c112b0147.png?authuser=6&hl=de)
Beachten Sie, wie im Screenshot über das Wort „Text“ viermal angezeigt wird. Das vierte Vorkommen ist
in grüner Code-Schriftart geschrieben. Wenn ich auf dieses Wort verlinken möchte, würde ich start
auf text
setzen. Da das Wort „Text“ aus nur einem Wort besteht, darf es kein end
geben. Was nun? Die URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=text
stimmt beim ersten Vorkommen des Wortes „Text“ bereits in der Überschrift überein:
![](https://web.dev/static/articles/text-fragments/image/nXxCskUwdCxwxejPSSZW.png?authuser=6&hl=de)
Zum Glück gibt es eine Lösung. In solchen Fällen kann ich prefix-
und -suffix
angeben. Das Wort vor der grünen Codeschriftart „Text“ ist „the“ und das Wort danach „Parameter“. Keines der anderen drei Vorkommen des Wortes „Text“ hat die gleichen umgebenden Wörter. Auf Grundlage dieses Wissens kann ich die vorherige URL optimieren und prefix-
und -suffix
hinzufügen. Genau wie die anderen Parameter müssen auch sie prozentcodiert werden und können mehr als ein Wort enthalten.
https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=the-,text,-parameter
.
Damit der Parser die prefix-
und die -suffix
eindeutig identifizieren kann, müssen sie vom start
und dem optionalen end
durch einen Bindestrich -
getrennt werden.
![](https://web.dev/static/articles/text-fragments/image/J3L5BVSMmzGY6xdkabP6.png?authuser=6&hl=de)
Die vollständige Syntax
Die vollständige Syntax von Textfragmenten ist unten zu sehen. Eckige Klammern kennzeichnen einen optionalen Parameter.
Die Werte für alle Parameter müssen in Prozent codiert sein. Dies ist besonders wichtig für die Bindestriche -
, das kaufmännische Und-Zeichen &
und das Komma ,
, damit sie nicht als Teil der Syntax der Textanweisung interpretiert werden.
#:~:text=[prefix-,]start[,end][,-suffix]
prefix-
, start
, end
und -suffix
stimmen jeweils nur mit Text in einem einzelnen Element auf Blockebene überein. Vollständige start,end
-Bereiche können jedoch mehrere Blöcke umfassen. Im folgenden Beispiel stimmt :~:text=The quick,lazy dog
beispielsweise nicht überein, weil der Startstring „The Quick“ nicht in einem einzelnen, ununterbrochenen Element auf Blockebene enthalten ist:
<div>
The
<div></div>
quick brown fox
</div>
<div>jumped over the lazy dog</div>
In diesem Beispiel stimmt dies jedoch überein:
<div>The quick brown fox</div>
<div>jumped over the lazy dog</div>
Textfragment-URLs mit einer Browsererweiterung erstellen
Das manuelle Erstellen von Textfragment-URLs ist mühsam, insbesondere wenn es um die Eindeutigkeit geht. Wenn Sie möchten, finden Sie in der Spezifikation einige Tipps und die genauen Schritte zum Generieren von Textfragment-URLs. Wir stellen die Open-Source-Browsererweiterung Link to Text Fragment zur Verfügung, mit der Sie einen Link zu einem beliebigen Text erstellen können, indem Sie ihn auswählen und dann im Kontextmenü auf "Link zum ausgewählten Text kopieren" klicken. Diese Erweiterung ist für die folgenden Browser verfügbar:
- Link zu Textfragment für Google Chrome
- Link zu Textfragment für Microsoft Edge
- Link zu Textfragment für Mozilla Firefox
- Link zum Textfragment für Apple Safari
![](https://web.dev/static/articles/text-fragments/image/ASLtFCPoHvyTKrAtKAv4.png?authuser=6&hl=de)
Mehrere Textfragmente in einer URL
Beachten Sie, dass mehrere Textfragmente in einer URL erscheinen können. Die jeweiligen Textfragmente müssen durch ein kaufmännisches Und-Zeichen &
getrennt werden. Hier ist ein Beispiellink mit drei Textfragmenten: https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=Text%20URL%20Fragments&text=text,-parameter&text=:~:text=On%20islands,%20birds%20can%20contribute%20as%20much%20as%2060%25%20of%20a%20cat's%20diet
.
![](https://web.dev/static/articles/text-fragments/image/ffsq7aoSoVd9q6r5cquY.png?authuser=6&hl=de)
Element- und Textfragmente vermischen
Herkömmliche Elementfragmente können mit Textfragmenten kombiniert werden. Es ist völlig in Ordnung, beide in derselben URL zu haben, um beispielsweise eine sinnvolle Alternative bereitzustellen, falls sich der Originaltext auf der Seite ändert und das Textfragment nicht mehr übereinstimmt. Die URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1:~:text=Give%20us%20feedback%20in%20our%20Product%20Forums.
, die mit Feedback in unseren Produktforen verknüpft ist, enthält sowohl ein Elementfragment (HTML1
) als auch ein Textfragment (text=Give%20us%20feedback%20in%20our%20Product%20Forums.
):
![](https://web.dev/static/articles/text-fragments/image/JRKCM6Ihrq8sgRZRiymr.png?authuser=6&hl=de)
Fragment-Anweisung
Es gibt ein Element der Syntax, das ich noch nicht erläutert habe: die Fragmentanweisung :~:
. Mit der Spezifikation für Textfragmente wird die Fragmentanweisung eingeführt, um Kompatibilitätsprobleme mit vorhandenen URL-Elementfragmenten zu vermeiden. Die Fragment-Anweisung ist ein Teil des URL-Fragments, der durch die Codesequenz :~:
getrennt ist. Es ist für User-Agent-Anweisungen wie text=
reserviert und wird beim Laden aus der URL entfernt, sodass Autorenskripts nicht direkt mit ihr interagieren können. Anweisungen für User-Agents werden auch als Anweisungen bezeichnet. Im konkreten Fall wird text=
daher als Textanweisung bezeichnet.
Funktionserkennung
Testen Sie zum Erkennen der Unterstützung das schreibgeschützte Attribut fragmentDirective
auf document
. Die Fragmentanweisung ist ein Mechanismus für URLs, um Anweisungen anzugeben, die an den Browser und nicht an das Dokument gerichtet sind. Die direkte Interaktion mit dem Autorenskript soll vermieden werden, damit zukünftige User-Agent-Anweisungen hinzugefügt werden können, ohne befürchten funktionsgefährdende Änderungen an bestehenden Inhalten vorzunehmen. Ein Beispiel für solche zukünftigen Ergänzungen sind Übersetzungshinweise.
if ('fragmentDirective' in document) {
// Text Fragments is supported.
}
Die Funktionserkennung ist hauptsächlich für Fälle vorgesehen, in denen Links dynamisch generiert werden (z. B. von Suchmaschinen), um zu verhindern, dass Textfragmente an Browser gesendet werden, die sie nicht unterstützen.
Stile für Textfragmente erstellen
Standardmäßig werden Browser-Stiltextfragmente auf dieselbe Weise wie mark
formatiert (in der Regel Schwarz auf Gelb, die CSS-Systemfarben für mark
). Das User-Agent-Stylesheet enthält CSS, die so aussehen:
:root::target-text {
color: MarkText;
background: Mark;
}
Wie Sie sehen, wird im Browser ein Pseudoselektor ::target-text
angezeigt, mit dem Sie die angewendete Hervorhebung anpassen können. Sie können Ihre Textfragmente beispielsweise als schwarzer Text auf rotem Hintergrund gestalten. Prüfen Sie wie immer den Farbkontrast, damit der Überschreibungsstil nicht zu Problemen mit der Barrierefreiheit führt. Außerdem sollten Sie darauf achten, dass sich die Hervorhebung optisch vom Rest der Inhalte abhebt.
:root::target-text {
color: black;
background-color: red;
}
Polyfüllbarkeit
Die Funktion „Textfragmente“ kann bis zu einem gewissen Grad mit Polyfills versehen werden. Wir bieten polyfill, der intern von der Erweiterung verwendet wird, für Browser, die keine integrierte Unterstützung für Textfragmente bieten und deren Funktionalität in JavaScript implementiert ist.
Programmatische Generierung von Textfragment-Links
polyfill enthält eine Datei fragment-generation-utils.js
, die du importieren und zum Generieren von Textfragment-Links verwenden kannst. Dies wird im folgenden Codebeispiel veranschaulicht:
const { generateFragment } = await import('https://unpkg.com/text-fragments-polyfill/dist/fragment-generation-utils.js');
const result = generateFragment(window.getSelection());
if (result.status === 0) {
let url = `${location.origin}${location.pathname}${location.search}`;
const fragment = result.fragment;
const prefix = fragment.prefix ?
`${encodeURIComponent(fragment.prefix)}-,` :
'';
const suffix = fragment.suffix ?
`,-${encodeURIComponent(fragment.suffix)}` :
'';
const start = encodeURIComponent(fragment.textStart);
const end = fragment.textEnd ?
`,${encodeURIComponent(fragment.textEnd)}` :
'';
url += `#:~:text=${prefix}${start}${end}${suffix}`;
console.log(url);
}
Textfragmente zu Analysezwecken abrufen
Viele Websites verwenden das Fragment für das Routing. Daher entfernen Browser Textfragmente, damit diese Seiten nicht beschädigt werden. Es besteht eine bestätigte Notwendigkeit, Textfragment-Links zu Seiten beispielsweise zu Analysezwecken bereitzustellen. Die vorgeschlagene Lösung wurde jedoch noch nicht implementiert. Als Behelfslösung können Sie den folgenden Code verwenden, um die gewünschten Informationen zu extrahieren.
new URL(performance.getEntries().find(({ type }) => type === 'navigate').name).hash;
Sicherheit
Anweisungen zu Textfragmenten werden nur bei vollständigen Navigationen (nicht auf derselben Seite) aufgerufen, die das Ergebnis einer Nutzeraktivierung sind.
Außerdem muss die Navigation bei Navigationsvorgängen, die von einem anderen Startort als dem Ziel beginnen, in einem noopener
-Kontext erfolgen, sodass die Zielseite bekanntermaßen ausreichend isoliert ist. Anweisungen zu Textfragmenten werden nur auf den Hauptframe angewendet. Das bedeutet, dass Text in iFrames nicht durchsucht wird und die iFrame-Navigation kein Textfragment aufruft.
Datenschutz
Es ist wichtig, dass bei Implementierungen der Text Fragments-Spezifikation nicht offengelegt wird, ob ein Textfragment auf einer Seite gefunden wurde oder nicht. Während Elementfragmente vollständig vom ursprünglichen Seitenautor verwaltet werden, können Textfragmente von jedem Nutzer erstellt werden. In meinem Beispiel oben gab es keine Möglichkeit, auf die Überschrift ECMAScript-Module in Web Workers zu verweisen, da die <h1>
kein id
hatte. Aber wie konnte jeder, einschließlich mir, einfach einen Link zu einer beliebigen Stelle erstellen, indem er das Textfragment sorgfältig erstellt?
Stellen Sie sich vor, ich führe ein böses Werbenetzwerk evil-ads.example.com
. Außerdem habe ich in einem meiner Anzeigen-iFrames dynamisch einen ausgeblendeten ursprungsübergreifenden iFrame für dating.example.com
mit einer Textfragment-URL dating.example.com#:~:text=Log%20Out
erstellt, sobald der Nutzer mit der Anzeige interagiert. Wenn der Text „Log Out“ (Abmelden) angezeigt wird, weiß ich, dass das Opfer derzeit bei dating.example.com
angemeldet ist. Dies könnte ich für die Nutzerprofilerstellung verwenden. Da eine naive Textfragments-Implementierung dazu führen kann, dass eine erfolgreiche Übereinstimmung einen Fokusschalter verursachen würde, könnte ich bei evil-ads.example.com
auf das blur
-Ereignis warten und so wissen, wann eine Übereinstimmung aufgetreten ist. Wir haben Textfragmente in Chrome so implementiert, dass das obige Szenario nicht möglich ist.
Ein weiterer Angriff könnte darin bestehen, Netzwerkverkehr basierend auf der Scroll-Position auszunutzen. Angenommen, ich hatte Zugriff auf die Netzwerk-Traffic-Logs meines Opfers, z. B. als Administrator eines Unternehmens-Intranets. Stellen Sie sich nun vor, es gäbe ein langes Personaldokument Was tun, wenn es unter ... leidet... und dann eine Liste von Bedingungen wie Burn-out, Angst usw. Ich könnte neben jedem Element in der Liste ein Tracking-Pixel platzieren. Wenn ich dann feststelle, dass das Laden des Dokuments vorübergehend zusammen mit dem Laden des Tracking-Pixels neben dem Burn-out-Element erfolgt, kann ich als Intranetadministrator feststellen, dass ein Mitarbeiter auf einen Textfragment-Link mit :~:text=burn%20out
geklickt hat, von dem der Mitarbeiter angenommen hat, dass er vertraulich und für niemanden sichtbar ist. Da dieses Beispiel anfangs eher konstruktiv ist und sehr spezifische Voraussetzungen erfüllt sein müssen, hat das Chrome-Sicherheitsteam das Risiko einer überschaubaren Implementierung von Scrollvorgängen bei der Navigation ausgewertet.
Andere User-Agents können stattdessen ein UI-Element zum manuellen Scrollen anzeigen.
Bei Websites, für die der Zugriff deaktiviert werden soll, unterstützt Chromium einen Dokumentrichtlinien-Headerwert, den der Nutzer senden kann, damit User-Agents keine Textfragment-URLs verarbeiten können.
Document-Policy: force-load-at-top
Textfragmente deaktivieren
Am einfachsten können Sie die Funktion deaktivieren, indem Sie eine Erweiterung verwenden, die HTTP-Antwortheader wie ModHeader (kein Google-Produkt) einschleust, um einen Antwortheader (keine Anfrage) wie folgt einzufügen:
Document-Policy: force-load-at-top
Eine weitere, aufwendigere Möglichkeit zur Deaktivierung ist die Unternehmenseinstellung ScrollToTextFragmentEnabled
.
Unter macOS fügen Sie dazu den folgenden Befehl in das Terminal ein.
defaults write com.google.Chrome ScrollToTextFragmentEnabled -bool false
Unter Windows folgen Sie der Dokumentation in der Google Chrome Enterprise-Hilfe.
Textfragmente in der Websuche
Auf einige Suchanfragen bietet die Suchmaschine von Google eine kurze Antwort oder Zusammenfassung mit einem Inhalts-Snippet von einer relevanten Website. Diese hervorgehobenen Snippets werden am ehesten angezeigt, wenn eine Suche in Form einer Frage erfolgt. Durch Klicken auf ein hervorgehobenes Snippet gelangt der Nutzer direkt zum Text des hervorgehobenen Snippets auf der Quellwebseite. Dies funktioniert dank automatisch erstellter Textfragment-URLs.
![](https://web.dev/static/articles/text-fragments/image/KbZgnGxZOOymLxYPZyGH.png?authuser=6&hl=de)
![](https://web.dev/static/articles/text-fragments/image/4Q7zk9xBnb2uw8GRaLnU.png?authuser=6&hl=de)
Fazit
Die Textfragment-URL ist eine leistungsstarke Funktion, um auf beliebigen Text auf Webseiten zu verlinken. Die wissenschaftliche Community kann sie verwenden, um sehr präzise Zitate oder Referenzlinks zur Verfügung zu stellen. Suchmaschinen können damit Deeplinks zu Textergebnissen auf Seiten einrichten. Auf Websites in sozialen Netzwerken können Nutzer bestimmte Abschnitte einer Webseite statt Screenshots teilen, die nicht zugänglich sind. Ich hoffe, Sie nutzen jetzt Textfragment-URLs und finden sie genauso nützlich wie ich. Installieren Sie unbedingt die Browsererweiterung Link to Text Fragment.
Weitere Informationen
- Entwurf der Spezifikation
- TAG-Überprüfung
- Statuseintrag für die Chrome-Plattform
- Tracking-Fehler in Chrome
- Thread „Intent to Ship“
- WebKit-Dev-Thread
- Positionierungs-Thread für Mozilla-Standards
Danksagungen
Textfragmente wurden von Nick Burris und David Bokan in Zusammenarbeit von Grant Wang implementiert und spezifiziert. Vielen Dank an Joe Medley für die gründliche Durchsicht dieses Artikels. Hero-Image von Greg Rakozy auf Unsplash