CSS sprites in de praktijk: Plan België titels

Dit is het eerste deel van een reeks artikels over CSS technieken waarbij sprites op een creatieve manier worden gebruikt om flexibele en performante resultaten te bekomen.

Aan de hand van CSS sprites kan je het aantal requests op een website beperken, door verschillende afbeeldingen in 1 of meerdere afbeeldingen te combineren. Dit heeft een grote impact op de performantie van je website. Als de sprites dan ook nog eens gecached worden, kan dit de rendering van de pagina’s drastisch optimaliseren.

Plan België

Zo hebben we ondermeer gezorgd voor een grondige frontend optimalisatie bij de uitwerking van de Plan België website. Het doel daar, was om het aantal requests tot een minimum beperken, omwille van het grafische karakter van de site. Daarom leek het ons wel een uitdaging om creatief aan de slag te gaan met PNG afbeeldingen en trachten 1 sprite te maken voor alle titels over heel de website.

Flexibele en herbruikbare PNG’s

Doorheen de Plan België website vind je dit soort titels:

Voorbeeld titels op Plan België website

Voorbeeld titels op Plan België website

Zoals je kan zien: verschillende kleuren en variabele breedtes zijn mogelijk.

Analyse en aanpak

Het idee dat we hadden, was om een transparante afbeelding te gebruiken, waarbij we hetgene dat wit moet zijn, wit houden en hetgene ingekleurd moet worden, transparant. Daardoor kunnen we via CSS een achtergrondafbeelding + achtergrondkleur specifiëren.

Om het gewenste effect te krijgen, maken we gebruik van een 24-bit PNG file. De afbeelding omvat tevens een semi-transparant gedeelte, waar een lichtere variant van de kleur doorschijnt (opacity 85%).

(Semi)transparante 24-bit PNG waarbij ter illustratie het transparante gedeelte groen is ingekleurd

(Semi)transparante 24-bit PNG waarbij ter illustratie het transparante gedeelte groen is ingekleurd

De sprite bestaat dus uit twee delen: .bg en .border

De sprite bestaat dus uit twee delen: .bg en .border

Omdat transparante 24-bit PNG files niet ondersteund worden in Internet Explorer 6, opteren we ervoor om in die browser een 8-bit PNG versie te voorzien. Het resultaat in deze browser is een iets ruwere versie, maar omdat bij Plan België het toch ging om een grunge look, vormde dat geen probleem.

De code

HTML
  1. <h2>
  2. <span class="border">Steun Plan</span>
  3. <span class="bg"></span>
  4. </h2>

Er zijn twee extra spans nodig om de styling naar behoren uit te voeren.

CSS
  1. h2 {
  2. position: relative;
  3. font-size: 15px;
  4. height: 32px;
  5. }

Position wordt op relative geplaatst, om een span absoluut te kunnen positioneren t.o.v. de h2. Verder wordt een vaste hoogte bepaald, omdat de children ofwel absoluut gepositioneerd zullen zijn, ofwel een float zullen krijgen.

  1. .bg {
  2. position: absolute;
  3. left: 0;
  4. height: 18px;
  5. padding: 7px 10px 3px;
  6. color: #fff;
  7. background: #0D5F99 url(img/sprite.png) no-repeat 0 0;
  8. }

De .bg class is het gekleurde vlak achter de tekst. Het wordt absoluut gepositioneerd, krijgt een witte tekstkleur, als achtergrond een kleur én een afbeelding (het bovenste deel van de sprite).

De totale hoogte is 18px + 7px (padding-top) + 3px (padding-bottom) = 28px.

  1. .border {
  2. float: left;
  3. margin: 2px 0 0;
  4. height: 28px;
  5. width: 100%;
  6. background: #0D5F99 url(img/sprite.png) no-repeat 0 100%;
  7. }

De .border class krijgt een float: left, alsook de achtergrondkleur en afbeelding (het onderste deel van de sprite). De hoogte wordt ook ingesteld op 28px, maar met een margin-top van 2px, zodat de lijn net onder het tekstvlak wordt getoond.

De breedte van de .border krijgt een waarde van 100%. Hij neemt dus de hele breedte van zijn parent in (dus de h2). Hierdoor zal de titel steeds even breed zijn als de container waarin hij zich bevindt (bvb smalle kolom, volledige pagina breedte, …)

Om een gelijkaardig resultaat te krijgen in IE6 waren nog enkele aanpassingen nodig in de conditional stylesheet.

  1. .bg, .border {
  2. background-image: url(img/sprite_8bit.png);
  3. z-index: 20;
  4. }
  5. .example .border {
  6. position: absolute;
  7. margin-top: 0;
  8. height: 30px;
  9. z-index: 10;
  10. }

Varianten

Op de Plan België website wordt ook een vereenvoudigde versie van deze titels gebruikt, waarbij een grunge lijntje onder de titel staat. Ook hier hanteren we dezelfde techniek.

Voorbeeld van vereenvoudigde PNG titels

Voorbeeld van vereenvoudigde PNG titels

Demo

Voor het gemak heb ik een demo klaargezet.

Voordelen van deze techniek

  • Slechts 1 HTTP request voor de afbeelding
  • Alle kleuren van titels (voor- en achtergrond alsook het semi-transparante gedeelte) kunnen eenvoudig via CSS aangepast worden
  • Geen image replacement technieken nodig
  • Titel zijn horizontaal schaalbaar
  • Je moet geen afzonderlijke images maken voor de verschillende titels of kleuren

AS3, fonts & speciale karakters

Flash & custom fonts, het blijft een speciale combinatie. Op zich is een custom font gebruiken niet moeilijk, maar wat als je extended ASCII karakters wil gebruiken?

Bij de uitwerking van een Flash ActionScript 3 project voor Toyota Europe werd ons de vraag gesteld om ondersteuning te bieden voor andere talen, met hun eigen tekenset, zoals o.a. een Cyrillische tekenset. Zo gingen wij op zoek naar de meest efficiënte manier om een custom font te embedden, met ondersteuning voor de meer exotische karakters.

Fonts in de library

Een eerste, logische stap zou zijn om het gewenste font in onze Flash library op te slaan, en daaruit te exporteren.

AS3 Font Embedding: Font exporteren Met het font in onze library kunnen we nu in de code duiken. We creëren een TextFormat object, waarin we de .name property invullen met de naam van ons font (de naam zoals je die ziet in elke tekst editor). Een goede manier om de naam van het font op te halen is via de Font.enumerateFonts() methode.

var fonts:Array = Font.enumerateFonts(false);
fonts.sortOn("fontName", Array.CASEINSENSITIVE);
var fmt:TextFormat = new TextFormat();
fmt.font = fonts[0].fontName; // Naam van het font als String
fmt.color = 0x4E3E16;
fmt.size = 20;
fmt.bold = false;

Om tekst te tonen hebben we natuurlijk een TextField nodig. Een overzicht van de belangrijkste properties.

var normalField:TextField = new TextField();
normalField.defaultTextFormat = fmt;
normalField.embedFonts = true;
normalField.text = "Custom font\n.text property\n&éèà# Ъ ē Ψ";

Als resultaat krijgen we volgende Flash movie. Het linkse veld is normale tekst, het rechtse html tekst.

Zoals je ziet worden de ‘gewone’ ASCII tekens en accenten getoond, de Cyrillische en Griekse tekens zijn echter in geen van beide gevallen zichtbaar.

[kml_flashembed fversion="9.0.0" movie="/wp-content/uploads/2009/01/as3-fontembedding-swf-01.swf" targetclass="flashmovie" publishmethod="dynamic" width="471" height="140"]Get Adobe Flash player

[/kml_flashembed]

Een font embedden in een tekstveld

Als we even terug de Flash IDE induiken, kunnen we een nieuw Flash AS3 bestand aanmaken. In dit bestand creëren we via de IDE een dynamisch tekstveld. In dit veld embedden we ons font via de ‘embed’-knop.
AS3 Font Embedding: Font embedden
In ons geval embedden we de volgende karakter sets:

  • Uppercase [A..Z]
  • Lowercase [a..z]
  • Numerals [0..9]
  • Punctuation [!@#%...]
  • Basic Latin
  • Latin I
  • Latin Extended A
  • Greek
  • Cyrillic

Als we tekst in dit tekstveld stoppen, zien we dat onze tekst getoond wordt, het font zit dus mee in onze movie.

Het zou natuurlijk nogal omslachtig zijn om per blok tekst een veld manueel op de stage te plaatsen. Een oplossing hiervoor is dat we ons tekstveld in een MovieClip stoppen. We hebben nu dus een MovieClip op onze stage, met daarin een TextField waarin ons font zit.

Deze MovieClip kunnen we nu van onze stage verwijderen, daar die toch nog in de library zit. Als we nu de MovieClip een klasse naam geven (bij de linkage eigenschappen) kunnen we deze exporteren.
AS3 Font Embedding: MovieClip exporteren
Merk op dat ik de Sprite klasse als base class definieer, dit omdat we in deze ‘MovieClip’ geen gebruik maken van de timeline mogelijkheden.

Nu kunnen we ons font binnen onze applicatie gebruiken, mits we deze MovieClip 1x instantieren (zodat het font mee gecompileerd wordt).

new EmbeddedFont(); // Eénmalig instantieren
var field:TextField = new TextField();
field.embedFonts = true;
field.htmlText = "<font face=\"My Font\" size=\"20\" color=\"#4e3e16\">Custom font<br>.htmlText property<br>&éèà# Ъ ē Ψ</font>";
addChild(field);

Dit is echter niet praktisch, als we bijvoorbeeld meerdere SWF bestanden gebruiken zouden we telkens deze MovieClip moeten kopiëren naar elk FLA bestand. En wat dan als we helemaal geen FLA bestanden gebruiken om te compileren (bvb. via het Flex SDK)?

Een tekstveld in een SWC

Hoe kunnen we er nu voor zorgen dat we gemakkelijk aan onze geëxporteerde Sprite kunnen, zodat deze kan geinstantieerd worden? Via een centraal SWC bestand natuurlijk.

Bij de publicatie instellingen van onze FLA kunnen we er voor kiezen om deze Flash movie ook als SWC bestand exporteren.

AS3 Font Embedding: SWC exporteren

Dit SWC bestand bevat dus onze Sprite met daarin het tekstveld en kunnen we voortaan gebruiken doorheen onze applicaties.

In ons voorbeeld hebben we de Sprite geëxporteerd als klasse EmbeddedFont. Nu kunnen we in een willekeurige Flash movie deze SWC integreren (via FDT kun je deze bijvoorbeeld aan je ’source folder’ toevoegen). De geëxporteerde klasse kan nu gebruikt worden in ons nieuw project.

Stel dat we in onze Flash applicatie een tekstveld willen, met daarin terug enkele speciale karakters, het enige wat we nu moeten doen is eenmalig een instantie aanmaken van onze geëxporteerde Sprite, zodat de compiler weet dat deze mee in de SWF moet.
Dan kunnen we doorheen alle klasses van de applicatie tekstvelden aanmaken, en ons font gebruiken.

new EmbeddedFont(); // Eénmalig instantieren
var field:TextField = new TextField();
field.embedFonts = true;
field.htmlText = "<font face=\"My Font\" size=\"20\" color=\"#4e3e16\">Custom font<br>.htmlText property<br>&éèà# Ъ ē Ψ</font>";
addChild(field);

Omdat we deze keer gebruik maken van de .htmlText property hoeven we hier geen TextFormat object aan te maken. Wil je gewoon de .text property gebruiken, dan werk je natuurlijk best wel met een TextFormat object.
Let erop dat we terug de naam van het font letterlijk moeten gebruiken, zoals je deze bijvoorbeeld in de Flash IDE ziet.

Links hebben we terug een tekstveld opgevuld via de .text property, links via de .htmlText property.

[kml_flashembed fversion="9.0.0" movie="/wp-content/uploads/2009/01/as3-fontembedding-swf-02.swf" targetclass="flashmovie" publishmethod="dynamic" width="471" height="140"]Get Adobe Flash player

[/kml_flashembed]

Meerdere SWF-files

Alles in orde zou je denken, maar wat dan als een applicatie meerdere SWF bestanden bevat?

Links hebben we hier een tekstveld binnen de SWF waarin we onze geëxporteerde EmbeddedFont klasse instantieren, het rechtse tekstveld zit in een SWF die bij runtime ingeladen wordt.

[kml_flashembed fversion="9.0.0" movie="/wp-content/uploads/2009/01/as3-fontembedding-swf-03.swf" targetclass="flashmovie" publishmethod="dynamic" width="471" height="140"]Get Adobe Flash player

[/kml_flashembed]

Ons font wordt dus niet getoond doorheen alle SWF bestanden.

Doordat we met een SWC bestand werken waarin ons font vervat zit, kunnen we dit gemakkelijk oplossen. Een gemakkelijke manier is om gewoon binnen elk SWF bestand, onze geëxporteerde klasse één maal te importeren.

In onderstaand voorbeeld hebben we terug een SWF bestand, met links een tekstveld, en rechts een ingeladen SWF bestand met ook een tekstveld. In beide SWF bestanden wordt onze klasse 1x geinstantieerd, en nu worden alle tekens getoond.

[kml_flashembed fversion="9.0.0" movie="/wp-content/uploads/2009/01/as3-fontembedding-swf-04.swf" targetclass="flashmovie" publishmethod="dynamic" width="471" height="140"]Get Adobe Flash player

[/kml_flashembed]

Conclusie

Er zijn natuurlijk meerdere manieren om fonts te gebruiken binnen Flash, en elke manier heeft zijn voor- en nadelen. Uit ervaring merken wij echter dat deze manier weinig omslachtig en zeer flexibel is. Ook vooral de ondersteuning van allerhande tekensets naar wens zorgt ervoor dat deze implementatie gemakkelijk werkt.

Website optimalisatietips: de tools

Na de vorige artikels, zou je nu moeten weten hoe je de serverconfiguratie kan optimaliseren en welke technieken aan de frontend je kan hanteren om je website performanter te maken. Nu rest ons alleen nog: hoe kan je de performatie van een website meten en eventuele problemen opsporen?

Tools om performantie te meten

Het lijkt allemaal eenvoudig: je laadt een webpagina, je start de chrono en je drukt opnieuw af wanneer de website geladen is. Alleen zijn we met die onnauwkeurige en algemene tijd niet veel. We moeten veel preciezer weten hoeveel tijd bepaalde componenten nodig hebben en achterhalen waar we verbeteringen kunnen aanbrengen.

Gelukkig bestaan er een aantal tools die dit proces voor de frontend ontwikkelaar vereenvoudigen.

IBM Page Detailer

IBM Page Detailer is een Windows tool, die in de achtergrond gegevens analyseert terwijl je surft. Aan de hand van deze tool kan je kijken hoe webpagina’s aan de browser worden bezorgd. Dit houdt ondermeer in: de timing en volgorde, bestandsgroottes, de identiteit en details van elk item op de pagina.

IBM Page Detailer moet als zelfstandige applicatie draaien en werkt dus browseronafhankelijk.

Handig bij de Page Detailer zijn de gedetailleerde waterfall reports. Aan de hand van deze charts kan je de sequentie en de timing van webobjecten analyseren. Je zal dus kunnen zien waar de typische performantieproblemen optreden. Ondermeer dat het laden van Javascript files de rest van de downloads blokkeert, of de browserlimitatie van 2 connecties per hostname.

IBM Page Detailer - Waterfall reports

Naast de grafiek, heb je ook nog toegang tot een detailscherm, met daarop meer informatie over elk object op de pagina. Je kan bovendien zelf in de tabel definiëren welke gegevens moeten weergegeven worden.

IBM Page Detailer details

Download IBM Page Detailer

Firebug

Met deze onmisbare extensie ben je ondermeer in staat om te meten wat er precies allemaal in Firefox gebeurt. Firebug beschikt onder de tab Net ook over waterfall reports en basisgegevens van bestandsgroottes, requests en de tijd die nodig is om de bestanden binnen te halen. Wanneer je met de muis even blijft hangen over items, krijg je een preview van dat element te zien.

Firebug waterfall report

Firebug toont echter geen details van elk van de requests. De response time, delivery time en zelfs de tijd om JavaScript uit te voeren worden gecombineerd.

Download Firebug

YSlow (Firebug extension)

YSlow is een Firebug uitbreiding, ontwikkeld door Yahoo!. Hiermee kan je een website testen tegen de 14 performantieregels, toegelicht in het boek High Performance Web Sites. YSlow analyseert je website aan de hand van Firebug’s Net Panel in combinatie met het overlopen van de DOM tree. Het voorziet de website dan van een score (Performance Grade).

Je kan op elk van de items klikken om meer details te ervan te bekijken.

YSlow performance report

Onder stats vinden we dan weer een handige grafiek waarop je de empty en primed cache met elkaar kan vergelijken.

YSlow stats

De components tab geeft een overzicht van alle componenten die ingeladen werden, met onder andere vermelding van type, url, response time, bestandsgrootte, ETag,…

YSlow components view

Zeer praktisch is ook de print view (onder Tools), de ultieme checklist om mee te starten.

Download YSlow

AOL Pagetest

Deze tool werd oorspronkelijk door AOL ontwikkeld voor interne performance testing, maar enkele maanden geleden werd de tool gereleased als open source. Het is momenteel de applicatie met de meeste features.

Bij AOL Pagetest worden ook waterfall reports gegenereerd, maar deze zijn voorzien van tijdslijn bovenaan, genummerde componenten en markeringen voor belangrijke sleutelmomenten bij de rendering van de pagina.

Elke request wordt visueel in een aantal kleuren voorgesteld en dit iets eleganter dan bij IBM Page Detailer.

AOL Pagetest chart

Naast de charts heb je ook nog toegang tot een handige checklist view, die je componenten test tegen een aantal optimalisatieregels (vergelijkbaar met die van YSlow).

AOL Pagetest checklist

Bij AOL Pagetest kan je optimalisatierapporten exporteren (in .txt files), of de charts en checklists als afbeelding (.png)

Pagetest is enkel beschikbaar voor Internet Explorer.
Download AOL Pagetest

Er bestaat tevens een online versie: Pagetest webpage performance test

Zelf de websiteperformatie testen

Nu je weet welke tools je kan gebruiken, is het belangrijk te weten wat je moet doen om deze zo waarheidsgetrouw te gebruiken.

We willen uiteraard zowel testen voor de bezoekers die nog nooit op de website hebben gesurfd, als de terugkerende bezoekers.

Flush DNS

Wanneer een browser een domeinnaam voor het eerst tegenkomt, moet hij een DNS lookup uitvoeren, om het IP adres van die domeinnaam te achterhalen. Gemiddeld duurt dit zo’n 10 tot 20 ms.

Dat IP adres wordt dan lokaal gecached. Dus voor je de website op performantie test, kan je deze cache best legen.

Windows: Start -> run -> ipconfig /flushdns
Mac OS X: Terminal -> lookupd -flushcache

Browsercache legen en cookies wissen

Om te verzekeren dat alle bestanden moeten gedownload worden, wis je best de cache en cookies.

Internet Explorer 7:
Selecteer Tools -> Internet Options -> Delete -> Delete Files
Selecteer Tools -> Internet Options -> Delete -> Delete Cookies

Internet Explorer 6:
Selecteer Tools -> Internet Options -> Delete Files
Selecteer Tools -> Internet Options -> Delete Cookies

Firefox:
Selecteer Tools -> Clear Private Date -> Check Cache, Cookies -> Clear Private Data Now

Connectiesnelheden simuleren

Als webontwikkelaars verschillen wij meestal van de doorsnee websitebezoekers: zo beschikken wij over recente computers en snelle internetverbindingen. Daarom zou het wel handig zijn als we bepaalde parameters kunnen simuleren.

Charles

Charles is een web debugging proxy. Via Charles kan je ondermeer toezicht houden op al de HTTP traffiek tussen jouw computer en het internet, dus zowel requests, responses als de HTTP headers zelf. Bovendien kan je verschillende connectiesnelheden simuleren en bewust vertragingen introduceren (round-trip latencies).

Snelheid simuleren en limiteren via Charles

Charles is een Java applicatie en is zowel beschikbaar voor Windows, Mac OS X als Linux / Unix.
Download Charles

En tot slot…

Zo, deze reeks van artikels over website (en dan vooral frontend) optimalisatie zit er bijna op. Ik wil jullie om af te sluiten nog enkele handige resources meegeven, voor zij wiens honger nog niet helemaal gestild is.

Interessante websites

Aanbevolen boeken

Podcasts en presentaties:

Website optimalisatietips: de frontend

Na het optimaliseren van de serverinstellingen is het deze keer de beurt aan de optimalisatietechnieken die je kan toepassen op de frontend, in je HTML, CSS en Javascript.

In het inleidende artikel haalde ik enkele cijfers aan: 80 à 90% van de snelheid van een website wordt bepaald bij het ophalen van de verschillende componenten. Dit ophalen van assets gebeurt aan de hand van HTTP requests.

Achtergrondinformatie

In de RFC 2616 staat het volgende te lezen:

Clients that use persistent connections SHOULD limit the number of simultaneous connections that they maintain to a given server. A single-user client SHOULD NOT maintain more than 2 connections with any server or proxy.

De eerste draft van deze RFC dateert van januari 1997 en toen was die connectielimiet nog te verantwoorden, omdat breedbandconnecties toen heel zeldzaam waren.

To find a decent balance, IE and Firefox by default restrict users to 6 connections total and 2 connections per host for HTTP 1.1 connections.

Omwille van historische redenen wordt standaard in browsers het aantal simultane connecties naar dezelfde host beperkt tot 2. De geavanceerde browsergebruiker kan die waarden wel aanpassen, maar de modale bezoeker van je website zit dus met die limiet van 2 connecties per host.

Opmerking: Internet Explorer 8 zal de limiet optrekken van 2 naar 6 connecties per host.

Downloaden van componenten

De performantie van je website hangt, zoals je nu al zal doorhebben, grotendeels af van het aantal componenten op de pagina.

Bij een standaard browserinstallatie, downloaden die componenten parallel in groepjes van 2 per hostnaam.

Gelukkig kan je deze beperking omzeilen en dit door de componenten te spreiden over 2 hostnamen. Zo kan je de response time dus halveren.

Je zou hier nog verder in kunnen gaan en bijvoorbeeld 4 of meer hostnames gebruiken, maar omwille van de vertraging die optreedt bij DNS lookups, kan dit dan weer een negatieve impact hebben op de performantie. Het kan in sommige gevallen de server CPU, bandbreedte of aantal simultane connecties belasten.

Volgens onderzoek van Yahoo! is het spreiden van componenten over 2 tot 4 hostnamen ideaal voor performantie.

Verschillende grote sites plaatsen hun statische componenten onder een andere hostname: Yahoo! op yimg.com, Youtube op ytimg.com en Amazon op images-amazon.com. Je hoeft zelfs geen afzonderlijke domeinnaam aan te kopen, het kan evengoed met een subdomein.

Ik haalde de techniek ook al aan in het vorige artikel uit de reeks met optimalisatietips, meerbepaald in de sectie over cookies:

Bij de meeste websites staan de cookies gewoon op de root (/), wat die cookie dan voor elk object zet. Daarom is het aan te raden om je statische content op een aparte domein, of subdomein te plaatsen, waarop dan geen cookies worden geplaatst.

Wij hebben er een gewoonte van gemaakt om de statische content (CSS, Javascript files, afbeeldingen, …) onder een subdomein te plaatsen. Meestal iets als static.example.be.

Minder HTTP Requests

Je kan de performantie van je website dus drastisch verhogen door het aantal HTTP requests tot een minimum te beperken.

In het vorige artikel legde ik uit hoe je via enkele serveraanpassingen componenten kan cachen voor hergebruik… Maar ook op de frontend kan je nog enkele performantie verhogende technieken toepassen.

CSS Sprites

Bij CSS Sprites worden verschillende afbeeldingen gecombineerd in 1 grotere afbeelding. Voorbeelden vind je op verschillende sites, waaronder die van BBC (voorbeeld), Yahoo (voorbeeld), Google (voorbeeld), … Met CSS sprites kan je dus al een groot aantal requests reduceren tot 1 of slechts enkele requests.

Een bijkomend voordeel van CSS sprites is dat de gecombineerde afbeelding, in de meeste gevallen ook kleiner in bestandsgrootte is dan de optelsom van de verschillende afzonderlijke groottes en dit doordat er minder kleurentabellen en formaatinformatie moet opgeslagen worden.

Op complexe websites met een groot kleurenpallet kan je dan opteren om eventueel meerdere sprites te gebruiken.

Zo heeft het ontwikkelingsteam van de BBC website 60 externe afbeeldingen kunnen samenvoegen tot 3 sprites: 1 voor achtergronden, 1 voor kleurverlopen en 1 voor de afgeronde hoekjes.

Combineren van scripts en stylesheets

De meeste websites gebruiken meerdere scripts of stylesheet documenten. Vaak kunnen deze zonder probleem gecombineerd worden: dus alle Javascript files combineren tot 1 script file, en alle CSS files tot 1 stylesheet document. Uitzonderingen zijn natuurlijk de print stylesheet en de stylesheets specifiek voor Internet Explorer (via conditional comments).

Je kan, zoals ons, een onderscheid maken tussen development en productie omgevingen en blijven werken met afzonderlijke files tijdens het ontwikkelen van de website en deze dan op de productieserver samenvoegen, eventueel via een geautomatiseerd server-side script.

Comprimeren van CSS en Javascript files

Je kan HTTP compressie toepassen op serverniveau, om bestandsgroottes in realtime te verkleinen, maar je kan je ook baseren op minifying. Hierbij worden onnodige karakters uit de files verwijderd. Het gaat dan om commentaarregels, spaties, tabinsprongen, newlines, … Het resultaat is een compactere (maar minder leesbare) file. Ideaal dus voor productieomgevingen.

Obfuscation gaat als techniek nog verder, waarbij het moeilijker wordt om de source files correct te interpreteren. Het vervangt functienamen en variabelen door kortere karakters (a, b, c, …). Deze compressiemethode kan echter ook bugs in je code introduceren. Wees dus voorzichtig bij gebruik.

Enkele populaire tools om je code te minimaliseren zijn: JSMin en onze persoonlijke favoriet, YUICompressor.

Onze methodiek bij Javascript files is: de namen van variabelen en functies zo compact mogelijk te houden en dan de verschillende files via een PHP script samen te voegen, om daarna te comprimeren (via de minify techniek) en dan via HTTP compressie in de browser te bezorgen.

Gemiddeld kan je met de minify techniek op de bestandsgrootte zo’n 20% besparen. Als je het combineert met HTTP compressie kan je er vaak nog eens een extra 5% van krijgen.

CSS optimalisatie

We kennen ondertussen allemaal het belang van CSS. Maar toch kan je ook met CSS nog de mist in gaan. Vooral bij grotere sites is het soms moeilijk om het aantal CSS regels beperkt te houden. Vandaar deze quote van Nate Koechley:

We spend a lot of time on familiarizing ourselves with all the properties and values of CSS, but the power of professional CSS lies in choosing the right selectors.

Het komt er dus op neer om je CSS compact te houden, ondermeer door het kiezen van de juiste selectors.

Je kan je CSS ook optimaliseren door:

  • Geen te lange namen te kiezen bij je ids en classes
  • Shorthand CSS properties toepassen
  • Modulaire aanpak volgen en groeperen van gemeenschappelijke kenmerken

Gebruik geen @import

Ondanks het gemak van het importeren van CSS via @import, is het ten stelligste af te raden. Zelfs al staat de @import regel helemaal bovenaan de HTML pagina, dan nog zullen die files pas als allerlaatste ingeladen worden. Het verhindert dus de vlotte rendering van de website.

Het laden van de externe CSS files gebeurt best via de <link> tag in de head van het document.

Javascript: plaats je externe scripttags niet in de head

In tegenstelling tot externe CSS files, plaats je scripts best onderaan de pagina. Vele developers doen dit net in de head van het HTML document, maar dat heeft een negatieve inpact op de performantie.

Tijdens het laden van zo’n script wordt namelijk het downloaden in parallel tijdelijk geblokkeerd. De reden hiervoor is dat het script document.write kan bevatten, waardoor de structuur van de HTML nog voor het renderen kan wijzigen.

Een andere reden voor dit gedrag is omdat browsers willen vermijden dat het ene script onbedoeld voor het andere wordt geladen. Hierdoor zouden Javascript errors kunnen optreden, wanneer de ene file afhankelijk is van de andere.

Tijdens het downloaden van Javascript files, worden er dus geen andere componenten gedownload… Als je wil dat de website snel wordt weergegeven, dan plaats je dus best Javascript files onderaan de pagina.

Deferred scripts

Je zou eventueel het attribuut defer kunnen toevoegen aan je script in de head, waarmee je aangeeft dat die file geen document.write zal bevatten, maar helaas werkt dat niet in Firefox en dus eigenlijk is dat geen optie.

Preloading

Door te preloaden kan je optimaal gebruik maken van de tijd nadat de browser alle huidige componenten heeft ingeladen, om nieuwe te downloaden, die je misschien nodig hebt op volgende pagina’s.

We onderscheiden 3 scenario’s waarin je assets kan preloaden:

  1. Unconditional preload:

    In dit geval worden de assets altijd ingeladen wanneer je bepaalde een pagina bezoekt. Een goed voorbeeld hiervan is de homepage van Google. Hierop downloaden ze de sprite met de afbeeldingen voor de resultaten pagina van zodra de homepage klaar is met laden (onLoad event). Wanneer de gebruikers dus iets zoekt en op de resultatenpagina terecht komt, dan zit de sprite al in de browsercache.

  2. Conditional preload:

    Hier start je het downloaden van sommige componenten of scripts van zodra de gebruiker bepaalde controls of widgets begint te gebruiken. Voorbeelden hiervan vind je op de Yahoo! homepage.

  3. Anticipated preload:

    Bij het redesignen van een website kan je een tijdje op voorhand de stylesheets, scripts of afbeeldingen van het nieuwe design laten downloaden. Wanneer de nieuwe site dan gelanceerd wordt, blijft hij toch snel presteren, omdat de componenten in de browsercache van de trouwe bezoekers zullen zitten.

En verder

Tot zover dus de theorie. In het volgende artikel ga ik met concrete voorbeelden en cijfers aantonen hoeveel voordeel je kan halen uit caching, het beperken van het aantal HTTP requests, de CSS en Javascript technieken, … En vooral met welke tools je de performantie kan meten, om zelf ook aan de slag te gaan. Stay tuned!

Website optimalisatietips: een introductie

Op @media 2008 hebben Vincent en ik de presentatie gezien van Nate Koechley, frontend engineer bij Yahoo!. Tijdens deze uiteenzetting zijn een hele reeks tips aan bod gekomen, over hoe je nu precies een website kan optimaliseren.

Het omzetten van de webdesigns naar HTML templates met CSS en Javascript interactie werd vroeger voornamelijk uitgevoerd door de webdesigner en de webprogrammeur.

Omwille van de groeiende complexiteit van projecten en de hogere eisen voor websites worden deze taken nu steeds vaker uitgevoerd door de zogenaamde frontend developers of frontend engineers, de term die ze bij Yahoo! gebruiken.

Frontend developer

Kort samengevat bestaat de taak van de frontend developer erin de browser te zeggen hoe een website moet weergegeven worden. Klinkt eenvoudig. In de praktijk moet je rekening houden met de verschillende platformen, browsers, verschillende renderingengines per browser, versies van browsers, … De frontend developer moet niet alleen de specificaties kennen, maar ook hoe browsers deze interpreteren.

Het volstaan al lang niet meer om mooie websites te maken. Ze moeten ook functioneel zijn, toegankelijk, goed gepositioneerd in zoekmachines en veel te vaak onderschat: performant.

Website optimalisatie

Wanneer we aan website optimalisatie denken, dan ging in het verleden vaak de aandacht naar backend optimalisatie: database queries, indexes, memory management,… In de realiteit dragen deze backend optimalisaties gemiddeld maar voor 10 à 20% toe aan de snelheid van een website. De overige 80 – 90% wordt besteed ná het ophalen van de HTML pagina, dus bij de verschillende requests voor externe componenten én het downloaden ervan.

Er is dus een groot onderscheid te maken tussen 2 soorten performantie:

  • System efficiency performance (voornamelijk backend)
  • Response time performance (dus frontend)

Omdat de frontend in grote mate verantwoordelijk is voor de snelheid van de website, is het dus ook de taak van de frontend developer om de response time van een website zo laag mogelijk te houden.

Hoe je dat precies kan doen, licht ik de komende weken toe in een reeks artikels over website optimalisatie, met volgende onderwerpen: