Slide 1

Slide 1 text

Pagespeed Extreme Kai Spriestersbach

Slide 2

Slide 2 text

Research & Development bei der eology GmbH • B.Sc. E-Commerce • Mediengestalter IHK • Lehrbeauftragter an der FHWS • Inhaber von SEARCH ONE • Aus- und Weiterbildung von Mitarbeitern • Speaker auf SMX, SEOkomm, SEO-Day, OMK, OMKB, etc. Kai Spriestersbach

Slide 3

Slide 3 text

SEO aus Leidenschaft • Online seit 1996 • Web-Design seit 2001 • Web-Entwicklung 2004 • SEO seit 2008 • Selbstständig seit 2012 Kai Spriestersbach Matt Cutts Head Of Web Spam, Google Sie könnten mich kennen von

Slide 4

Slide 4 text

Neuer Rankingfaktor Page Experience

Slide 5

Slide 5 text

https://webmasters.googleblog.com/2020/05/evaluating-page-experience.html

Slide 6

Slide 6 text

https://webmasters.googleblog.com/2020/05/evaluating-page-experience.html

Slide 7

Slide 7 text

https://webmasters.googleblog.com/2020/05/evaluating-page-experience.html

Slide 8

Slide 8 text

https://webmasters.googleblog.com/2020/05/evaluating-page-experience.html

Slide 9

Slide 9 text

https://webmasters.googleblog.com/2020/05/evaluating-page-experience.html

Slide 10

Slide 10 text

https://webmasters.googleblog.com/2020/05/evaluating-page-experience.html

Slide 11

Slide 11 text

Mehr unter: https://kai.im/pagespeed Mein Online-Seminar 
 Web Vitals & PageSpeed +

Slide 12

Slide 12 text

PageSpeed Basics

Slide 13

Slide 13 text

PageSpeed Basics Daran führt kein Weg vorbei • HTTP/2 (Test: https://http2.pro/) • Cache-Control & ETags • GZIP, besser noch brotli • Bilder • Responsive Images • Nur in dargestellter Größe einbetten • Lazy Load für Bilder & Videos • Kompression via JPG + PNG + WebP (+ Avif)

Slide 14

Slide 14 text

TTFB Optimierung

Slide 15

Slide 15 text

TTFB = Time To First Byte

Slide 16

Slide 16 text

Deshalb ist die TTFB so wichtig! https://www.webpagetest.org/

Slide 17

Slide 17 text

Deshalb ist die TTFB so wichtig! } GEFÜHLT PASSIERT NIX! https://www.webpagetest.org/

Slide 18

Slide 18 text

Was passiert vor dem 1. Byte? • Domain wird via DNS aufgelöst • TCP-Verbindung wird aufgebaut
 SYN, SYN-ACK, ACK • TLS-Handshake für SSL-Verbindung • Request wird an den Server gesendet
 TTFB https://www.mozilla.org/de/firefox/browsers/compare/ https://www.cloudflare.com/learning/dns/what-is-dns/ https://www.cloudflare.com/de-de/learning/ssl/what-happens-in-a-tls-handshake/ TCP ~50ms TLS ~110ms DNS ~50ms

Slide 19

Slide 19 text

Puh… wir warten immer noch auf das erste Byte! • HTTP Request • CGI-Request • PHP-Script laden • PHP ausführen • Datenbank abfragen • HTML rendern • HTTP Response mit HTML senden TTFB GET / HTTP/1.1 Host: www.example.com Request / index.php SELECT column1, colum FROM table_name; Built HTML HTTP/1.1 200 OK Date: Mon, 27 Jul 2020 12:28:53 GMT Server: NGINX Content-Length: 88 Content-Type: text/html Connection: Closed

Hello, World!

Slide 20

Slide 20 text

Puh… wir warten immer noch auf das erste Byte! • HTTP Request • CGI-Request • PHP-Script laden • PHP ausführen • Datenbank abfragen • HTML rendern • HTTP Response mit HTML senden TTFB GET / HTTP/1.1 Host: www.example.com Request / index.php SELECT column1, colum FROM table_name; Built HTML HTTP/1.1 200 OK Date: Mon, 27 Jul 2020 12:28:53 GMT Server: NGINX Content-Length: 88 Content-Type: text/html Connection: Closed

Hello, World!

Slide 21

Slide 21 text

1. Full Page Cache aktivieren • Fertig generiertes HTML wird im RAM vorgehalten • Alle unbekannten Nutzer erhalten statisches HTML • Cookie-/Pfadbasierte Ausnahmen • PHP, HDD & DB werden nicht benötigt! TTFB Optimierung Request / Cached HTML ..zZz RAM

Slide 22

Slide 22 text

2. Opcode, Object In-Memory Cache + NVMe nutzen • Schnellste SSDs (NVMe) statt drehender Platten • Bereits vorprozessierter PHP-Code wird gespeichert • Häufig benutze Objekte/Fragmente werden persistent gespeichert • Häufige Datenbankabfragen werden im RAM gehalten • Beschleunigt selbst dynamische Webseiten! TTFB Optimierung

Slide 23

Slide 23 text

3. CDN verwenden • Schnellster DNS + AnyCast IP • Hosting in weltweiten Datencentern = Nah am Kunden • Argo Routing = Schnellster Weg • Seiten liegen bereits fertig gerendert im CDN • On-The-Fly Content Optimierung möglich (Bilder, Kompression, etc.) TTFB Optimierung

Slide 24

Slide 24 text

Rendering verbessern

Slide 25

Slide 25 text

Rendering „sichtbar“ machen https://developers.google.com/web/fundamentals/performance/critical-rendering-path?hl=de Progressives Rendering Unoptimiertes Rendering

Slide 26

Slide 26 text

Der kritische Rendering-Pfad https://bitsofco.de/understanding-the-critical-rendering-path/

Slide 27

Slide 27 text

Performance in den Chrome Developer Tools

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

Non-blocking CSS Inline CSS im Media-Attribut

Slide 30

Slide 30 text

Critical CSS

Slide 31

Slide 31 text

Critical CSS Tool https://criticalcss.com/

Slide 32

Slide 32 text

Critical CSS Tool https://criticalcss.com/

Slide 33

Slide 33 text

Third-Party Tags reduzieren https://www.webpagetest.org/video/view.php?id=190919_Di27491eeccb968f96eda867ddabf2ff3c8c24ed3d

Slide 34

Slide 34 text

Third-Party Tags reduzieren https://www.webpagetest.org/video/view.php?id=190919_Di27491eeccb968f96eda867ddabf2ff3c8c24ed3d

Slide 35

Slide 35 text

Async & Deferred JavaScript

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

>80% des JS ist nicht aufschiebbar! https://w3techs.com/technologies/overview/javascript_library https://trends.builtwith.com/javascript

Slide 41

Slide 41 text

Alles hört auf „DOM ready“

Slide 42

Slide 42 text

No content

Slide 43

Slide 43 text

Wahrgenommene Ladezeit

Slide 44

Slide 44 text

Skeleton Screens https://css-tricks.com/building-skeleton-screens-css-custom-properties/

Slide 45

Slide 45 text

Abstrakte Darstellung genügt! https://css-tricks.com/building-skeleton-screens-css-custom-properties/

Slide 46

Slide 46 text

No content

Slide 47

Slide 47 text

Web Fonts

Slide 48

Slide 48 text

Font Rendering verbessern https://fonts.google.com/specimen/Roboto

Slide 49

Slide 49 text

So bitte nicht! CSS-Datei herunterladen CSS prozessieren DNS Auflösung TCP-Verbindungsaufbau SSL-Handshake WebFont herunterladen WebFont rendern DNS Auflösung TCP-Verbindungsaufbau SSL-Handshake Text anzeigen HTML geladen

Slide 50

Slide 50 text

Das können wir uns sparen CSS-Datei herunterladen CSS prozessieren DNS Auflösung TCP-Verbindungsaufbau SSL-Handshake WebFont herunterladen WebFont rendern DNS Auflösung TCP-Verbindungsaufbau SSL-Handshake Text anzeigen HTML geladen

Slide 51

Slide 51 text

Also besser so… CSS-Datei herunterladen CSS prozessieren WebFont herunterladen WebFont rendern Text anzeigen HTML geladen

Slide 52

Slide 52 text

Also besser so… CSS-Datei herunterladen CSS prozessieren WebFont herunterladen WebFont rendern Text anzeigen HTML geladen https://web.dev/font-display/

Slide 53

Slide 53 text

Also besser so… CSS-Datei herunterladen CSS prozessieren WebFont herunterladen WebFont rendern Text anzeigen HTML geladen

Slide 54

Slide 54 text

Also besser so… CSS-Datei herunterladen CSS prozessieren WebFont herunterladen WebFont rendern Text anzeigen HTML geladen

Slide 55

Slide 55 text

Smart Font Reducing

Slide 56

Slide 56 text

https://transfonter.org/ Danke an Daniel Abromeit @der_abro

Slide 57

Slide 57 text

https://github.com/hakatashi/unicode-map

Slide 58

Slide 58 text

No content

Slide 59

Slide 59 text

No content

Slide 60

Slide 60 text

Was bringt Smart Font Reducing? 4 DNS Requests
 30 HTTP-Requests
 300 KB Daten via Google Fonts Selfhosted reduced Font 0 DNS Requests
 1 HTTP-Requests
 20 KB Daten

Slide 61

Slide 61 text

Smart Preloading

Slide 62

Slide 62 text

No content

Slide 63

Slide 63 text

No content

Slide 64

Slide 64 text

No content

Slide 65

Slide 65 text

No content

Slide 66

Slide 66 text

HOME

Slide 67

Slide 67 text

HOME

Slide 68

Slide 68 text

No content

Slide 69

Slide 69 text

Mouse Over, ARTICLE HOME

Slide 70

Slide 70 text

Universal Hover-Preloader /** * Copyright (c) 2020 Google Inc * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ const exposed = {}; if (location.search) { var a = document.createElement("a"); a.href = location.href; a.search = ""; history.replaceState(null, null, a.href); } function tweet_(url) { open( "https://twitter.com/intent/tweet?url=" + encodeURIComponent(url), "_blank" ); } function tweet(anchor) { tweet_(anchor.getAttribute("href")); } expose("tweet", tweet); function share(anchor) { var url = anchor.getAttribute("href"); event.preventDefault(); if (navigator.share) { navigator.share({ url: url, }); } else if (navigator.clipboard) { navigator.clipboard.writeText(url); message("Article URL copied to clipboard."); } else { tweet_(url); } } expose("share", share); function message(msg) { var dialog = document.getElementById("message"); dialog.textContent = msg; dialog.setAttribute("open", ""); setTimeout(function () { dialog.removeAttribute("open"); }, 3000); } function prefetch(e) { if (e.target.tagName != "A") { return; } if (e.target.origin != location.origin) { return; } var l = document.createElement("link"); l.rel = "prefetch"; l.href = e.target.href; document.head.appendChild(l); } document.documentElement.addEventListener("mouseover", prefetch, { capture: true, passive: true, }); document.documentElement.addEventListener("touchstart", prefetch, { capture: true, passive: true, }); const GA_ID = document.documentElement.getAttribute("ga-id"); window.ga = window.ga || function () { if (!GA_ID) { return; } (ga.q = ga.q || []).push(arguments); }; ga.l = +new Date(); ga("create", GA_ID, "auto"); ga("set", "transport", "beacon"); var timeout = setTimeout( (onload = function () { clearTimeout(timeout); ga("send", "pageview"); }), 1000 ); var ref = +new Date(); function ping(event) { var now = +new Date(); if (now - ref < 1000) { return; } ga("send", { hitType: "event", eventCategory: "page", eventAction: event.type, eventLabel: Math.round((now - ref) / 1000), }); ref = now; } addEventListener("pagehide", ping); addEventListener("visibilitychange", ping); addEventListener( "click", function (e) { var button = e.target.closest("button"); if (!button) { return; } ga("send", { hitType: "event", eventCategory: "button", eventAction: button.getAttribute("aria-label") || button.textContent, }); }, true ); var selectionTimeout; addEventListener( "selectionchange", function () { clearTimeout(selectionTimeout); var text = String(document.getSelection()).trim(); if (text.split(/[\s\n\r]+/).length < 3) { return; } selectionTimeout = setTimeout(function () { ga("send", { hitType: "event", eventCategory: "selection", eventAction: text, }); }, 2000); }, true ); if (window.ResizeObserver && document.querySelector("header nav #nav")) { var progress = document.getElementById("reading-progress"); var timeOfLastScroll = 0; var requestedAniFrame = false; function scroll() { if (!requestedAniFrame) { requestAnimationFrame(updateProgress); requestedAniFrame = true; } timeOfLastScroll = Date.now(); } addEventListener("scroll", scroll); var winHeight = 1000; var bottom = 10000; function updateProgress() { requestedAniFrame = false; var percent = Math.min( (document.scrollingElement.scrollTop / (bottom - winHeight)) * 100, 100 ); progress.style.transform = `translate(-${100 - percent}vw, 0)`; if (Date.now() - timeOfLastScroll < 3000) { requestAnimationFrame(updateProgress); requestedAniFrame = true; } } new ResizeObserver(() => { bottom = document.scrollingElement.scrollTop + document.querySelector("#comments,footer").getBoundingClientRect().top; winHeight = window.innerHeight; scroll(); }).observe(document.body); } function expose(name, fn) { exposed[name] = fn; } addEventListener("click", (e) => { const handler = e.target.closest("[on-click]"); if (!handler) { return; } e.preventDefault(); const name = handler.getAttribute("on-click"); const fn = exposed[name]; if (!fn) { throw new Error("Unknown handler" + name); } fn(handler); }); // There is a race condition here if an image loads faster than this JS file. But // - that is unlikely // - it only means potentially more costly layouts for that image. // - And so it isn't worth the querySelectorAll it would cost to synchronously check // load state. document.body.addEventListener( "load", (e) => { if (e.target.tagName != "IMG") { return; } // Ensure the browser doesn't try to draw the placeholder when the real image is present. e.target.style.backgroundImage = "none"; }, /* capture */ "true" ); https://kai.im/preloader Danke an Daniel Abromeit @der_abro

Slide 71

Slide 71 text

Noch nicht genug gehört? Lerne einfach alles über PageSpeed & Web Vitals Melde Dich jetzt unverbindlich für mein Online Seminar an! https://kai.im/pagespeed