It's all in your <head>
Hallo
Mein Name ist Marco
Mein Name ist Marco
Ich
- bin verheiratet.
- bin Vater von zwei Mädels (19 und 12).
- Meine Pronomen sind er/ihn.
Mein Name ist Marco
Ich
- bin verheiratet.
- bin Vater von zwei Mädels (19 und 12).
- Meine Pronomen sind er/ihn.
- liebe Musik und Tanzen.
- lese gern.
- bin Casual-Gamer und Speedrunner (Super Metroid).
- werfe gerne Bälle auf Körbe.
Mein Name ist Marco
Ich
- bin verheiratet.
- bin Vater von zwei Mädels (19 und 12).
- Meine Pronomen sind er/ihn.
- liebe Musik und Tanzen.
- lese gern.
- bin Casual-Gamer und Speedrunner (Super Metroid).
- werfe gerne Bälle auf Körbe.
- habe mit 6 Jahren meinen ersten Computer gehabt.
- bin seit 1996 online.
- bin Front-End-Entwickler.
Smashing Magazine
Januar 2013 – Mitte 2016
Land in Sicht
2016 – 2020
Aufwind
seit 2020
Warum der <head>?
Erste Bytes
Entwickler lieben Abkürzungen
- TTFB – Time to First Byte
- LCP – Largest Contentful Paint
- FCP – First Contentful Paint
- CLS – Cumulative Layout Shift
Aber am Ende geht's nur um Render-blocking
Aber am Ende geht's nur um Render-blocking
und wie man's verhindert
Aber am Ende geht's nur um Render-blocking
und wie man's verhindert
indem man seinen <head> richtig aufbaut
Und die Wahrheit ist:
Es ändert sich kaum.
Was sich wirklich geändert hat
Dazugekommen
rel="preload"preconnectprefetch
Rausgeflogen
X-UA-Compatiblemeta name="keywords"- Der Favicon-Wildwuchs
Die Reihenfolge
Das ist es
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Page Title</title>
<link rel="preload" href="/css/site.css?v=0.0.1" as="style" type="text/css">
<link rel="preload" href="/fonts/primary.woff2" as="font" type="font/woff2" crossorigin>
<script>/* fontloading.js inlined */</script>
<style>/* critical CSS inlined */</style>
<link rel="stylesheet" media="print" onload="this.media='screen'" href="/css/site.css?v=0.0.1">
<noscript><link rel="stylesheet" href="/css/site.css?v=0.0.1"></noscript>
<meta name="description" content="…">
<link rel="canonical" href="…">
<script>/* cut-the-mustard inlined */</script>
<link rel="icon" type="image/svg+xml" href="/favicon/favicon.svg">
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png">
<link rel="manifest" href="/site.webmanifest">
</head>
Danke für eure Zeit
10 Schritte, immer in dieser Reihenfolge
meta charsetviewporttitle
10 Schritte, immer in dieser Reihenfolge
meta charsetviewporttitle- Preloads (CSS, Fonts)
- Font Loading (inline JS)
- Critical CSS (inline)
- Async Main Stylesheet
10 Schritte, immer in dieser Reihenfolge
meta charsetviewporttitle- Preloads (CSS, Fonts)
- Font Loading (inline JS)
- Critical CSS (inline)
- Async Main Stylesheet
- SEO Meta (description, canonical, hreflang)
- Feature Detection (inline JS)
- Favicons
Warum diese Reihenfolge?
1. meta charset
Charset – als allererstes
<meta charset="utf-8">
2. viewport
Der Standard-Viewport
<meta name="viewport"
content="width=device-width, initial-scale=1">
Lass den Zoom in Ruhe
<!-- Bitte nicht -->
<meta name="viewport"
content="width=device-width,
initial-scale=1,
maximum-scale=1,
user-scalable=no">
3. title
Title
<title>My beautiful website</title>
4. Preloads
Was ist preload?
Was preloaden?
<link rel="preload"
href="/css/site.css?v=0.0.1"
as="style"
type="text/css" />
<link rel="preload"
href="/fonts/FiraSans-Variable.woff2"
as="font"
type="font/woff2"
crossorigin />
Die Fallen
Die Fallen
crossorigin · as
Die Fallen
crossorigin · as
type
Die Fallen
crossorigin · as
type
Nicht übertreiben
5. Font Loading
Schicht 1: Preload
<link rel="preload"
href="/fonts/FiraSans-Variable.woff2"
as="font"
type="font/woff2"
crossorigin />
<link rel="preload"
href="/fonts/FiraCode-Variable.woff2"
as="font"
type="font/woff2"
crossorigin />
Schicht 2: sessionStorage-Fontloading-Script
(function () {
'use strict';
if (sessionStorage.fontsLoaded) {
document.documentElement.className += ' fonts-loaded-1 fonts-loaded-2';
return;
}
if ('fonts' in document) {
document.fonts.load('400 1em FiraSans').then(function () {
document.documentElement.className += ' fonts-loaded-1';
document.fonts.load('700 1em FiraCode').then(function () {
document.documentElement.className += ' fonts-loaded-2';
sessionStorage.fontsLoaded = true;
});
});
}
})();
Schicht 3: font-family im critical CSS
@font-face {
font-family: 'FiraSans';
src: url('/fonts/FiraSans-Variable.woff2') format('woff2');
font-weight: 100 900;
font-display: swap;
}
body {
font-family: 'Helvetica Neue', sans-serif;
}
.fonts-loaded-1 body {
font-family: 'FiraSans', sans-serif;
}
6. Critical CSS
Was ist Critical CSS?
<style>
/* critical.css */
</style>
Was kommt rein?
@import 'foundation/fonts';
@import 'foundation/normalize';
@import 'foundation/typography';
@import 'foundation/header';
@import 'foundation/hero';
Klein und einfach halten
Idealerweise passen HTML und Critical CSS bis zu diesem Punkt in 14kb.
7. Async Main Stylesheet
Das Hauptstylesheet – ohne zu blocken
<link rel="stylesheet"
media="print"
onload="this.media='screen'"
href="/css/site.css?v=0.0.1" />
<noscript>
<link rel="stylesheet"
href="/css/site.css?v=0.0.1" />
</noscript>
Cache-Busting
<link href="/css/site.css?v=0.0.1" />
8. SEO Meta
Description, Canonical, Hreflang
<meta name="description"
content="Personal website and blog" />
<link rel="canonical"
href="https://your-website.com/" />
<link rel="alternate"
hreflang="de"
href="https://your-website.com/" />
<link rel="alternate"
hreflang="en"
href="https://your-website.com/en/" />
9. Feature Detection
Ein cooler One-Liner
<html lang="de" class="no-js">
document.documentElement.classList.replace('no-js', 'js');
Was bringt's?
/* Verstecke JS-only Komponenten, wenn kein JS */
.no-js .js-only {
display: none;
}
/* Verstecke No-JS-Fallbacks, wenn JS verfügbar */
.js .no-js-only {
display: none;
}
Warum inline und so früh?
- Das Script läuft synchron, bevor irgendein CSS rendert.
- Die Klasse ist am
<html>, bevor der erste Pixel gezeichnet wird. - Kein zusätzlicher Request, kein
defer, keine Race-Condition.
10. Favicons
Das Mindeste
<link rel="icon"
type="image/svg+xml"
href="/favicon/favicon.svg">
<link rel="icon"
type="image/png"
sizes="32x32"
href="/favicon/favicon-32x32.png">
<link rel="apple-touch-icon"
sizes="180x180"
href="/favicon/apple-touch-icon.png">
<link rel="manifest"
href="/site.webmanifest">
Warum ganz am Ende?
Der ganze Block
Von oben nach unten
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Page Title</title>
<link rel="preload" href="/css/site.css?v=0.0.1" as="style" type="text/css">
<link rel="preload" href="/fonts/primary.woff2" as="font" type="font/woff2" crossorigin>
<script>/* fontloading.js inlined */</script>
<style>/* critical CSS inlined */</style>
<link rel="stylesheet" media="print" onload="this.media='screen'" href="/css/site.css?v=0.0.1">
<noscript><link rel="stylesheet" href="/css/site.css?v=0.0.1"></noscript>
<meta name="description" content="…">
<link rel="canonical" href="…">
<script>/* cut-the-mustard inlined */</script>
<link rel="icon" type="image/svg+xml" href="/favicon/favicon.svg">
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png">
<link rel="manifest" href="/site.webmanifest">
</head>
Dieselbe Seite. Zwei Heads.
Checklist
Performance-Checklist
- Korrekt preloaden mit
type,as– undcrossorigin, wenn es eine Font ist - Nicht alles preloaden
font-display: swapin@font-face- Font-Loading mit Klassen-Toggle und sessionStorage
- Critical CSS inline
- Hauptstylesheet async (print-media-Trick)
<noscript>-Fallback für Stylesheets- Cache-Busting per Version-Query-String
- Kleine Scripts inline
no-js-Klasse am<html>
Performance-Checklist
- Korrekt preloaden mit
type,as– undcrossorigin, wenn es eine Font ist - Nicht alles preloaden
font-display: swapin@font-face- Font-Loading mit Klassen-Toggle und sessionStorage
- Critical CSS inline
- Hauptstylesheet async (print-media-Trick)
<noscript>-Fallback für Stylesheets- Cache-Busting per Version-Query-String
- Kleine Scripts inline
no-js-Klasse am<html>- Ressourcen selbst hosten
Danke!
Fragen?
marco-hengstenberg.de