webpages have to be designed with speed in mind. In fact, speed must be the overriding design criterion.
| Dauer | Wirkung |
|---|---|
| 0 - 1 s. | gefühlt "unmittelbar", sehr angenehm |
| 1 - 10 s. | spürbar, aber im erträglichen Rahmen |
| 10+ s. |
unerträglich! Man verliert den Faden und die Lust an der Seite |
Die Durchschnittserwartung liegt bei 4 Sekunden Ladezeit.
| Ladezeit | Pageviews | Konversionsrate | Abbruchquote |
|---|---|---|---|
| 1 s. | +/-0% | +/-0% | +/-0% |
| 3 s. | -22% | -22% | +50% |
| 5 s. | -35% | -38% | +105% |
| 10 s. | -46% | -42% | +135% |
80% of the end-user response time is spent on the front-end. Most of this time is tied up in downloading all the components in the page: images, stylesheets, scripts, Flash, etc.
| Jahr | Dateianzahl | Dateigöße |
|---|---|---|
| 1995 | 2,3 Dateien | 14,1 KB |
| 2010 | 75 Dateien | 498 KB |
Nope!
A single-user client SHOULD NOT maintain more than 2 connections with any server
Ein Wasserfall, je 2 Dateien parallel (IE6 & 7),
Extra-Latenzen addieren sich pro Stufe auf. Thank you, IETF.
Wasserfall, je 6 Dateien parallel (Chrome, Firefox & Co) Besser. Extra-Latenzen addieren sich dennoch auf.
Gut:
Schlecht:
Entfernung in km / (0.66 x Lichtgeschwindigkeit)
+ ca. 10ms (wg. Signalwandler)
+ "letzte Meile":
| Leitungstechnik | Latenz |
|---|---|
| Kabelnetzwerk | 1 ms |
| Drahtlosnetzwerk | 5 ms |
| Fernsehkabel | 5 ms |
| DSL | 20 ms |
| ISDN | 100 ms |
| UMTS | 175 ms |
| GPRS / EDGE | 425 ms |
via DSL + WLAN:
33 ms + 20 ms + 5 ms
= 58 ms
via UMTS:
33 ms + 175 ms
= 208 ms
Nicht schön:
<script src="js/jquery.js"></script>
<script src="js/jquery-ui.js"></script>
<script src="js/jquery-fancybox.js"></script>
Besser:
<script src="js/jquery-jquery-ui-jquery-fancybox.js"></script>
Nicht schön:
<html> <head> <link rel="stylesheet" href="desktop.css" media="screen"> <link rel="stylesheet" href="mobile.css" media="screen and (max-width: 1024px)"> <link rel="stylesheet" href="tablet.css" media="screen and (max-width: 768px)"> <link rel="stylesheet" href="print.css" media="print"> <!--[if IE]> <link rel="stylesheet" href="ie.css"> <![endif]-->
Besser:
<!--[if !IE]><!--> <html> <!--<![endif]--> <!--[if IE]> <html class="ie"> <![endif]--> <head><link rel="stylesheet" href="styles.css">
body { width: 1024px; }
.ie body { zoom: 1; }
@media print {
body { width: auto; }
}
@media screen and (max-width: 1024px) {
body { width: 768px; }
}
@media screen and (max-width: 768px) {
body { width: 320px; }
}
Per PHP zusammenfassen:
<?php
header("Content-type: text/javascript");
echo file_get_contents("jquery.js")."\r\n";
echo file_get_contents("jquery-ui.js")."\r\n";
echo file_get_contents("jquery-fancybox.js")."\r\n";
?>
und als JavaScript dieses PHP einbinden:
<script src="js/scripte.php"></script>
@import url("reset.css");
@import url("page.css");
@import url("navi.css");
@import url("content.css");
besser:
<?php
header("Content-type: text/css");
echo file_get_contents("reset.css")."\r\n";
echo file_get_contents("page.css")."\r\n";
echo file_get_contents("navi.css")."\r\n";
echo file_get_contents("content.css")."\r\n";
?>
<link rel="stylesheet" href="styles.php">
<a href="#"><img src="neu.png"></a> <a href="#"><img src="oeffnen.png"></a> <a href="#"><img src="speichern.png"></a>
Besser:
a {
display: inline-block;
width: 16px;
height: 16px;
background-image: url(sprite.png);
}
a.neu { background-position: 0 0; }
a.oeffnen { background-position: -16px 0; }
a.speichern { background-position: -32px 0; }
Vorher:
<img src="bild.gif">
Nachher:
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAOfo7AAAACH5BAAAAAAA LAAAAAABAAEAAAICRAEAOw==">
WTF?!!?
data:
image/gif+
;charset=
utf-8+
;base64,
IE8 kennt Data URI, belegt sie aber mit Einschränkungen:
Aus 24KB Binärdaten werden 32KB Data URI Daten. Als Gegenmaßnahme ZIP-Kompression aktivieren:
<IfModule mod_filter.c>
AddOutputFilterByType DEFLATE application/atom+xml \
application/javascript application/json \
application/rss+xml application/vnd.ms-fontobject \
application/x-font-ttf application/xhtml+xml \
application/xml font/opentype \
image/svg+xml image/x-icon text/css text/html \
text/plain text/x-component text/xml
</IfModule>
Eintrag in der .htaccess Datei
Alles wird 1 Monat gecached, außer: das Dokument, AJAX-Calls und eine mögliche AppCache-Datei.
<IfModule mod_expires.c>
ExpiresActive on
ExpiresDefault "access plus 1 month"
ExpiresByType text/html "access plus 0 seconds"
ExpiresByType text/xml "access plus 0 seconds"
ExpiresByType application/xml "access plus 0 seconds"
ExpiresByType application/json "access plus 0 seconds"
ExpiresByType text/cache-manifest "access plus 0 seconds"
</IfModule>
Eintrag in der .htaccess Datei
Um nachträglich geänderte Dateien an den Mann zu bringen, die im Browser gecached liegen, muss man die URL abändern. Am besten klappt das mit GET-Parametern, z.B. einer hochzählenden Versionierung:
<script src="script.js?v=2"><script>
...oder einem automatisierten Timestamp (etwas mehr Belastung für den Server):
<script src="script.js?timestamp=<?php echo filemtime('script.js') ?>"><script>
Grund:
Fehlende Schriften erzeugen eine Renderblockade.
Im HTML referenzieren spart gegenüber in externem CSS Latenz:
<style>
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: local('Open Sans'), local('OpenSans'), url(blabla.woff) format('woff');
}
</style>
<link rel="stylesheet" href="...">
</head>
JavaScript stoppt das progressive Rendern der Seite an der Stelle der Einbindung.
Beispiel: Testaufbau bei Cuzillion
JavaScript im Fuß der Seite bremst dort genauso, wird aber nicht bemerkt.
Sorge tragen, dass non-funktionale Elemente solange nicht als "kaputt" auffallen, bzw. dass sie ausgeblendet sind:
.interaktives_element { display: none; }
$(document).ready(function(){
$('.interaktives_element').interaktivMach().fadeIn();
});
Ansonsten beginnt der IE das Parsen der Seite nochmal neu, wenn er auf das Charset stößt:

<head> <meta charset="utf-8"> <title>Foobar</title>
Auch hier beginnt der IE das Parsen der Seite nochmal neu, wenn er auf die Metaangabe stößt:

<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=IE7">
Auch sollte kein JavaScript vorher kommen
Besonders relevant aufgrund des blockierenden Verhaltens dieser Dateitypen.

Name |
Sprache |
für… |
Webservice |
Yahoo! YUI Compressor |
Java |
JS + CSS |
Ja |
Google Closure Compiler |
Java |
JS |
Ja |
UglifyJS |
Node.js |
JS |
Ja |
Microsoft AJAX Minifier |
.NET |
JS + CSS |
Nein |
CSSTidy |
PHP |
CSS |
Ja |
JSMin+ |
PHP |
JS |
Nein |
java -jar yuicompressor-2.4.6.jar -o "../css/datei.min.css" "../css/datei.css"
vorher:
.klasse {
font-style: normal;
font-variant: normal;
font-weight: bold;
font-size: 1em;
line-height: 1.7;
font-family: Arial, Helvetica, sans-serif;
}nachher:
.klasse{font:bold 1em/1.7 Arial,Helvetica,sans-serif;}
vorher:
if(a == 1){
var x = 'eins';
}
else {
var x = 'null';
}
nachher:
var x=a==1?'eins':'null';
| jQuery version | Normal file size (in bytes) | Minified file size (in bytes) | Gzipped file size (in bytes) | Minified and gzipped file size (in bytes) |
|---|---|---|---|---|
| 1.4.4 | 183,184 bytes (178.89 KB) | 78,601 bytes (76.76 KB) | 51,690 bytes (50.48 KB) | 27,073 bytes (26.44 KB) |
| 1.6.2 | 236,202 bytes (230.67 KB) | 91,556 bytes (89.41 KB) | 67,775 bytes (66.19 KB) | 32,065 bytes (31.31 KB) |
| 1.8.1 | 261,525 bytes (255.40 KB) | 92,793 bytes (90.62 KB) | 77,626 bytes (75.81 KB) | 33,204 bytes (32.43 KB) |
|
|
|
|
SVG |
7,57 KB |
51,50 KB |
4,50 KB |
PNG 200px |
6,50 KB |
11,10 KB |
4,18 KB |
PNG 400px |
11,80 KB |
27,60 KB |
8,32 KB |
PNG 800px |
18,50 KB |
72,70 KB |
14,80 KB |
Fett = kleiner als SVG.
SVG gewinnt an Land, je mehr die Bildfläche zunimmt.
Metadaten raus, Optimierung der bei der Kompression verwendeten sogenannten Huffman Tabellen, geringere Farbunterabtastung.
Stattdessen PNG 8/8 verwenden.

Erzeugung per Fireworks oder Umwandelung per PNGQuant auf der Kommandozeile: pngquant 256 *.png
Oder via PNGMini auf dem Mac
Metadaten und "Chunks" raus
Detailgrad der Formen reduzieren und Metadaten sowie Füllmaterial aus dem SVG-Quelltext entfernen
python scour.py -i bild.svg -o bild-opt.svg
Wenn klar ist, dass nur Deutsch geschrieben wird, kann man sich viele länderspezifische Zeichen sparen. Zeichenreduktion z.B. via Font Squirrel @font-face Generator.

| Datei | Ursprungsgröße, bytes | gezippte Größe, bytes | Ersparnis, % |
|---|---|---|---|
| AllerDisplay.ttf | 95,616 | 47,771 | 50.04% |
| Aller_Bd.ttf | 128,368 | 59,884 | 53.35% |
| Aller_BdIt.ttf | 123,556 | 58,942 | 52.30% |
| Aller_It.ttf | 120,876 | 58,459 | 51.64% |
| Aller_Lt.ttf | 132,780 | 60,766 | 54.24% |
| Aller_LtIt.ttf | 122,296 | 57,342 | 53.11% |
| Aller_Rg.ttf | 134,436 | 63,379 | 52.86% |
| Sansation_Bold.ttf | 19,644 | 10,467 | 46.72% |
| Sansation_Light.ttf | 19,568 | 10,425 | 46.72% |
| Sansation_Regular.ttf | 19,480 | 10,172 | 47.78% |
Außer WOFF-Dateien. Die sind eh schon gezippt.
Bilder erst beim Ins-Bild-Scrollen einladen, z.B. via Lazy Load Plugin for jQuery:
<img src="blank.gif" data-original="blubb.jpg" width="640" heigh="480">
$(document).ready(function(){
$("img").lazyload();
});In jQuery via getScript-Methode. z.B. vorher:
$(window).load(function() {
$('.flexslider').flexslider();
});nachher:
$(window).load(function() {
window.setTimeout(function(){
$.getScript('js/jquery.flexslider.js', function(){
$('.flexslider').flexslider();
});
}, 2000);
});oder sowas:
$('#dings').mouseenter(function({
$.getScript('js/dingsbumms.js', function(){
$('#dings a').click(function(){
machwasschoenes();
});
});
});getScript-Methode cached von Haus aus nicht, weil sie für AJAX-Calls gedacht ist. Und die sollen nicht gecached werden. So baut man es um:
$.getScript = function(url, callback){
$.ajax({
type: "GET",
url: url,
success: callback,
dataType: "script",
cache: true
});
};In HTML5 gibt es <link rel="prefetch">.
Für ganze Seiten:
<link rel="prefetch" href="http://goatse.com">
für einzelne Ressourcen:
<link rel="prefetch" href="http://goatse.com/tubgirl.jpg">
Unterstützt von Firefox
Chrome unterstützt <link rel="prerender">:
<link rel="prerender" href="http://goatse.com">
Aber nur einmal im Dokument. Chrome lädt UND rendert dann dieses Dokument schon einmal im Hintergrund vor, so dass es, wenn es annavigiert wird, sofort bereitsteht.