In deze nieuwe reeks artikels geven we in het totaal 10 tips voor een zeer goede webshop. Als Marlon hebben we al heel wat webshops bedacht, ontworpen en gebouwd. Geen bandwerk bij ons. We maken van elke shop iets uniek, met een eigen gezicht en het resultaat is altijd van een zeer hoge kwaliteit. Dus we mogen stellen — ok, toegegeven, dit klinkt arrogant — dat we stilaan weten waarover we het hebben.
The money will roll right in
Ga echter niet denken dat deze tips een perfect draaiende en geld binnenrijvende webwinkel garanderen. Zo werkt het helemaal niet!
Een goede webshop heeft om te starten een aantal basisvereisten, die keihard voor zich spreken, maar die we toch even kort opsommen:
- een reeks straffe producten;
- aan exact de juiste prijs;
- ideaal gepromoot;
- met een fenomenale klantendienst als ondersteuning.
Zonder deze fundering mag je webshop nog zo professioneel gemaakt zijn, zo mooi ogen of zo state-of-the-art zijn, je bereikt er niet zoveel mee. De vier puntjes hierboven, dat is waar je aan moet voldoen voor je ook maar aan de rest begint te denken.
Want dat is waar we het in deze artikels over gaan hebben: the icing on the cake. Die kleine dingen die het af maken. Die eenvoudige zaken die aandacht vergen, werk vereisen, met als resultaat dat jouw webshop nog beter wordt dan die al is.
Tip 1: De ervaring van het online shoppen
Elke winkel die zichzelf respecteert — en we hebben het hier even over echte winkels uit baksteen, met deuren en ramen, en in een straat; je weet wel, dat oud soort winkels — wil ervoor zorgen dat de klant iets ervaart. Sommige winkels zijn zeer praktisch ingericht, denk maar aan de Colruyt warenhuizen. De ervaring en sfeer in die winkels is quasi onbestaand. Maar dat is ook niet erg.
Andere winkels daarentegen gaan ver de andere richting uit: de etalage, de muziek, de belichting, hoe het personeel gekleed is (of niet gekleed is): aan alles wordt aandacht geschonken. En daar eindigt het niet: de verpakking, het prijskaartje, de kapstokken, tot en met de zak die je mee neemt naar buiten: dat allemaal maakt deel uit van een merk, van een ervaring, van een sfeer. Een identiteit.
Bij een webshop is dit niet anders. We hebben vaak het idee dat iemand die online winkelt een vrij praktische actie aan het uitvoeren is. Ah ja! Ze zitten aan een computer, hét saaie en technische werkinstrument bij uitstek! Dat is een foute redenering. Natuurlijk heeft de webshop een aantal zeer praktische voordelen tegenover een gewone winkel, en natuurlijk moet de webshop uitmunten in gebruiksvriendelijkheid. Maar dat betekent niet dat we een webshop mogen herleiden tot een praktische tool. Uw webshop moet op alle vlakken ook nog haar identiteit uitstralen.
De aankoop start vroeger en duurt langer dan je denkt
Als we nadenken over welke stappen doorlopen worden door iemand die in contact komt met je webshop, dan komen we ruwweg tot deze lijst:
- eerste kennismaking: een artikel lezen, je naam lezen (en al dan niet onthouden; of al dan niet weten hoe je die juist schrijft); of een vriend of vriendin die het er over heeft en zeer eerlijk zal zijn in het delen van zijn of haar ervaring; of een zoekresultaat in Google;
- je website bezoeken: welke kleuren gebruik je, welke afbeeldingen;
- nog straffer: welke bewoording hanteer je, hoe beschrijf je jouw producten, hoe praat je tegen je bezoeker;
- hoe loopt de bestelling: stroef, de ene drempel na de ander; of gaat alles vlot en is alles ongelooflijk duidelijk;
Let op je taal, jongen!
Kortom, stap één is je eigen stijl ontwikkelen. En dat is niet enkel visueel. Ook je taalgebruik is van belang. Het grootste gevaar is dat je webshop als een machine gaat klinken. Een aanvang als ‘Gelieve een… ‘ of een beschrijving als ‘Kurkentrekker die er uit ziet als een stier’ geeft niets van je persoonlijkheid of stijl weer.
Dus het start al met de productomschrijving. Webshop Lisa Mille schrijft bij elk product een haast persoonlijke beschrijving. Zelfs een eikokertje krijgt een mooi zelf geschreven en persoonlijke beschrijving. Zomaar de tekst van de leverancier overnemen is echt uit den boze.

Lisa Mille webshop: zelfs een eikokertje krijgt een persoonlijke beschrijving
Bij De Kleine Zebra trekken ze dit door in de manier waarop ze hun categorieën noemen, net als Monsters with an Attitude. Hier geen ‘Badkamer’ maar ‘splish splash‘ of geen ‘Speelgoed’ maar ‘Ravot’ en ‘Kot op stelten’

De naam van een categorie bij Monsters with an Attitude is allesbehalve gewoontjes.
Bedanken en bevestigen, maar niet als een machine
En dan? Wat na de bestelling? Dan denken veel webshops dat het is afgelopen. Dan begint het pas! Weet de klant wanneer het pakje komt? Kan de klant het pakje volgen? Stuur je een degelijk bevestigingsmail uit? Wat staat daar in? Spreek je de klant persoonlijk aan of klinkt alles zeer technisch? Het geld is binnen en het lijkt er op dat alles beklonken is: de bestelling is namelijk geplaatst. Ook vlak na die stap moet je in contact blijven, de ervaring moet blijvend zijn. Je mag niet verzanden in formeel en technisch de bestelling af te handelen. Zo hebben we voor de website van Fuchsia-kwekerij Katrien Michiels een bevestigingsmail ontworpen waar een collage staat van de foto’s van de bloemen die je besteld hebt. Zo krijg je na je bestelling een mooi visueel overzicht van wat je kocht. Voor haar klanten — die echt gepassioneerde fuchsia-fans zijn — is het belangrijk dat ze na hun bestelling een visuele bevestiging hebben, waarmee ze bijvoorbeeld aan vrienden of familie in één oogopslag hun mooie bestelling kunnen tonen.
Verpakking, verpakking, verpakking
Is het dan afgelopen, eenmaal je mooi en persoonlijk bevestigd hebt? Neen, nog steeds niet. Want wat is allesbepalend bij het online kopen: het ontvangen van het product zelf. Is de doos een saaie bruine kartonnen ding vol gaten en blutsen, die ook nog eens lelijk is dicht gekleefd? Of is het een doos met een eigen grafiek? De Kleine Zebra levert aan in mooi bedrukte dozen. Zelf de sticker met het adres is ontworpen. De aankoop van een product bij hen blijft dus doorlopen tot het openen van het pakje. Het is zelfs zo dat we die dozen meermaals bij mensen thuis zien staan. Ze gooien die niet weg of gebruiken die niet om oude kranten in te verzamelen. Sommige klanten gebruiken die als volwaardige opbergdozen die mogen gezien worden.

De mooie verpakkingen van De Kleine Zebra
Verrassing!
Zit er een verrassing in de doos? Een klein extraatje die de klant blij maakt? Vraag je achteraf om feedback, op een zeer persoonlijke manier? Monsters with an Attitude legt in al haar pakjes die ze opsturen een cadeautje: een klein stoffen popje. Een kleine attentie die bij vele klanten een leuke extra is en mensen een positief beeld geeft van de webshop en het online bestellen.

Monsters with an Attitude stopt een extra popje in elke verpakking
Maar hou het sober
Belangrijk is wel dat die ervaring niks in de weg staat. Een achtergrondmuziekje lijkt iets te zijn dat de sfeer van een webwinkel versterkt, maar werkt voor de overgrote meerderheid van de mensen eerder irritatie op. Een splash-pagina, een soort homepage voor de homepage, waar je in één beeld je sfeer wil oproepen: nutteloos en een drempel vol goede bedoelingen maar met een tegengesteld effect.
Tip 2: Persoonlijkheid: ge zijt wie ge zijt
We hebben het hiernet al vaak gezegd, en ik heb zelfs al 7 maal het woord ‘persoonlijk’ of een variant gebruikt: hoe technische een website ook lijkt (een stuk code, bekeken op een scherm, aan een computer), je webwinkel moet persoonlijkheid uitstralen in elke stap.
Je zal merken dat elk van de webshops die we gebouwd hebben dat doet. Of de meeste toch.
Geef je webshop een gezicht
De Kleine Zebra maakt elk jaar opnieuw een foto van de drie zussen die de winkel hebben opgestart, samen het hun kinderen. Wij vinden dit zo’n mooi voorbeeld. Deze dames zeggen en tonen dat ze echt zijn, dat ze net dezelfde personen zijn als hun klanten: mama’s op zoek naar mooie spullen voor hun kinderen. Ze maken ook werk van een jaarlijks aangepaste beschrijving van hun verhaal.

De jaarlijkse aangepaste 'Wie zijn we' pagina van De Kleine Zebra.
Lisa Mille spreekt de bezoeker ook zeer persoonlijk aan. Om te beginnen in de manier waarop ze de producten op een eigen manier beschrijft (zie hierboven), maar ook door een kleine foto met haar kinderen op elke pagina van de website te zetten. Op haar Facebook pagina geeft ze ook een eerlijke inkijk op haar werk als mama die een webshop runt.

Persoonlijkheid is je klanten ook inkijk geven op wat er zich achter de schermen afspeelt.
Ook voor de kwekerij Fuchsia Michiels maakten we een punt van dat principe: Katrien Michiels, die de kwekerij van haar vader overnam, is in haar sector een naam en een gezicht. Het is daarom essentieel dat ze onmiddellijk op de homepagina staat. Iedereen in die sector kent haar. En op die manier geeft ze ook aan hoe authentiek de website is.

Katrien Michiels spreekt haar klanten rechtstreeks aan. Iedereen in haar sector kent haar. Persoonlijkheid ten top!
Vriendelijk ‘dank u’ zeggen
Maar persoonlijkheid kan ook schuilen in een klein hoekje. Zo leerden we van Plan België het belang van eenvoudigweg ‘bedankt’ te zeggen. Na een bestelling je klant bedanken, daar heel eerlijk en persoonlijk in zijn, geeft je webshop heel wat authenticiteit. Of je kan een eigen persoonlijkheid weergeven door een bepaalde filosofie te hanteren, zoals de bio, eco & fair-trade webshop Villa Kakelbont dat doet.

Villa Kakelbont, een webwinkel met een 'Onze filosofie' pagina.
Giveaways
Wat te onthouden?
- Get the basics right: product, prijs, promoten, customer service; die moeten allemaal top-notch zijn;
- Zorg voor een echte ervaring: van copywriting (de lange teksten & de short-copy), tot stijl, tot verpakking; verras je klanten; maak hen blij; wees speciaal;
- Zeg ‘Dank u’, wees vriendelijk en persoonlijk; maak van je webshop iets met een gezicht en kleef er zelfs letterlijk je eigen gezicht op; zorg voor een kijk achter de schermen. Wees dus levensecht;
- En overdrijf niet, hou het subtiel;
Volgende keer…
In deel 2 zullen we het hebben over meer praktische zaken zoals ‘Duidelijkheid’ en ‘Bereikbaarheid’. Want naast een gevoel en sfeer moet je webshop vooral ook vertrouwen uitstralen.
In een vorige post hadden we het over custom fonts en speciale karakters in Flash. Maar welke karakters embedden we nu best?
Bij het ontwikkelen van onze projecten houden we zoveel mogelijk rekening met de gebruiksvriendelijkheid. Het is dus niet meer dan logisch dat de eindgebruiker een website of applicatie voorgeschoteld krijgt in zijn of haar eigen taal, of tenminste een begrijpbare taal.
Voor sommige projecten vereist dit het ondersteunen van een ander alfabet, zoals bvb. het Cyrillisch of het Grieks.

Om karakters in een movie te embedden, hebben we in de Flash IDE (in dit geval de CS4 versie), een knop bij de eigenschappen van een tekstvak. Deze opent een venster waarbij we 1 of meerdere karaktersets kunnen aanduiden, of zelfs aparte karakters kunnen intikken die we mee willen embedden in onze file.
In dit venster kunnen we duidelijk zien welke karakters een bepaalde set omvat.
Als onze tekst echter in meerdere, vreemde talen moet getoond worden, is het soms onduidelijk welke karakter sets we juist moeten embedden. Om dit op te lossen kunnen we op deze website een XML bestand laten genereren, aan de hand van een tekstbestand waarin alle benodigde karakters staan.
Dit XML bestand kan gebruikt worden als UnicodeTable.xml, of kan de bestaande UnicodeTable.xml aanvullen (aan te raden). UnicodeTable.xml is een bestand dat door de Flash IDE gebruikt wordt, en dat alle karakter sets definieert die dan in het embed-venster komen (zie bovenstaande screenshot).
De door Flash gebruikte UnicodeTable.xml kun je op deze locatie terugvinden:
- Windows Vista:
<boot drive>\Users\<gebruiker>\AppData\Local\Adobe\Flash <versie>\<taal>\Configuration\FontEmbedding\
- Windows XP:
<boot drive>\Documents and Settings\<gebruiker>\Local Settings\Application Data\Adobe\Flash <versie>\<taal>\Configuration\FontEmbedding\
- Mac:
<boot drive>/<gebruiker>/Library/Application Support/Adobe/Flash <versie>/<taal>/Configuration/FontEmbedding/
Voor je UnicodeTable.xml wijzigt, neem je best een backup.
Zoals je kan zien staat elke karakterset in deze XML gedefinieerd, d.m.v. een node glyphRange. Deze node heeft 2 attributen, namelijk name en id. De id node wordt niet visueel getoond in de IDE, maar moet wel een unieke waarde bevatten. De waarde van de name node is wat we te zien krijgen in ons embed-venster, geef je eigen karakterset dus best een logische naam.
Welke tekens juist bij een bepaalde set horen kiezen we aan de hand van range nodes. Elke glyphRange node kan één of meerdere van die range nodes omvatten. Een range node definieert een tekenreeks, aan de hand van de <a href=”http://en.wikipedia.org/wiki/Unicode” title=”Unicode op Wikipedia”>unicode</a> waarde van het 1e en laatste karakter in die reeks. Als voorbeeld gebruiken we de voorgedefinieerde karakter set ‘Numerals [0..9]‘
<glyphRange name="Numerals [0..9] " id="3" >
<range min="0x0030" max ="0x0039" />
<range min="0x002E" max ="0x002E" />
</glyphRange>
Als we één van de vele unicode tabellen bekijken, kunnen we aflezen dat de unicode waarde 0x0030 het cijfer 0 voorstelt, 0x0039 staat voor het cijfer 9, en omdat we een range definieren zullen alle karakters tussen deze 2 ook binnen deze reeks vallen. Zoals we zien is het ook mogelijk om een enkel karakter als reeks te definiëren, dit gebeurt hier met de punt (.) die 0x002E als unicode waarde heeft.
Bij wijze van voorbeeld heb ik een karakterset gemaakt die ons Latijns alfabet met alle speciale tekens omvat, alsook het Cyrillisch en Grieks alfabet. De regels in commentaar zijn dubbele regels.
<glyphRange name="Latin Greek Cyrillic " id="27">
<!-- Uppercase [A..Z] -->
<range min="0x0020" max ="0x0020" />
<range min="0x0041" max ="0x005A" />
<!-- Lowercase [a..z] -->
<!-- <range min="0x0020" max ="0x0020" /> -->
<range min="0x0061" max ="0x007A" />
<!-- Numerals [0..9] -->
<range min="0x0030" max ="0x0039" />
<range min="0x002E" max ="0x002E" />
<!-- Punctuation [!@#%...] -->
<range min="0x0020" max ="0x002F" />
<range min="0x003A" max ="0x0040" />
<range min="0x005B" max ="0x0060" />
<range min="0x007B" max ="0x007E" />
<range min="0x02c6" max ="0x02c6" />
<range min="0x02dc" max ="0x02dc" />
<range min="0x2013" max ="0x2014" />
<range min="0x2018" max ="0x201a" />
<range min="0x201c" max ="0x201e" />
<range min="0x2020" max ="0x2022" />
<range min="0x2026" max ="0x2026" />
<range min="0x2030" max ="0x2030" />
<range min="0x2039" max ="0x203a" />
<range min="0x20ac" max ="0x20ac" />
<range min="0x2122" max ="0x2122" />
<!-- Basic Latin -->
<range min="0x0020" max ="0x002F" />
<range min="0x0030" max ="0x0039" />
<range min="0x003A" max ="0x0040" />
<range min="0x0041" max ="0x005A" />
<range min="0x005B" max ="0x0060" />
<range min="0x0061" max ="0x007A" />
<range min="0x007B" max ="0x007E" />
<!-- Latin I -->
<!-- <range min="0x0020" max ="0x0020" /> -->
<range min="0x00A1" max ="0x00FF" />
<range min="0x2000" max ="0x206F" />
<range min="0x20A0" max ="0x20CF" />
<range min="0x2100" max ="0x2183" />
<!-- Latin Extended A -->
<range min="0x0100" max ="0x01FF" />
<!-- <range min="0x2000" max ="0x206F" /> -->
<range min="0x20A0" max ="0x20CF" />
<range min="0x2100" max ="0x2183" />
<!-- Greek -->
<range min="0x0374" max ="0x03F2" />
<range min="0x1F00" max ="0x1FFE" />
<range min="0x2000" max ="0x206f" />
<range min="0x20A0" max ="0x20CF" />
<range min="0x2100" max ="0x2183" />
<!-- Cyrillic -->
<range min="0x0400" max ="0x04CE" />
<!-- <range min="0x2000" max ="0x206f" /> -->
<range min="0x20A0" max ="0x20CF" />
<range min="0x2100" max ="0x2183" />
</glyphRange>
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.
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"]
[/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.

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.

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.

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"]
[/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"]
[/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"]
[/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.
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:
-
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.
-
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.
-
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!
- Toegevoegd op: 14 November 2008
- Geschreven door: davy
- Tags: CSS, CSS sprites, frontend, HTTP request, Javascript, minify, optimalisatie, preloading, technieken, tips, website
In dit artikel uit de reeks met website optimalisatietips, ga ik toelichten welke aanpassingen je kan voorzien in de Apache serverconfiguratie, om een betere performantie te bekomen.
Cachen van componenten
Het cachen van componenten, is het tijdelijk opslaan van vaak geraadpleegde website elementen, op de lokale harde schijf van de persoon die de website bezoekt of op een proxyserver van een bedrijf of ISP. Het gaat dan in de eerste plaats om afbeeldingen, CSS en Javascript files.
Doordat deze files niet opnieuw van de server moeten gedownload worden, kunnen het aantal HTTP requests beperkt worden en moeten er minder DNS Lookups gebeuren (die typisch 20-120 milliseconden in beslag nemen).
Empty Cache en Primed Cache
We maken een onderscheid tussen een empty cache en een primed cache. Empty cache slaat op een lege cache, relatief tegenover jouw website. De bezoeker heeft dus van jouw pagina’s geen componenten in cache.
Bij een primed cache zitten al jouw componenten in de cache van de gebruiker.
Volgens onderzoek van Yahoo! wordt 62% tot 95% van de tijd gespendeerd aan het maken van HTTP requests. Als je dus een druk bezochte website hebt, met veel terugkerende bezoekers, dan haal je veel voordeel uit caching.
Er bestaan 3 manieren om te cachen:
Wij richten ons in dit artikel tot de 3de manier.
Expires Header en mod_deflate
Als je een Expires Header gebruikt die ver in de toekomst ligt, dan kan je verzekeren dat het element gecached wordt door browsers. Een Expire Header vertelt de browser namelijk vanaf wanneer het element opnieuw van op de server ingeladen moet worden.
Om caching te activeren op een Apache 2.0 server, moet je volgende modules inschakelen:
LoadModule expires_module modules/mod_expires.so
LoadModule headers_module modules/mod_headers.so
Cachen aan de hand van extensie
Een snelle manier om bestanden te cachen, is aan de hand van de extensie. Eerst dien je mod_expires aan te zetten:
ExpiresActive On
Caching voor je site inschakelen:
<Directory "/var/www/htdocs" />
Options FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
Allow from all
ExpiresDefault A3600
<FilesMatch "\.html$">
ExpiresDefault A86400
</FilesMatch>
<FilesMatch "\.(gif|jpg|png|js|css)$">
ExpiresDefault A31536000
</FilesMatch>
</Directory>
ExpiresDefault A3600 zet de default expiry time op 3600 seconden (of 1 uur) na toegang tot de file. De HTML files zullen maximum 1 dag (86400 seconden) gecached worden, en de assets uit de 2de FileMatch maximum 1 jaar (31536000 seconden).
Cachen aan de hand van MIME type
Je kan de caching voor files ook specifiëren aan de hand van het MIME type.
<VirtualHost *>
...
ExpiresActive On
ExpiresDefault "access plus 3600 seconds"
<Directory "/var/www/htdocs" />
Options FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
Allow from all
ExpiresByType text/html "access plus 1 day"
ExpiresByType text/css "access plus 1 year"
ExpiresByType text/javascript "access plus 1 year"
</Directory>
</VirtualHost>
Dankzij de AllowOverride All kan je de caching ook bepalen op mapniveau, via een .htaccess file:
<FilesMatch "\.(css)$">
Header set Cache-Control "max-age=604800, public"
</FilesMatch>
Meer details kan je lezen op:
http://httpd.apache.org/docs/2.2/mod/mod_expires.html
Versioneren van componenten
Als de componenten een lange tijd in de cache van de browser kunnen zitten, dan moet je ook een manier voorzien om toch een download van bepaalde assets te forceren. Je kan een versienummer voorzien in de bestandsnaam (bv all.min.1.0.2.js) of in de mappenstructuur (bv /js/1.0.2/all.min.js).
Caching uitzondering: browserhomepages
Als je het voorrecht hebt dat jouw site ingesteld staat als homepage in de browser van een gebruiker, dan worden alle assets die worden ingeladen, niet gecached !
In die uitzonderlijke gevallen is het te verantwoorden om de CSS en Javascript inline te plaatsen, om zo het aantal HTTP requests te beperken en de reactiesnelheid van de site te verhogen.
Gzip componenten
Een handige manier op je pagina sneller te doen laden, is door HTTP compressie toe te passen op tekstuele content (HTML, CSS, Javascript, XML, …). Dit wordt in vrijwel alle browsers ondersteund, meerbepaald in diegene die HTTP 1.1 en PNG files ondersteunen. (Internet Explorer 4 en later, Firefox, Opera 5.12+).
In Apache bestaat een module om content on fhe fly te comprimeren (mod_gzip – voor Apache 1.3+, mod_deflate – voor Apache 2+)
De module activeren in Apache 2 is eenvoudig:
LoadModule deflate_module modules/mod_deflate.so
Configureren kan via:
AddOutputFilterByType DEFLATE text/html text/plain
text/xml text/css application/javascript
Hiermee zeg je dus: comprimeer alle html, plain text, xml, css en javascript files.
Meer details kan je lezen op:
http://httpd.apache.org/docs/2.0/mod/mod_deflate.html
ETags
ETags zijn ontworpen om beter te kunnen achterhalen wanneer een component in cache hetzelfde is als op de server. Een ETag id is uniek voor een specifieke resource op een specifieke server. Op drukke websites met meerdere servers kan dit dus problemen opleveren bij het cachen.
De Etag bestaat uit 3 componenten: INode, MTime en Size. Een optie is dus om de Etag zo te configureren, dat het de server niet vermeld bij de Etag.
<Directory /usr/local/httpd/htdocs>
FileETag MTime Size
</Directory>
Een andere optie is om ETags gewoon uit te schakelen en je volledig te baseren op Expires of Cache-Control headers.
Header unset Etag
FileETag none
Meer details kan je lezen op:
http://httpd.apache.org/docs/2.2/mod/core.html#fileetag
Cookies
Cookies worden meegestuurd met elke request. Dus ook wanneer je statische content, zoals afbeeldingen inlaadt.
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. Een andere manier om overhead te vermijden is om het pad van je cookies beter te specifiëren.
Verwijder ook de overbodige cookies, zodat deze niet telkens meegestuurd worden met iedere request.
Je kan beter ook een kortere of zelfs geen Expiry date zetten. Zo wordt de cookie sneller opnieuw verwijderd, en verbetert de responsetijd voor de gebruiker weer.
Let ook op: sommige proxy servers weigeren files te cachen waaraan cookies gekoppeld zijn.
Dit artikel richtte zich voornamelijk toch de Apache configuratie. Je kan de technieken echter ook toepassen in andere serveromgevingen. In een later artikel zullen we dan toelichten hoe je het kan configureren in een Internet Information Services (IIS) omgeving.
Wil je weten (en meten) hoe het gesteld is met de performantie van je website: lees dan zeker ook het artikel met een overzicht van de tools om performantie te meten.