Drie manieren om pagina of blok-element met onbe­kende hoogte verticaal te centreren - uitleg

Skip links en inhoudsopgave

Laatst aangepast: .

Afbeelding 1:

Korte omschrijving

Drie manieren om een pagina of blok-element met onbekende hoogte verticaal te centreren: display: table; flexbox en translateY().

Gele blok

Pagina. Met behulp van display: table; verticaal gecentreerd in het venster van de browser, ongeacht de hoogte van de pagina.

Tekst en blauwe blok links

Gewone <div> met wat tekst en 'n geneste (blauwe) <div>. Als de hoeveelheid tekst toeneemt, wordt de pagina hoger, maar deze blijft verticaal gecentreerd.

Witte blokje midden

Met behulp van flexbox binnen de pagina gecentreerde <div>.

Witte blok rechts

De witte <div> is verticaal gecentreerd met behulp van flexbox. De tekst in de <div> staat in een geneste <div>. De geneste <div> is weer verticaal gecentreerd in de witte <div> met behulp van translateY().

BELANGRIJK

Deze uitleg hoort bij het voorbeeld dat in de download zit. Het voorbeeld uit de download verschilt iets van het voorbeeld hier op de site. In de download ontbreekt bijvoorbeeld de navigatie voor de site. Ook in de kopregels zit vaak wat verschil. Daarnaast kunnen er nog andere (meestal kleine) verschillen zijn.

Als je deze uitleg leest naast de broncode van het voorbeeld op de site, kan het dus bijvoorbeeld zijn dat 'n <h1> uit de css bij 'n <h2> uit de html hoort. Maar het gaat niet om hele grote, fundamentele afwijkingen.

Als je dit lastig vindt, downloadt dan de hele handel (ga terug naar het voorbeeld en kies daar voor downloaden). In de download zit 'n voorbeeld dat wel naadloos aansluit op de uitleg in de download.

Alles op deze site kan vrij worden gebruikt, met drie beperkingen:

* Je gebruikt het materiaal op deze site volledig op eigen risico. Het kan prima zijn dat er fouten in de hier verstrekte info zitten. Voor eventuele schade die door gebruik van materiaal van deze site ontstaat, in welke vorm dan ook, zijn www.css-voorbeelden.nl en medewerkers daarvan op geen enkele manier verantwoordelijk.

* Deze uitleg wordt regelmatig bijgewerkt. Het is daarom niet toegestaan deze uitleg op welke manier dan ook te verspreiden, zonder daarbij duidelijk te vermelden dat de uitleg afkomstig is van www.css-voorbeelden.nl en dat daar altijd de nieuwste versie is te vinden. Dit is om te voorkomen dat er verouderde versies worden verspreid.

* Het kan zijn dat materiaal is gebruikt dat van anderen afkomstig is. Dat materiaal kan onder een bepaalde licentie vallen, waardoor het mogelijk niet onbeperkt gebruikt mag worden. Als dat zo is, wordt dat vermeld onder Inhoud van de download en licenties.

Een link naar www.css-voorbeelden.nl wordt trouwens altijd op prijs gesteld.

Alle code is geschreven in een afwijkende lettersoort en -kleur. De code die te maken heeft met de basis van dit voorbeeld (essentiële code), is in de hele uitleg blauw gekleurd. Alle niet-essentiële code is bruin. (In de inhoudsopgave staat alles vanwege de leesbaarheid in een gewone letter.)

Opmerkingen

Links in deze uitleg, vooral links naar andere sites, kunnen verouderd zijn. Op de pagina met links vind je steeds de meest recente links.

Dit voorbeeld is gemaakt op een systeem met Linux (Kubuntu). Daarbij is vooral gebruik gemaakt van Komodo Edit, GIMP en Firefox met extensies. De pdf-bestanden zijn gemaakt met LibreOffice.

Vragen of opmerkingen? Fout gevonden? Ga naar het forum.

Iets gevonden waar je wat aan hebt? Mooi. Als je je waardering wilt uiten, maak dan een donatie over aan War Child Nederland, een organisatie die kinderen uit oorlogsgebieden helpt hun trauma's te verwerken. Of - nog beter - wordt donateur:
War Child Nederland

Achterliggend idee

Omdat verticaal centreren alleen zinvol is in grotere browservensters, wordt in vensters smaller dan 760 px en/of lager dan 500 px niet verticaal gecentreerd. Het is wat raar om <div>'s speciaal hoger te gaan maken, zodat de inhoud ervan gecentreerd kan worden. Maar in principe werken de hier beschreven technieken precies hetzelfde in kleinere vensters.

Verticaal centreren van een blok-element met onbekende hoogte kon tot voor kort behoorlijk lastig zijn. De enige echt bruikbare methode was weergave in een tabel, omdat in de cel van een tabel met vertical-align de hele inhoud simpel verticaal gecentreerd kan worden, inclusief eventuele blok-elementen in de cel. En ook als de hoogte van de inhoud van de cel onbekend was.

Inmiddels kan uit meerdere methodes worden gekozen. In dit voorbeeld worden drie manieren van verticaal centreren van een blok-element met onbekende hoogte getoond: het gebruik van een css-tabel (dat is iets totaal anders dan een html-tabel), flexbox en translateY().

Als je de hele pagina verticaal wilt centreren, zou ik me eerst nog 'ns afvragen, wat het nut daarvan is. Is 'n kleine marge aan de bovenkant of zoiets niet voldoende? Dat is veel simpeler dan allerlei speciale constructies. Als je bijvoorbeeld afbeeldingen centraal wilt weergeven, is het dan niet veel simpeler die afbeelding (of het element waar de afbeelding in zit) verticaal te centreren?

Tabel

Dit is de enige methode die geschikt is voor het verticaal centreren van de volledige pagina. Bij flexbox en translateY() is er een grote kans dat een deel van de pagina bovenaan het browservenster verdwijnt.

Alle moderne browsers kunnen een element weergeven, alsof het een tabel is, of een cel uit een tabel. Als je van een element met behulp van display: table; een css-tabel maakt, en je zet daar met behulp van display: table-cell; een css-tabelcel in, dan kun je vertical-align gebruiken om verticaal te centeren.

De tabel, het ouder-element, krijgt een bepaalde hoogte. De css-tabelcel wordt, net zoals bij html-tabelcellen, niet hoger dan nodig is om de inhoud ervan weer te geven. Met behulp van vertical-align: middle; kan de cel dan verticaal in de tabel worden gecentreerd. Waardoor ook de inhoud van de cel verticaal binnen de tabel wordt gecentreerd. Ook al is de hoogte van de inhoud van de tabelcel onbekend, de inhoud wordt toch verticaal gecentreerd.

Het verticaal centreren van de hele pagina kan op precies dezelfde manier. De ouder van <body> is <html>. Als je <html> 100% hoog maakt, wordt <html> even hoog als het browservenster. Als je vervolgens ook <body> 100% hoog maakt, zal ook <body> het hele venster vullen. Maak van <body> een css-tabel en je kunt de inhoud van <body> verticaal centreren met behulp van css-tabelcellen.

<body> is in dit voorbeeld even hoog als het browservenster gemaakt en met display: table; in een css-tabel veranderd. <main>, het element waar de pagina in staat, is met display: table-cell; in een css-tabelcel veranderd en kan daardoor met vertical-align: middle; verticaal in <body> worden gecentreerd. En daarmee staat de hele pagina verticaal gecentreerd binnen het venster.

Eh, 'n tabel voor lay-out??? Daar staat inmiddels toch zeven jaar mosselen duiken in de Waddenzee op? En nu moet je opeens 'n tabel voor lay-out gebruiken?

Ja.

Een tabel is inderdaad bedoeld voor tabulaire gegevens, zoals een kalender. Een tabel voor lay-out maakt je pagina uiterst ontoegankelijk voor schermlezers, zoekmachines, en dergelijke. En tabellen, zeker geneste tabellen, zijn uiterst moeilijk te onderhouden. Maar het gaat dan om een html-tabel, en dit is een css-tabel.

De eigenlijke inhoud van de pagina bestaat nog steeds uit doodgewone <div>'s en dergelijke. De css-tabel wordt alleen voor de lay-out gebruikt, voor de weergave, niet om de inhoud van de pagina zelf in een tabel te zetten. Dus de hierboven aangegeven problemen zullen zich niet voordoen. In het verleden werd voor verticaal centreren vaak een html-tabel gebruikt, en dan heb je die nadelen wel.

Bij een html-tabel zijn er allerlei regels. Zo moet een <td> (een tabelcel) binnen een <tr> (een tabelregel) staan. Bij een css-tabel is dat niet zo. De browser maakt automatisch de missende onderdelen van de tabel aan. Je hoeft dus niet allerlei overbodige elementen aan de html toe te voegen om een css-tabel te kunnen gebruiken.

Overigens blijft het een goede gewoonte om tabellen alleen voor tabulaire gegevens te gebruiken, omdat de css anders al snel even rommelig en moeilijk te onderhouden wordt als een html-tabel. Maar om verticaal te centreren is zo'n enkele css-tabelcel heel handig.

Flexbox

Deze methode is absoluut ongeschikt om een hele pagina mee te centreren. Als de pagina hoger is dan het venster van de browser, valt in onder andere Internet Explorer aan de bovenkant van het venster een deel van de pagina weg. Als wordt ingezoomd (vergroot) en de pagina daardoor hoger wordt dan het venster, valt in een groot deel van de browsers aan de bovenkant een deel van de pagina weg.

Met behulp van display: flex; kan een element worden veranderd in een zogenaamde 'flex container'. Dat is een blok-element, waarbinnen allerlei aparte regels gelden voor positioneren, uitlijnen, en dergelijke.

De directe kinderen binnen een flex container zijn zogenaamde 'flex items'. Dat geldt alleen voor de directe kinderen van de flex container:

<div id="flexbox" style="display: flex;"> <div class="direct-kind"> <p id="ondergeschoven-kindje"></p> </div> <div class="direct-kind"></div> </div>

div#flexbox is met display: flex; veranderd in een flex container. Beide <div>'s met class="direct-kind" zijn directe kinderen van div#flexbox en zijn veranderd in een flex item. p#ondergeschoven-kindje is geen direct kind van div#flexbox, maar van de eerste div.direct-kind. p#ondergeschoven-kindje is dan ook niet veranderd in een flex item.

Ook voor flex items gelden aparte regels voor positioneren, uitlijnen, en dergelijke.

Flexbox, zoals het geheel van eigenschappen op dit gebied heet, is gemaakt om problemen als verticaal centreren, onderverdelen in gelijke stukken, en dergelijke op te lossen.

De hele pagina staat binnen het element <main>, dat maar één direct kind heeft: div#voor-flex. Deze <div> is met display: flex; veranderd in een flex container. De directe kinderen div#links, div#midden en div#rechts zijn hiermee veranderd in flex items.

(Feitelijk is die hele div#voor-flex min of meer overbodig, omdat ook <main> in een flex container had kunnen worden veranderd met display: flex;. Maar bij <main> staat al display: table-cell;, dus dat kon niet meer. Op een 'normale' pagina zou dat waarschijnlijk wel kunnen.)

Door bij de flex container align-items: center; te gebruiken worden alle directe kinderen van div#voor-flex verticaal gecentreerd, of de hoogte nu bekend is of niet.

Op div#links, waarin de tekst links en het blauwe blok staan, heeft dit verticaal centreren geen invloed. Deze <div> is van de drie kinderen van div#voor-flex het hoogste en bepaalt daarmee de hoogte van div#voor-flex. Centreren van deze <div> is dus zinloos, want hij is automatisch even hoog als div#voor-flex.

div#midden, het kleine witte blokje in het midden, wordt wel verticaal gecentreerd binnen div#voor-flex. Deze <div> is heel laag, waardoor dit duidelijk is te zien. Als in div#midden inhoud wordt toegevoegd of verwijderd, blijft div#midden toch verticaal gecentreerd. Terwijl de hoogte van deze <div> onbekend is. Bij het opbouwen van de pagina rekent de browser alle groottes uit. De browser kan dat, omdat bij weergave grootte, resolutie, en dergelijke van scherm en browservenster bij de browser bekend zijn. De browser kan daardoor de hoogte van div#voor-flex berekenen en vervolgens div#midden verticaal daarbinnen centreren.

Op div#rechts, het witte blok rechts, heeft align-items: center; ook geen invloed. Normaal genomen zou dat wel zo zijn, maar bij div#rechts staat in de css align-self: stretch;. Hierdoor wordt div#rechts even hoog als de flex container div#voor-flex en kan dus niet worden gecentreerd. (Dat de witte achtergrond van div#rechts niet de volle hoogte vult, komt doordat boven en onder de <div> een marge staat.)

Dit is trouwens een van de vele handige dingen van flexbox: je kunt bij de flex container (hier div#voor-flex) eigenschappen opgeven voor álle flex items, en bij de afzonderlijke flex items kun je die eventueel weer overrulen met aparte css specifiek voor 'n bepaald flex item.

Blok-elementen zoals een <div> komen normaal genomen op een nieuwe regel te staan. Flex items, directe kinderen van een flex container, blijven echter normaal genomen op dezelfde regel staan. Als dat nodig is, worden ze eventueel versmald. Daardoor blijven in dit voorbeeld div#rechts, div#midden en div#links naast elkaar staan. (Je kunt dit veranderen, zodat ze wel op een nieuwe regel komen te staan.)

Browsers die flexbox niet kennen, negeren het gewoon. Dat zijn van de geteste browsers alleen Android browser en UC browser op Android. In deze browsers zouden de <div>'s daardoor toch onder elkaar komen te staan. Dat is echter niet zo, omdat de <div>'s ook worden gefloat. Browsers die flexbox kennen, negeren een float bij een flex item, maar oudere browsers die flexbox niet kennen, voeren de float gewoon uit.

In browsers die flexbox niet kennen, staat div#midden gewoon bovenin div#voor-flex, en div#rechts vult niet de volle hoogte van div#voor-flex. Alleen de lay-out verschilt, er verdwijnt geen tekst of zo. Bij Bekende problemen (en oplossingen) staat hiervan een afbeelding.

transform: translateY();

Deze methode is absoluut ongeschikt om een hele pagina mee te centreren. Als de pagina hoger is dan het venster van de browser, valt aan de bovenkant een deel van de pagina weg.

Het idee van deze methode is om het te centreren blok-element eerst halverwege de hoogte van de ouder (of een voorouder) te zetten. Daarna wordt het de halve hoogte van het element zelf terug naar boven gezet, waardoor de helft van het element boven en de helft onder het midden van de ouder of voorouder komt te staan. Oftewel: verticaal gecentreerd.

In dit voorbeeld wordt deze methode gebruikt om de tekst in div#rechts, het witte blok rechts, te centreren. Die tekst staat in een eigen <div> binnen div#rechts. Als de <div> met de tekst (die ik vanaf nu de 'binnenste' <div> noem) verticaal wordt gecentreerd binnen div#rechts, zal uiteraard ook de tekst daarin verticaal gecentreerd staan binnen div#rechts.

De binnenste <div> wordt halverwege de hoogte van div#rechts gezet met behulp van top: 50%;. Om top te kunnen gebruiken, moet de binnenste <div> een relatieve of absolute positie krijgen. Als bij top een percentage wordt gebruikt, geldt dit bij een relatieve positie ten opzichte van de ouder van het element, hier div#rechts. (Vaak wordt gedacht dat top altijd ten opzichte van het element zelf is bij een relatieve positie, maar dat is niet zo als een percentage wordt gebruikt.)

Om een relatieve positie te kunnen gebruiken, moet div#rechts dus een hoogte hebben. Omdat dit voorbeeld nou juist gaat over blok-elementen die geen bekende hoogte hebben, kan geen hoogte in de css worden opgegeven aan div#rechts. Maar bij het weergeven van de pagina kent de browser alle hoogtes, omdat dan grootte, resolutie, en dergelijke van scherm en browservenster bekend zijn. De browser kent dan dus ook de hoogte van div#rechts en zou die kunnen gebruiken.

Helaas blijkt een fors aantal browsers (waaronder Safari en de meeste mobiele browsers) de hoogte van div#rechts te negeren, omdat dit een 'flex item' is: een element dat een direct kind is van een met display: flex; gemaakte flex container, hier div#voor-flex. Daarom kan position: relative; hier niet worden gebruikt: verticaal centreren binnen een element dat geen hoogte heeft, is tamelijk zinloos.

Blijft over position: absolute; voor de binnenste <div>. Dan geldt top: 50%; ten opzichte van de eerste voorouder die zelf een positie heeft. Je zou div#rechts met position: relative; een positie kunnen geven, maar ook dat is hier geen goed idee. In browsers die flexbox niet kennen, heeft div#rechts namelijk helemaal geen hoogte. En 50% van een hoogte van 0 px is weliswaar formeel halverwege, maar leidt in dit geval toch niet tot wilde volksfeesten.

Maar als position: relative; bij div#voor-flex wordt gezet, blijkt de absolute positie bij de binnenste <div> wel te werken, want div#voor-flex heeft wel in alle browsers een hoogte. Daardoor kan de binnenste <div> nu in alle browsers halverwege div#voor-flex worden gepositioneerd. In dit geval heeft div#voor-flex (min of meer toevallig) de goede hoogte, maar soms zul je het nog hogerop moeten zoeken bij eerdere voorouders.

Hèhè. En dat is nog maar de helft van het verhaal. Maar het is wel weer een aardige illustratie, waarom uitgebreid testen echt nodig is. Als dit voorbeeld alleen in Firefox, Chrome, Internet Explorer en Edge op de desktop was getest, was dit probleem nooit aan het licht gekomen.

Goed, de binnenste <div> staat halverwege de hoogte. Gelukkig is het tweede deel simpeler: met transform: translateY(-50%); wordt de binnenste <div> met de helft van z'n eigen hoogte terug omhoog gezet. Waardoor de helft van de binnenste <div> boven het midden van div#voor-flex staat, en de helft eronder. Het maakt hierbij niet uit hoe hoog de binnenste <div> is, de browser berekent dit automatisch bij het opbouwen van de pagina. Als er meer of minder inhoud in de binnenste <div> komt te staan, wordt de hoogte automatisch aangepast.

Welke methode is het beste?

Dat is niet heel simpel te zeggen.

Voor het centreren van de hele pagina, als je dat beslist wilt, is alleen de tabel-methode geschikt, omdat bij de andere methodes de kans te groot is dat aan de bovenkant een deel van de pagina wegvalt. De methode met de tabel is ook de enige methode, die op dit moment in alle geteste browsers werkt.

Met de tabel-methode kun je eventueel meerdere elementen centreren, door meerdere elementen in een css-tabelcel te veranderen en in dezelfde css-tabel op te nemen.

Voor één enkel element is de combinatie position: relative; top: 50%; transform: translateY(-50%); met stip het simpelste. Maar als je absoluut moet gaan positioneren, zoals in dit voorbeeld, wordt het al 'n stuk lastiger.

Bovendien loop je altijd het risico dat gegevens verdwijnen. Als het te centreren element hoger is dan z'n ouder, kunnen er aan de bovenkant van de ouder gegevens verdwijnen. Dit ligt ook aan de instelling van overflow bij de ouder. Je hebt hier niet volledig controle over, want gebruikers kunnen bijvoorbeeld ook hun lettergrootte verhogen. Maar als de ouder voldoende hoger is dan het te centreren element, is dit een uiterst bruikbare methode.

Voor het centreren van de hele pagina is translateY() niet geschikt, omdat in een deel van de pagina aan de bovenkant van het browservenster wegvalt, als de pagina hoger is dan het venster. Over de hoogte van de pagina heb je nooit volledige controle, want bezoekers kunnen bijvoorbeeld de lettergrootte verhogen of inzoomen.

De methode met de meeste mogelijkheden is flexbox. Dat is, als je eraan gewend bent, ook de makkelijkste. Je kunt met flexbox de elementen horizontaal verdelen op allerlei mogelijke manieren. In de flex container kun je css opgeven voor álle flex items, en vervolgens kun je bij de flex items zelf dat weer veranderen voor één of meer flex items. Alle elementen verticaal centreren, maar eentje bovenaan zetten. Alle elementen even hoog, maar twee niet. Noem maar op. Flexbox is speciaal voor dit soort problemen bedacht, dus het is niet vreemd dat het het beste werkt.

Voor het centreren van de hele pagina is flexbox niet geschikt, omdat in meerdere browsers een deel van de pagina aan de bovenkant van het browservenster wegvalt, als de pagina hoger is dan het venster. Bij inzoomen (vergroten) gebeurt dit zelfs in de meeste browsers. Over de hoogte van de pagina heb je nooit volledige controle, want bezoekers kunnen bijvoorbeeld de lettergrootte verhogen.

(Waarom dat mallotige verticale centreren van een pagina hier is opgenomen, terwijl ik het 398 keer afraadt? Omdat de vraag op forums regelmatig terugkwam. En áls je dan echt denkt dat je bezoekers in gejubel uitbarsten bij een verticaal gecentreerde pagina, kun je het beter op de minst slechte manier doen.)

Helaas werkt flexbox nog niet in alle browsers. In Internet Explorer 11 werkt het wel, maar stikt het van de bugs. Als het geen onoverkomelijke problemen oplevert in browsers, waarin het niet werkt, kun je het best flexbox gebruiken. In dit voorbeeld wordt, als flexbox niet wordt ondersteund, het middelste witte blokje niet verticaal gecentreerd, maar bovenaan gezet. Verder heeft div#rechts geen hoogte, waardoor de witte achtergrond te kort is en de border als een streepje helemaal bovenaan staat. In dit geval is dat allemaal niet zo erg, dus zou flexbox gewoon gebruikt kunnen worden. (Bij Bekende problemen (en oplossingen) staat een afbeelding, hoe het er zonder ondersteuning voor flexbox uitziet.)

(Voor de volledigheid: ook in UC browser op Android en Android browser kun je flexbox aan de praat krijgen, maar dat is een zwaar verouderde versie. Bovendien wonen daarin niet slechts 'n paar schattige buggetjes met hoge aaibaarheidsfactor, maar blijkt er 'n compleet regiment beroepsartiesten uit een professioneel vlooiencircus in te wonen. Reden voor de Werkgroep Overspannenheid van de Nederlandse Vereniging van Therapeuten om het gebruik van flexbox in deze browsers te verbieden. Waarmee ik maar wil zeggen: dat is echt volledig onbruikbaar door de onvolledige en foutieve implementatie.)

De voorvoegsels -moz-, -ms- en -webkit-

Voordat een nieuwe css-eigenschap wordt ingevoerd, is er in de regel een experimentele fase. Browsers passen het dan al toe, maar met een aangepaste naam. Tijdens deze fase kunnen problemen worden opgelost en worden veldslagen uitgevochten, over hoe de standaard precies moet worden toegepast.

Als iedereen het overal over eens is en alle problemen zijn opgelost, wordt de officiële naam uit de standaard gebruikt.

De belangrijkste browsers hebben elk een eigen voorvoegsel:

Firefox: -moz-, naar de maker: Mozilla.

Op webkit gebaseerde browsers, zoals Google Chrome, Opera, Safari en Android browser: -webkit-.

(Google Chrome is van webkit overgestapt op een eigen weergave-machine: Blink. Blink gaat geen voorvoegsels gebruiken. Het is echter een aftakking van webkit, dus het zal nog wel even duren voor -webkit- hier helemaal uit is verdwenen. Ook Opera gebruikt Blink.)

Internet Explorer: -ms-, naar de maker: Microsoft. (Edge gebruikt geen voorvoegsels, maar vanwege compatibiliteit met oudere sites kunnen er nog wat aanwezig zijn.)

Zodra de experimentele fase voorbij is, wordt het voorvoegsel weggelaten. Omdat dat moment niet bij alle browsers hetzelfde is, zet je nu ook al de officiële naam erbij. Deze wordt als laatste opgegeven. Bijvoorbeeld Android browser herkent -webkit-linear-gradient. Zodra Android browser linear-gradient gaat herkennen, zal dit -webkit-linear-gradient overrulen, omdat het er later in staat. Dat ze er beide in staan, is dus geen enkel probleem.

In dit voorbeeld wordt transform gebruikt.

transform

Op dit moment moet je nog het volgende schrijven:

{-webkit-transform: ...; transform: ...;}

In de toekomst kun je volstaan met:

{transform: ...;}

Inmiddels is de algemene mening dat 'vendor prefixes', zoals deze voorvoegsels in het Engels heten, geen groot succes zijn. Eén van de grootste problemen: veel sitemakers gebruiken alleen de -webkit-variant. Daar kwamen ze in het verleden nog mee weg, omdat Apple op mobiel zo'n beetje 'n monopolie had. Inmiddels is dat niet meer zo, maar deze gewoonte bestaat nog steeds. Waardoor 'n site alleen in op webkit georiënteerde browsers goed is te bekijken.

Dit is zo'n groot probleem dat andere browsers soms de variant met -webkit- ook maar zijn gaan implementeren, naast de standaard. Want als 'n site het niet goed doet in 'n bepaalde browser, krijgt in de regel niet de site maar de browser de schuld.

Vanwege alle problemen met 'vendor prefixes' worden deze door steeds meer browsers niet meer gebruikt. Nieuwe, experimentele css-eigenschappen zitten inmiddels in bijvoorbeeld Firefox, Google Chrome en Safari achter een zogenaamde vlag: de gebruiker moet iets veranderen in de instellingen, waarna de eigenschap gebruikt (en getest) kan worden. Als alles werkt, zoals het hoort te werken, schakelt de browsermaker de vlag standaard in.

Voorlopig zijn we echter nog niet van deze voorvoegsels af. Als je ze gebruikt, gebruik dan álle varianten, en eindig met de variant zonder voorvoegsel, zoals die uiteindelijk ooit gebruikt gaat worden. Als je alleen de -webkit-variant gebruikt, ben je in feite 'n onbetaalde reclamemaker voor Apple.

De code aanpassen aan je eigen ontwerp

Toegankelijkheid en zoekmachines

Het eerste deel van deze tekst is voor alle voorbeelden hetzelfde. Eventueel specifiek voor dit voorbeeld geldende dingen staan verderop onder het kopje Specifiek voor dit voorbeeld.

Toegankelijkheid (in het Engels 'accessibility') is belangrijk voor bijvoorbeeld blinden die een schermlezer gebruiken, of voor motorisch gehandicapte mensen die moeite hebben met het bedienen van een muis. Een spider van een zoekmachine (dat is het programmaatje dat de site indexeert voor de zoekmachine) is te vergelijken met een blinde. Als je je site goed toegankelijk maakt voor gehandicapten, is dat gelijk goed voor een hogere plaats in een zoekmachine. Dus als je 't niet uit sociale motieven wilt doen, kun je 't uit egoïstische motieven doen.

(Op die plaats in de zoekmachine heb je maar beperkt invloed. De toegankelijkheid van je site is maar één van de factoren, maar zeker niet onbelangrijk.)

Als je bij het maken van je site al rekening houdt met toegankelijkheid, is dat nauwelijks extra werk. 't Is ongeveer te vergelijken met inbraakbescherming: doe dat bij 'n nieuw huis en 't is nauwelijks extra werk, doe 't bij 'n bestaand huis en 't is al snel 'n enorme klus.

Enkele tips die helpen bij toegankelijkheid:

Specifiek voor dit voorbeeld

Deze constructie heeft geen invloed op de toegankelijkheid. Zonder css zie je gewoon de tekst zonder opmaak. Schermlezers lezen gewoon de tekst voor in de volgorde, zoals deze in de html staat.

Getest in

Laatst gecontroleerd op 6 juni 2017.

Onder dit kopje staat alleen maar, hoe en waarin is getest. Eventuele problemen, ook die met betrekking tot zoomen en lettergroottes, staan hieronder bij Bekende problemen (en oplossingen). Het is belangrijk dat deel te lezen, want uit een test kan ook prima blijken dat iets totaal niet werkt!

Eventuele opmerkingen over de toegankelijkheid specifiek voor dit voorbeeld staan hierboven bij Toegankelijkheid en zoekmachines onder het kopje Specifiek voor dit voorbeeld.

Dit voorbeeld is getest op de volgende systemen:

Desktopcomputers

Windows 7 (1280 x 1024 px, resolution: 96 dpi):
Firefox, UC Browser, Google Chrome en Internet Explorer 11, in grotere en kleinere browservensters.

OS X 10.11.6 ('El Capitan') (1680 x 1050 px, resolution: 96: dpi, device-pixel-ratio: 1):
Firefox, Safari en Google Chrome, in grotere en kleinere browservensters.

Linux (Kubuntu 14.04 LTS, 'Trusty Tahr') (1280 x 1024 px, resolution: 96 dpi):
Firefox en Google Chrome, in grotere en kleinere browservensters.

Laptops

Windows 8.1 (1366 x 768 px, resolution: 96 dpi):
Bureaublad-versie: Firefox, UC Browser, Google Chrome en Internet Explorer 11, in grotere en kleinere browservensters.
Startscherm-versie: Internet Explorer 11.

Windows 10 (1600 x 900 px, resolution: 96 dpi):
Firefox, UC Browser, Google Chrome, Internet Explorer 11, Edge, in grotere en kleinere browservensters.

Tabletten

iPad met iOS 9.3.5 (1024 x768 px, device-pixel-ratio: 1):
Safari, Chrome for iOS, UC Browser, Firefox (alle portret en landschap).
Opera Mini (turbo mode) portret en landschap.

iPad met iOS 10.3.2 (2048 x 1536 px, device-pixel-ratio: 2 ('retina'):
Safari, Chrome for iOS, UC browser, Firefox (alle portret en landschap).
Opera Mini (turbo mode) portret en landschap.

Android 4.4.2 ('Kitkat') (1280 x 800 px, resolution: 96 dpi):
Android browser, UC Browser, Firefox en Chrome (alle portret en landschap).
Opera Mini (besparingen uitgeschakeld) portret en landschap.

Android 4.4.2 ('Kitkat') (2560 x 1600 px, resolution: 192 dpi):
Android browser, UC Browser, Firefox en Chrome (alle portret en landschap).
Opera Mini (besparingen uitgeschakeld) portret en landschap.

Android 5.0.1 ('Lollipop') (1920 x 1200 px, resolution: 144 dpi):
Dolphin, UC Browser, Firefox en Chrome (alle portret en landschap).
Opera Mini (besparingen uitgeschakeld) portret en landschap.

Android 7.0 ('Nougat') (1920 x 1200 px, resolution: 144 dpi):
Dolphin, Samsung Internet, UC Browser, Firefox en Chrome (alle portret en landschap).
Opera Mini (besparingen uitgeschakeld) portret en landschap.

Smartphones

Windows Phone 8.1 (800 x 480 px, resolution: 136 dpi):
Internet Explorer en UC browser (portret en landschap).

Windows 10 Mobile (1280 x 720 px, resolution: 192 dpi):
Edge en UC browser (portret en landschap).

Android 4.1.2 ('Jelly Bean') (800 x 480 px, resolution: 144 dpi):
Chrome, Android browser, UC Browser en Firefox (alle portret en landschap).
Opera Mini (besparingen uitgeschakeld) portret en landschap.

Android 7.0 ('Nougat') (1280 x 720 px, resolution: 192 dpi):
Dolphin, Samsung Internet, UC Browser, Firefox en Chrome (alle portret en landschap).
Opera Mini (besparingen uitgeschakeld) portret en landschap.

Er is op de aan het begin van dit hoofdstukje genoemde controledatum getest in de meest recente versie van de browser, die op het betreffende besturingssysteem kon draaien. Het aantal geteste browsers en systemen is al tamelijk fors, en als ook nog rekening gehouden moet worden met (zwaar) verouderde browsers, is het gewoon niet meer te doen. Surfen met een verouderde browser is trouwens vragen om ellende, want updates van browsers hebben heel vaak met beveiligingsproblemen te maken.

In- en uitzoomen en – voor zover de browser dat kan – een kleinere en grotere letter zijn ook getest. Er is ingezoomd en vergroot tot zover de browser kan, maar niet verder dan 200%.

Er is getest met behulp van muis en toetsenbord, behalve op de iPad, Android, Windows Phone en Windows 10 Mobile, waar een touchscreen is gebruikt. Op Windows 8.1 en 10 is getest met een touchscreen, met een combinatie van toetsenbord en touchpad, en met een combinatie van toetsenbord en muis.

Als dat relevant is, is op de desktop ook getest, als JavaScript uitstaat. Eventuele problemen staan hierboven bij Toegankelijkheid en zoekmachines onder het kopje Specifiek voor dit voorbeeld. (Op iOS, Android, Windows Phone en Windows 10 Mobile is niet getest zonder JavaScript, omdat je JavaScript in een toenemend aantal mobiele browsers niet uit kunt zetten. Bovendien is een mobiel apparaat zonder JavaScript niet veel meer dan een duur en groot uitgevallen horloge.)

Naast deze 'gewone' browsers is ook getest in Lynx, WebbIE, NVDA, TalkBack, VoiceOver en ChromeVox.

Lynx is een browser die alleen tekst laat zien en geen css gebruikt. Er is getest op Linux.

WebbIE is een browser die gericht is op mensen met een handicap. Er is getest op Windows 7.

NVDA is een schermlezer, zoals die door blinden wordt gebruikt. Er is getest in combinatie met Firefox op Windows 7 en Firefox op Windows 10.

TalkBack is een in Android ingebouwde schermlezer. Er is getest in combinatie met Chrome.

VoiceOver is een in iOS en OS X ingebouwde schermlezer. Er is getest in combinatie met Safari op iOS en OS X.

ChromeVox is een schermlezer in de vorm van een extensie bij Google Chrome. Er is getest op een systeem met Kubuntu Linux.

Als het voorbeeld in deze programma's toegankelijk is, zou het in principe toegankelijk moeten zijn in alle aangepaste browsers en dergelijke. En dus ook voor zoekmachines, want een zoekmachine is redelijk vergelijkbaar met een blinde. Eventuele opmerkingen over de toegankelijkheid specifiek voor dit voorbeeld staan hierboven bij Toegankelijkheid en zoekmachines onder het kopje Specifiek voor dit voorbeeld.

Alleen op de hierboven genoemde systemen en browsers is getest. Er is dus niet getest op bijvoorbeeld 'n Blackberry. De kans is (heel erg) groot dat dit voorbeeld niet (volledig) werkt op niet-geteste systemen en apparaten. Om het wel (volledig) werkend te krijgen, zul je vaak (kleine) wijzigingen en/of (kleine) aanvullingen moeten aanbrengen, bijvoorbeeld met JavaScript.

Er is ook geen enkele garantie dat iets werkt in een andere tablet of smartphone dan hierboven genoemd, omdat fabrikanten in principe de software kunnen veranderen. Dit is anders dan op de desktop, waar browsers altijd (vrijwel) hetzelfde werken, zelfs op verschillende besturingssystemen. Iets wat in Android browser werkt, zal in de regel overal werken in die browser, maar een garantie is er niet. De enige garantie is het daadwerkelijk testen op een fysiek apparaat. En aangezien er duizenden mobiele apparaten zijn, is daar eigenlijk geen beginnen aan.

De html is gevalideerd met de validator van w3c, de css ook. Als om een of andere reden niet volledig gevalideerd kon worden, wordt dat bij Bekende problemen (en oplossingen) vermeld.

Nieuwe browsers worden pas getest, als ze uit het bèta-stadium zijn, omdat er anders 'n redelijke kans is dat je tegen 'n bug zit te vechten, die voor de uiteindelijke versie nog gerepareerd wordt. Dit voorbeeld is alleen getest in de hierboven met name genoemde browsers. Vragen over niet-geteste browsers kunnen niet worden beantwoord, en het melden van fouten in niet-geteste browsers heeft ook geen enkel nut. (Melden van fouten, problemen, enzovoort in wel geteste browsers: graag!)

Bekende problemen (en oplossingen)

Waarop en hoe is getest, kun je gelijk hierboven vinden bij Getest in.

Als je hieronder geen oplossing vindt voor een probleem dat met dit voorbeeld te maken heeft, kun je op het forum proberen een oplossing te vinden voor je probleem. Om forumspam te voorkomen, moet je je helaas wel registreren, voordat je op het forum een probleem kunt aankaarten.

Alle browsers

Bij het centreren van de pagina met flexbox verdwijnt de bovenkant

Flexbox is niet geschikt om een hele pagina verticaal mee te centreren.

Als de pagina hoger wordt dan het venster van de browser, verdwijnt in Internet Explorer (alle versies) en Dolphin een deel van de pagina aan de bovenkant van het venster. De pagina staat nog steeds verticaal gecentreerd, maar juist daardoor staat een deel boven het venster. Aan de onderkant is dat geen probleem, omdat gescrold kan worden, maar aan de bovenkant verdwijnt een deel echt volledig.

Als wordt ingezoomd (vergroot) en de pagina wordt daardoor hoger dan het venster van de browser, gebeurt dit in een groot deel van de browsers.

Omdat gebruikers kunnen inzoomen, de lettergrootte kunnen verhogen, en dergelijke, heb je nooit volledig controle over de hoogte van de pagina. Daarom is alleen de methode met de css-tabel geschikt voor het verticaal centreren van de hele pagina, want daarin speelt dit probleem niet.

Bij het centreren van de pagina met translateY() verdwijnt de bovenkant

De transform-functie translateY() is niet geschikt om een hele pagina verticaal mee te centreren.

Als je deze methode gebruikt, wordt de pagina eerst halverwege de hoogte van het browservenster gezet. Daarna wordt de pagina de helft van de hoogte van de pagina terug naar boven gezet. Als de pagina hoger is dan het venster, verdwijnt hierdoor in alle browsers een deel van de pagina aan de bovenkant van het venster.

Aan de onderkant steekt de pagina ook uit, maar dat is geen probleem, omdat daar kan worden gescrold. Boven het browservenster kan echter niet worden gescrold: wat daar verdwijnt, is echt weg.

Omdat gebruikers kunnen inzoomen, de lettergrootte kunnen verhogen, en dergelijke, heb je nooit volledig controle over de hoogte van de pagina. Daarom is alleen de methode met de css-tabel geschikt voor het verticaal centreren van de hele pagina, want daarin speelt dit probleem niet.

Bij het centreren van een element met translateY() verdwijnt de bovenkant

Dit is precies hetzelfde probleem dat gelijk hierboven bij het centreren van de pagina wordt beschreven. Als je met deze methode iets verticaal wilt centreren, zorg dan dat de tekst minstens twee keer zo groot kan worden gemaakt, voordat het niet meer in de ouder van het te centreren element past.

Als je de methode met flexbox of de css-tabel gebruikt, is er geen risico dat er iets verdwijnt. Bij die methodes komt het te centreren element nooit boven de ouder uit, maar wordt de ouder eventueel hoger gemaakt, als dat nodig is.

Bij gebruik van translateY() verdwijnen erop volgende elementen

Iets kan alleen verdwijnen, als het op dezelfde plaats op het scherm staat. Dus op een of andere manier staan er dan twee (of meer) elementen op dezelfde plaats.

Normaal genomen bepaalt de volgorde van de html, welk element bovenaan komt te staan en dus volledig zichtbaar is. Wat het laatst in de html staat, komt bovenaan te staan.

Bij gebruik van een transform-functie werkt dat echter anders. Als je een van de transform-functies gebruikt, is dat vergelijkbaar met het gebruik van bijvoorbeeld position: relative;. Een gepositioneerd element komt vaak boven een niet-gepositioneerd element te staan, ongeacht de volgorde in de html.

Het element dat op dezelfde plaats staat als het met translateY() verplaatste element, zal daardoor verdwijnen. Door aan het verdwenen element in de css position: relative; toe te voegen, krijgt het verdwenen element zelf ook een positie en zal het weer bovenaan staan.

Als je position niet kunt gebruiken, kun je ook opacity: 0.99; gebruiken. Dat heeft hetzelfde effect als position: relative;. Omdat de doorzichtigheid maar 0,01 is, is dat verder met het blote oog niet te zien.

UC browser op Android en Android browser

Flexbox wordt niet ondersteund

Dit is niet helemaal correct. Flexbox wordt wel ondersteund, maar dan een oudere versie. Die is bovendien zo onvolledig en foutief geïmplementeerd, dat flexbox in deze browsers feitelijk onbruikbaar is. Als het geen onoverkomelijke problemen oplevert, zou je flexbox gewoon kunnen gebruiken en deze browsers negeren. In deze browsers ziet het er dan anders uit, maar alles is gewoon aanwezig. Dat is in dit voorbeeld gebeurd.

De rechterhelft van de pagina ziet er in dit voorbeeld in deze browsers anders uit. Op de afbeelding hieronder is links te zien, hoe het er in UC browser op Android en Android browser uitziet. Rechts is te zien, hoe het eruit zou moeten zien (en hoe het er in alle andere browsers ook echt uitziet).

Afbeelding 2: zonder flexbox is alleen de lay-out anders

De middelste witte <div> staat niet verticaal gecentreerd, maar bovenaan. Bij de <div> rechts mist een deel van de witte achtergrond, en de border staat niet rondom de <div>, maar is in elkaar geklopt tot een lijntje bovenaan. Er verdwijnt echter geen tekst of zo, dus in dit geval zou is flexbox gewoon gebruikt. Dat het er anders uitziet: jammer dan.

Overigens wordt UC browser regelmatig geüpdatet en Android browser wordt al tijden niet meer geleverd en verdwijnt in rap tempo, dus binnen niet al te lange tijd zou dit probleem vanzelf moeten zijn verdwenen.

Wijzigingen

Alleen grotere wijzigingen worden hier vermeld, geen dingen als een link die is geüpdatet.

:

Nieuw opgenomen.

6 juni 2017:

Omdat de code volledig is gewijzigd, zijn eerdere wijzigingen verwijderd. Die wijzigingen zijn inmiddels zelf ook weer gewijzigde wijzigingen die gewijzigd zijn, of helemaal verdwenen, vandaar. Hieronder staan de belangrijkste verschillen met vorige versies.

Inhoud van de download en licenties

De inhoud van deze download kan vrij worden gebruikt, met drie beperkingen:

* Sommige onderdelen die van 'n andere site of zo afkomstig zijn, vallen mogelijk onder een of andere licentie. Dat is hieronder bij het betreffende onderdeel te vinden.

* Je gebruikt het materiaal uit deze download volledig op eigen risico. Het kan prima zijn dat er fouten in de hier verstrekte code en dergelijke zitten. Voor eventuele schade die door gebruik van materiaal uit deze download ontstaat, in welke vorm dan ook, zijn www.css-voorbeelden.nl en medewerkers daarvan op geen enkele manier verantwoordelijk.

* Dit voorbeeld (en de bijbehorende uitleg en dergelijke) wordt regelmatig bijgewerkt. Het is daarom niet toegestaan dit voorbeeld (en de bijbehorende uitleg en dergelijke) op welke manier dan ook te verspreiden, zonder daarbij duidelijk te vermelden dat voorbeeld, uitleg, en dergelijke afkomstig zijn van www.css-voorbeelden.nl en dat daar altijd de nieuwste versie is te vinden. Dit is om te voorkomen dat er verouderde versies worden verspreid.

Een link naar www.css-voorbeelden.nl wordt trouwens altijd op prijs gesteld.

positioneren-007-118-dl.html: de pagina met het voorbeeld.

positioneren-007.pdf: deze uitleg (aangepast aan de inhoud van de download).

positioneren-007-inhoud-download-en-licenties.txt: een kopie van de tekst onder dit kopje (Inhoud van de download en licenties).

007-css-dl:

positioneren-007-dl.css: stylesheet voor positioneren-007.html.

HTML

De code is geschreven in een afwijkende lettersoort. De code die te maken heeft met de basis van dit voorbeeld (essentiële code), is in de hele uitleg blauw gekleurd. Alle niet-essentiële code is bruin. (In de inhoudsopgave staat alles in een gewone letter vanwege de leesbaarheid.)

In de html hieronder wordt alleen de html besproken, waarover iets meer is te vertellen. Een <h1> bijvoorbeeld wordt in de regel niet genoemd, omdat daarover weinig interessants valt te melden. (Als bijvoorbeeld het uiterlijk van de <h1> wordt aangepast met behulp van css, staat dat verderop bij de bespreking van de css.)

Zaken als een doctype en charset hebben soms wat voor veel mensen onbekende effecten, dus daarover wordt hieronder wel een en ander geschreven.

<!DOCTYPE html>

Een document moet met een doctype beginnen om weergaveverschillen tussen browsers te voorkomen. Zonder doctype is de kans op verschillende (en soms volkomen verkeerde) weergave tussen verschillende browsers heel erg groot.

Geldige doctypes vind je op www.w3.org/QA/2002/04/valid-dtd-list.

Gebruik het volledige doctype, inclusief de eventuele url, anders werkt het niet goed.

Het hier gebruikte doctype is dat van html5. Dit kan zonder enig probleem worden gebruikt: het werkt zelfs in Internet Explorer 6.

<html lang="nl">

De toevoeging lang="nl" bij <html> geeft aan dat de pagina in het Nederlands is. De taal is van belang voor schermlezers, automatisch afbreken, automatisch genereren van aanhalingstekens, juist gebruik van decimale punt of komma, en dergelijke.

<meta charset="utf-8">

Zorgt dat de browser letters met accenten en dergelijke goed kan weergeven.

utf-8 is de beste charset (tekenset), omdat deze alle talen van de wereld (en nog heel veel andere extra tekens) bestrijkt, maar toch niet meer ruimte inneemt voor de code, dan nodig is. Als je utf-8 gebruikt, hoef je veel minder entiteiten (&auml; en dergelijke) te gebruiken, maar kun je bijvoorbeeld gewoon ä gebruiken.

Deze regel moet zo hoog mogelijk komen te staan, als eerste regel binnen de head, omdat hij anders door sommige browsers niet wordt gelezen.

In html5 hoeft deze regel niet langer te zijn, dan wat hier staat.

<meta name="viewport" content="width=device-width, initial-scale=1">

Mobiele apparaten variëren enorm in breedte. En dat is een probleem. Sites waren, in ieder geval tot voor kort, gemaakt voor desktopbrowsers. En die hebben, in vergelijking met bijvoorbeeld een smartphone, heel brede browservensters. Hoe moet je op 'n smartphone een pagina weergeven, die is gemaakt voor de breedte van een desktop? Je kunt natuurlijk wachten tot álle sites zijn omgebouwd voor smartphones, tablets, enzovoort, maar dan moet je waarschijnlijk heel erg lang wachten.

Mobiele browsers gokken erop dat een pagina een bepaalde breedte heeft. Safari voor mobiel bijvoorbeeld gaat ervan uit dat een pagina 980 px breed is. De pagina wordt vervolgens zoveel versmald dat hij binnen het venster van het apparaat past. Op een iPhone wordt de pagina dus veel smaller dan op een iPad. Vervolgens kan de gebruiker inzoomen op het deel van de pagina dat hij of zij wil zien.

Dit betekent ook dat bij het openen van de pagina de tekst meestal heel erg klein wordt weergegeven. (Meestal, want niet alle browsers en apparaten doen het op dezelfde manier.) Niet erg fraai, maar bedenk maar 'ns 'n betere oplossing voor bestaande sites.

Nieuwe sites of pagina's kunnen echter wel rekening houden met de veel kleinere vensters van mobiele apparaten. In dit voorbeeld wordt in kleinere vensters niet verticaal gecentreerd. Maar die stomme mobiele browser weet dat niet, dus die gaat ervan uit dat ook de al aangepaste pagina 980 px breed is, en verkleint die dan. Dat is ongeveer even behulpzaam als de gedienstige kelner die behulpzaam de stoel naar achteren trekt, net als jij wilt gaan zitten.

Om de door de browser aangeboden hulp vriendelijk maar beslist te weigeren, wordt deze tag gebruikt. Hiermee geef je aan dat de pagina is geoptimaliseerd voor mobiele apparaten.

Een iPad in portretstand bijvoorbeeld is 768 px breed. De kreet width=device-width zegt tegen de mobiele browser dat de breedte van de weer te geven pagina gelijk is aan de breedte van het apparaat. Voor een iPad in portretstand dus 768 px.

Simpeler gezegd: je zegt tegen het mobiele apparaat dat de pagina geen vaste breedte heeft, en dat het dus niet nodig is om de weergave aan te passen.

Er staat nog een tweede deel in de tag: initial-scale=1. Sommige mobiele apparaten zoomen een pagina gelijk in of uit. Ook weer in een poging behulpzaam te zijn. Ook dat is hier niet nodig, want de pagina past zich aan het apparaat aan. Er is ook een instructie om zoomen helemaal onmogelijk te maken, maar die wordt niet gebruikt. De bezoeker kan zelf nog gewoon zoomen, wat belangrijk is voor mensen die wat slechter zien.

CSS

De code is geschreven in een afwijkende lettersoort. De code die te maken heeft met de basis van dit voorbeeld (essentiële code) is in de hele uitleg blauw gekleurd. Alle niet-essentiële code is bruin. (In de inhoudsopgave staat alles in een gewone letter vanwege de leesbaarheid.)

Omdat deze site nou eenmaal (voornamelijk) op css is gericht, wordt hieronder álle css besproken.

Technisch gezien is er geen enkel bezwaar om de css in de stylesheet allemaal achter elkaar op één regel te zetten:

div#header-buiten {position: absolute; right: 16px; width: 100%; height: 120px; background: yellow;} div p {margin-left 16px; height: 120px; text-align: center;}

Maar als je dat doet, garandeer ik je hele grote problemen, omdat het volstrekt onoverzichtelijk is. Beter is het om de css netjes in te laten springen:

              div#header-buiten {
            position: absolute;
            right: 16px;
            width: 100%;
            height: 120px;
            background: yellow;
        }

        div p {
            margin-left: 16px;
            height: 120px;
            text-align: center;
        }

Hiernaast is het heel belangrijk voldoende commentaar (uitleg) in de stylesheet te schrijven. Op dit moment weet je waarschijnlijk (hopelijk...), waarom je iets doet. Maar over vijf jaar kan dat volstrekt onduidelijk zijn. Op deze site vind je nauwelijks commentaar in de stylesheets, maar dat heeft een simpele reden: deze uitleg is in feite één groot commentaar.

Op internet zelf is het goed, als de stylesheet juist zo klein mogelijk is. Dus voor het uploaden kun je normaal genomen het beste het commentaar weer verwijderen. Veel mensen halen zelfs alles wat overbodig is weg, voordat ze de stylesheet uploaden. Inspringingen bijvoorbeeld zijn voor mensen handig, een computer heeft ze niet nodig.

Je hebt dan eigenlijk twee stylesheets. De uitgebreide versie waarin je dingen uitprobeert, verandert, enzovoort, met commentaar, inspringingen, en dergelijke. Dat is de mensvriendelijke versie. Daarnaast is er dan een stylesheet die je op de echte site gebruikt: een gecomprimeerde versie.

Dat comprimeren kun je met de hand doen, maar er bestaan ook hulpmiddelen voor. Op de pagina met links kun je onder Gereedschap → Snelheid, testen, gzip, comprimeren links naar sites vinden, waar je bestanden kunt comprimeren.

(Stylesheets op deze site zijn niet gecomprimeerd. Omdat het vaak juist om de css gaat, kunnen mensen dan zonder al te veel moeite de css bekijken.)

css voor alle vensters

/* positioneren-007-dl.css */

Om vergissingen te voorkomen is het een goede gewoonte bovenaan het stijlbestand even de naam neer te zetten. Voor je het weet, zit je anders in het verkeerde bestand te werken.

body

Het element waarbinnen de hele pagina staat. Veel instellingen die hier worden opgegeven, worden geërfd door de nakomelingen van <body>. Ze gelden voor de hele pagina, tenzij ze later worden gewijzigd. Dit geldt bijvoorbeeld voor de lettersoort, de lettergrootte en de voorgrondkleur.

background: #ff9;

Achtergrondkleurtje.

color: black;

Voorgrondkleur zwart. Dit is onder andere de kleur van de tekst.

Hoewel dit de standaardkleur is, wordt deze toch specifiek opgegeven. Hierboven is een achtergrondkleur opgegeven. Sommige mensen hebben zelf de voor-‑ en/of achtergrondkleur veranderd, bijvoorbeeld omdat ze slecht kleuren kunnen onderscheiden. Als nu de achtergrondkleur wordt veranderd, maar niet de voorgrondkleur, loop je het risico dat tekstkleur en achtergrondkleur te veel op elkaar gaan lijken.

Door beide op te geven, is redelijk zeker dat achtergrond- en tekstkleur genoeg van elkaar blijven verschillen. Als de gebruiker !important heeft gebruikt in een eigen stylesheet, is er nog niets aan de hand, want dan veranderen achtergrond- en voorgrondkleur geen van beide.

font-family: Arial, Helvetica, sans-serif;

Als Arial is geïnstalleerd op de machine van de bezoeker, wordt deze gebruikt, anders Helvetica. Als die ook niet wordt gevonden, wordt in ieder geval een schreefloze letter (zonder dwarsstreepjes) gebruikt.

margin: 0; padding: 0;

Slim om te doen vanwege verschillen tussen browsers.

#voor-flex

Het element met id="voor-flex". De hele pagina staat binnen <main>. div#voor-flex is het enige kind van <main>.

Deze <div> is alleen nodig voor grotere browservensters, waarin de pagina met behulp van flexbox verticaal wordt gecentreerd. Om dit te kunnen doen, moet de pagina binnen een zogenaamde 'flex container' staan. Bij #voor-flex wordt deze <div> in zo'n container veranderd. Voor kleinere vensters is deze <div> overbodig. De hieronder staande css zou in kleinere vensters vrij makkelijk aan andere elementen kunnen worden gegeven.

background: yellow;

Gele achtergrond.

color: black;

Voorgrondkleur zwart. Dit is onder andere de kleur van de tekst.

Hoewel dit de standaardkleur is, wordt deze toch specifiek opgegeven. Hierboven is een achtergrondkleur opgegeven. Sommige mensen hebben zelf de voorgrond‑ en/of achtergrondkleur veranderd, bijvoorbeeld omdat ze slecht kleuren kunnen onderscheiden. Als nu de achtergrondkleur wordt veranderd, maar niet de voorgrondkleur, loop je het risico dat tekstkleur en achtergrondkleur te veel op elkaar gaan lijken.

Door beide op te geven, is redelijk zeker dat achtergrond- en tekstkleur genoeg van elkaar blijven verschillen. Als de gebruiker !important heeft gebruikt in een eigen stylesheet, is er nog niets aan de hand, want dan veranderen achtergrond- en voorgrondkleur geen van beide.

Dit is ook al bij <body> opgegeven, maar sommige mensen hebben bij álle elementen de kleuren veranderd. Het heeft immers weinig zin, als ze dat alleen bij de body doen, terwijl de sitebouwer de kleuren ook bij bijvoorbeeld de paragrafen heeft aangepast.

h1

Alle <h1>'s. Dat is er maar één: de belangrijkste kop van de pagina.

font-size: 1.3em;

Een <h1> heeft van zichzelf een nogal grote letter, die wordt hier iets kleiner gemaakt.

Als eenheid wordt de relatieve eenheid em gebruikt, omdat bij gebruik van een absolute eenheid zoals px niet alle browsers de lettergrootte kunnen veranderen. Zoomen kan wel altijd, ongeacht welke eenheid voor de lettergrootte wordt gebruikt.

#midden, #rechts

Voor een deel van deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat.

#links, #midden, #rechts div {padding: 5px;}

background: white;

Witte achtergrond.

color: black;

Voorgrondkleur zwart. Dit is onder andere de kleur van de tekst.

Hoewel dit de standaardkleur is, wordt deze toch specifiek opgegeven. Hierboven is een achtergrondkleur opgegeven. Sommige mensen hebben zelf de voorgrond‑ en/of achtergrondkleur veranderd, bijvoorbeeld omdat ze slecht kleuren kunnen onderscheiden. Als nu de achtergrondkleur wordt veranderd, maar niet de voorgrondkleur, loop je het risico dat tekstkleur en achtergrondkleur te veel op elkaar gaan lijken.

Door beide op te geven, is redelijk zeker dat achtergrond- en tekstkleur genoeg van elkaar blijven verschillen. Als de gebruiker !important heeft gebruikt in een eigen stylesheet, is er nog niets aan de hand, want dan veranderen achtergrond- en voorgrondkleur geen van beide.

Dit is ook al bij <body> opgegeven, maar sommige mensen hebben bij álle elementen de kleuren veranderd. Het heeft immers weinig zin, als ze dat alleen bij de body doen, terwijl de sitebouwer de kleuren ook bij bijvoorbeeld de paragrafen heeft aangepast.

width: 180px;

Breedte.

margin: 20px auto 0;

Omdat voor links geen waarde is opgegeven, krijgt links automatisch dezelfde waarde als rechts. Hier staat dus eigenlijk 20px auto 0 auto in de volgorde boven – rechts – onder – links.

In kleinere browservensters staan div#links, div#midden en div#rechts niet naast, maar onder elkaar. Een marge van 20 px aan de bovenkant voorkomt dat ze tegen elkaar aan komen te staan.

Links en rechts auto, wat hier hetzelfde betekent als evenveel. Ongeacht hoe breed de ouder is, de <div>'s staan altijd horizontaal gecentreerd binnen hun ouder. Die ouder is hier div#voor-flex. Omdat div#voor-flex een blok-element is, wordt dit normaal genomen even breed als z'n ouder <main>, ook een blok-element. Als blok-element wordt ook <main> normaal genomen even breed als z'n ouder <body>, ook weer een blok-element. Ook <body> wordt normaal genomen even breed als z'n ouder <html>. Omdat <html> het buitenste element is, wordt dit normaal genomen even breed als het venster van de browser.

Als je dit hele verhaal in omgekeerde richting volgt, staan div#midden en div#rechts hierdoor horizontaal gecentreerd binnen het venster van de browser.

border: black solid 1px;

Zwart randje.

h2

Alle <h2>'s. Dat is er hier maar eentje: het begin van de tekst rechts: 'Met translate gecentreerde tekst'.

display: inline;

Een <h2> is een blok-element. De <h2> komt daardoor normaal genomen op een eigen regel te staan. Door van de <h2> een blok-element te maken, komt de erop volgende tekst op dezelfde regel te staan.

font-size: 1.3em;

Lettergrootte iets kleiner maken dan de standaardlettergrootte van een <h2>.

Als eenheid wordt de relatieve eenheid em gebruikt, omdat bij gebruik van een absolute eenheid zoals px niet alle browsers de lettergrootte kunnen veranderen. Zoomen kan wel altijd, ongeacht welke eenheid voor de lettergrootte wordt gebruikt.

css voor vensters minimaal 760 px breed en minimaal 500 px hoog

@media screen and (min-width: 760px) and (min-height: 500px)

De css die hier tot nu toe staat, geldt voor alle browservensters.

De css die binnen deze media query staat, geldt alleen voor vensters die minimaal 760 px breed én minimaal 500 px hoog zijn. In deze grotere vensters worden de pagina en enkele <div>'s verticaal gecentreerd.

@media: geeft aan dat het om css gaat die alleen van toepassing is, als aan bepaalde voorwaarden wordt voldaan. Al langer bestond de mogelijkheid om met behulp van zo'n @media-regel css voor bijvoorbeeld printers op te geven. css3 heeft dat uitgebreid tot bepaalde fysieke eigenschappen, zoals de breedte en hoogte van het venster van de browser.

screen: deze regel geldt alleen voor schermweergave.

and: er komt nog een voorwaarde, waaraan moet worden voldaan.

(min-width: 760px): het venster moet minimaal 760 px breed zijn. Is het venster smaller, dan wordt de css die binnen deze media-regel staat genegeerd.

and: er komt nog een voorwaarde, waaraan moet worden voldaan.

(min-height: 500px): het venster moet minimaal 500 px hoog zijn. Is het venster lager, dan wordt de css die binnen deze media-regel staat genegeerd.

Gelijk na deze regel komt een { te staan, en aan het einde van de css die binnen deze regel valt een bijbehorende afsluitende }. Die zijn in de regel hierboven weggevallen, maar het geheel ziet er zo uit:

@media screen and (min-width: 760px) and (min-height: 500px) { body {color: silver;} (...) rest van de css voor deze @media-regel (...) footer {color: gold;} }

Voor de eerste css binnen deze media-regel staat dus een extra {, en aan het eind staat een extra }.

Als je nou 'n mobieltje hebt met een resolutie van – ik roep maar wat – 1024 x 768 px, dan geldt deze media query toch niet voor dat mobieltje. Terwijl dat toch echt meer dan 760 px breed en meer dan 500 px hoog is. Een vuig complot van gewetenloze multinationals? Voordat je je gaat beklagen bij Radar, zou ik eerst even verder lezen.

Steeds meer mobiele apparaten, maar ook steeds meer gewone beeldschermen, hebben een hogere resolutiedichtheid. Dat wil zeggen dat ze kleinere pixels hebben, die dichter bij elkaar staan. Daardoor zijn foto's, tekst, en dergelijke veel scherper weer te geven. Hoe kleiner de puntjes (de pixels) zijn, waaruit een afbeelding is opgebouwd, hoe duidelijker het wordt.

Er ontstaat alleen één probleem: als je de pixels twee keer zo klein maakt, wordt ook wat je ziet twee keer zo klein. En inmiddels zijn er al apparaten met pixels die meer dan vier keer zo klein zijn. Een lijntje van 1 px breed zou op die apparaten minder dan 'n kwart van de oorspronkelijke breedte krijgen en vrijwel onzichtbaar zijn. Een normale foto zou in een thumbnail veranderen. Kolommen zouden heel smal worden. Tekst zou onleesbaar klein worden. Allemaal fantastisch scherp, maar je hebt 'n vergrootglas nodig om 't te kunnen zien.

Om dit te voorkomen wordt een verschil gemaakt tussen css-pixels en schermpixels (in het Engels 'device pixels'). De css-pixels zijn gebaseerd op de – tot voor kort – normale beeldschermen van de desktop. 1 css-pixel is op zo'n beeldscherm 1 pixel. Het aantal schermpixels is het werkelijk op het apparaat aanwezige aantal pixels (dat is het aantal pixels, waarvoor je hebt betaald).

Dat eerder genoemde mobieltje van 1024 x 768 px heeft wel degelijk het aantal pixels, waarvoor je hebt betaald. Maar die zitten dichter bij elkaar. Op een gewoon beeldscherm zitten 96 pixels per inch, wat wordt uitgedrukt met de eenheid dpi ('dots per inch'). Als dat mobieltje een resolutie van 192 dpi heeft, 192 pixels per inch, zijn de pixels ervan twee keer zo klein als op een origineel beeldscherm. Er zijn per inch twee keer zoveel schermpixels aanwezig.

Om nu te voorkomen dat alles op dat mobieltje twee keer zo klein wordt, geeft het mobieltje niet het echte aantal schermpixels (1024 x 768), maar een lager aantal css-pixels door bij een media query. De 192 dpi van het mobieltje is twee keer zo veel als de 96 dpi van een normaal beeldscherm. Het aantal css-pixels is dan het aantal schermpixels gedeeld door 2. 1024 x 768 gedeeld door 2 is 512 x 384 px. Het aantal css-pixels is 512 x 384 px en zit daarmee dus ruim onder de 760 px breedte én onder de 500 px hoogte van deze media query.

Je bent dus niet opgelicht, of in ieder geval niet wat betreft het aantal pixel.

Door deze truc is een lijn van 1 px breed op een normaal beeldscherm ook op het mobieltje nog steeds 1 px breed, alleen wordt die ene (css‑)pixel opgebouwd uit twee schermpixels (feitelijk vier, want het verhaal geldt voor breedte én hoogte). De dikte van het lijntje is hetzelfde, maar het is veel fijner opgebouwd. Bij lijntjes is dat verschil bijvoorbeeld in bochten goed te zien.

Hetzelfde verhaal geldt voor hogere resoluties, Een tablet met een breedte van 4096 schermpixels en een dpi van 384 (vier keer de originele dichtheid) geeft 4096 gedeeld door 4 = 1024 css-pixel door. Het lijntje van 1 px breedte op de originele monitor is nog steeds 1 css-pixel breed op de tablet, maar die ene css-pixel is nu opgebouwd uit zestien schermpixel.

(Overigens kun je met behulp van media query's ook testen op de resolutie met gebruik van het sleutelwoord 'resolution'. Apple gebruikt het niet-standaard 'device-pixel-ratio', maar het idee is hetzelfde. Dit kan bijvoorbeeld handig zijn om te bepalen, hoe groot een foto moet zijn.)

Kort samengevat: omdat niet het aantal schermpixels (waarvoor je hebt betaald), maar het aantal css-pixels (de door de ontwerper bedoelde afmeting) wordt doorgegeven, wordt voorkomen dat een hogeresolutiescherm onleesbaar klein wordt.

html

Het buitenste element.

height: 100%;

Een hoogte in procenten geldt normaal genomen ten opzichte van de ouder van het element. Omdat <html> het buitenste element is, geldt de hoogte ten opzichte van het venster van de browser. Hiermee wordt <html> even hoog gemaakt als het venster.

Normaal genomen zou <html> niet hoger worden dan nodig is om de pagina weer te kunnen geven, maar nu wordt <html> even hoog als het venster.

Hier gelijk onder wordt <body> even hoog gemaakt als <html>. Als je nu iets verticaal centreert <body>, staat het ook verticaal gecentreerd binnen het browservenster, want <body> en <html> zijn even hoog als dat venster.

body

Voor dit element is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat. (Alleen wat binnen deze media query geldig is, wordt binnen dit blokje herhaald.)

body {background: #ff9; color: black; font-family: Arial, Helvetica, sans-serif; margin: 0; padding: 0;}

display: table;

<body> wordt hiermee van een gewoon blok-element veranderen in een css-tabel. Het enige kind van <body> is <main>, dat bij main wordt veranderd in een css-tabelcel. (De rest van de pagina staat allemaal binnen <main>). Dan heb je dus eigenlijk dit:

<body>(gedraagt zich als <table>) <main>(gedraagt zich als <td>)

(...) rest van de pagina (...)

</main> </body>

Missende elementen van de tabel, zoals de <tr> rondom de <td>, worden automatisch door de browser aangemaakt.

Anders dan bij een html-tabel, waarbij je daadwerkelijk elementen als <table> gebruikt, levert een css-tabel geen problemen op wat betreft zoekmachines, toegankelijkheid, en dergelijke. De html bestaat nog steeds uit volstrekt gangbare <div>'s en dergelijke. Alleen voor de weergave, voor het uiterlijk, wordt gedaan alsof <body> een tabel en <main> een tabelcel is.

Het voordeel hiervan: de inhoud van een tabelcel kan makkelijk verticaal worden gecentreerd met vertical-align: middle;, ook als de hoogte van de inhoud van de tabelcel onbekend is.

Deze methode met behulp van een tabel is de enige veilige manier om een hele pagina verticaal te centreren. Bij gebruik van flexbox of translateY() kan een deel van de pagina aan de bovenkant van het browservenster verdwijnen, waarover meer bij Bekende problemen (en oplossingen) is te vinden. Bij deze methode loop je dat risico niet, want de tabel komt nooit boven het venster uit. Als de pagina hoger is dan het venster, komt het te hoge deel gewoon onder het venster te staan en kan worden bereikt door te scrollen.

width: 750px;

Breedte. Zonder 'n breedte kan de pagina in bredere browservensters wanstaltig breed worden, waardoor tekst veel te breed en daardoor slecht leesbaar kan worden.

height: 100%;

Een hoogte in procenten is normaal genomen ten opzichte van de ouder. Die ouder is hier <html>, die hierboven bij html even hoog als het venster van de browser is gemaakt. Normaal genomen wordt <body> precies hoog genoeg om de pagina weer te kunnen geven, maar nu wordt <body> even hoog als <html> en daarmee ook even hoog als het venster.

De rest van de pagina staat allemaal binnen <main>. Als <main> verticaal wordt gecentreerd binnen <body>, staat daarmee de hele pagina verticaal gecentreerd binnen het venster van de browser, omdat <body> even hoog is als het venster.

font-size: 110%;

Iets groter dan standaard. 't Zal de leeftijd zijn, maar ik vind de standaardgrootte wat te klein.

Als eenheid wordt de relatieve eenheid % gebruikt, omdat bij gebruik van een absolute eenheid zoals px niet alle browsers de lettergrootte kunnen veranderen. Zoomen kan wel altijd, ongeacht welke eenheid voor de lettergrootte wordt gebruikt.

margin: 0 auto;

Omdat voor onder en links geen waarden zijn opgegeven, krijgen die automatisch dezelfde waarde als boven en rechts. Hier staat dus eigenlijk 0 auto 0 auto in de volgorde boven – rechts – onder – links.

Boven en onder geen marge. Links en rechts auto, wat hier hetzelfde betekent als evenveel. Hierdoor staat <body> altijd horizontaal gecentreerd binnen z'n ouder, ongeacht de breedte van die ouder. Die ouder is hier <html>, het buitenste element en daarom normaal genomen even breed als het venster van de browser. Uiteindelijk staat <body> hierdoor horizontaal gecentreerd binnen het venster.

main

Het element waarin de belangrijkste inhoud van de pagina staat. In het voorbeeld is dat de hele pagina.

display: table-cell;

Verander <main> van een blok-element in een css-tabelcel. Dit heeft verder geen enkele invloed op zoekmachines, toegankelijkheid, en dergelijke, omdat het alleen om de weergave gaat. Een iets uitgebreider verhaal hierover staat iets hierover bij display: table; waar <body> wat betreft de weergave in een css-tabel wordt veranderd.

vertical-align: middle;

Een tabelcel is heel simpel verticaal te centreren binnen de tabel, ook als de hoogte onbekend is. De ouder van <main> is <body>. Die is bij body wat betreft de weergave veranderd in een tabel die even hoog is als het venster van de browser. Door de in een tabelcel veranderde <main> verticaal te centreren binnen <body> staat <main> – en daarmee de hele zichtbare inhoud van de pagina – verticaal gecentreerd binnen het venster.

#voor-flex

Voor dit element is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat. (Alleen wat binnen deze media query geldig is, wordt binnen dit blokje herhaald.)

voor-flex {background: yellow; color: black; max-width: 98%; border: black solid 1px;}

Het element met id="voor-flex". Deze <div> is nodig om flexbox te kunnen gebruiken.

display: flex;

Hiermee wordt van div#voor-flex een zogenaamde 'flex container' gemaakt. Binnen een flex container gelden voor de directe kinderen, de zogenaamde 'flex items', aparte regels voor dingen als hoogte, positie, marges, en dergelijke.

Normaal genomen zou deze <div> overbodig zijn, omdat display: flex; ook bij <main> zou kunnen worden gezet. De andere css hieronder is ook wel elders onder te brengen. Maar bij <main> staat al display: table-cell;, dus display: flex; kan daar niet meer worden gebruikt.

Alleen de directe kinderen van een flex container zijn flex items. Alleen daarvoor gelden de speciale regels. Hieronder staat de ingekorte html van dit voorbeeld, die binnen div#voor-flex staat:

<div id="voor-flex"> <div id="links"> <h1>Verticaal gecentreerde (...) </h1> <p>De pagina (...) </p> <div>Ik ben (...) </div> </div> <div id="midden">Verticaal (...) </div> <div id="rechts"> <div> <h2>Met (...) tekst</h2> binnen een (...) achtergrond. </div> </div> </div>

Van de elementen hierboven zijn alleen div#links, div#midden en div#rechts directe kinderen van div#voor-flex. Alleen deze drie <div>'s zijn dus flex items. Alle andere elementen hierboven zijn een nakomeling van een van deze drie <div>'s. Het zijn geen directe kinderen van div#voor-flex en daarom geen flex items.

align-items: center;

Hiermee worden de directe kinderen van flex container div#voor-flex, de flex items, verticaal gecentreerd. Ook als de hoogte daarvan onbekend is. Meer is niet nodig. Die directe kinderen zijn hier div#links, div#midden en div#rechts.

Omdat flexbox speciaal voor dit soort dingen is bedoeld, is het echt uiterst handig in gebruik. Zonder enig gedoe kun je elementen met onbekende hoogte verticaal centreren. Dit kun je trouwens desgewenst per element weer overrulen, door bij het betreffende flex item zelf iets anders op te geven.

Dat div#voor-flex, de flex container, ook geen hoogte heeft, is geen enkel probleem. Op het moment van weergave weet de browser de hoogte, resolutie, en dergelijke van browservenster en scherm. Daardoor kan de browser de hoogte van div#voor-flex en de flex items berekenen en de flex items verticaal centreren. Ook al heeft geen van de elementen een vaste hoogte.

Omdat div#links, de <div> met de tekst links en het blauwe blok, de hoogste is van de drie flex items, bepaalt deze <div> de hoogte van de flex container, van div#voor-flex. Deze <div> is daardoor per definitie even hoog als div#voor-flex en kan dus niet verticaal worden gecentreerd. Althans: formeel theoretisch is div#links verticaal gecentreerd, maar dat kun je niet zien.

div#midden, het middelste witte blokje, wordt wel verticaal gecentreerd door deze regel.

div#rechts, het witte blok rechts wordt ook niet echt verticaal gecentreerd door deze regel. Bij #rechts wordt dit flex item namelijk met align-self: stretch; even hoog gemaakt als <main>, de flex container. Normaal genomen zou deze <div> niet hoger worden dan nodig is voor de weergave van de erin zittende tekst.

Dat de <div> toch gecentreerd lijkt, komt door een marge aan boven- en onderkant van div#rechts.

overflow: hidden;

Browsers die flexbox niet ondersteunen, zetten div#rechts, div#midden en div#links gewoon op een nieuwe regel:

Afbeelding 3: alle divs staan op een nieuwe regel

Ook allerlei andere dingen gaan mis, zoals de breedte bij div#midden. Om flexbox zoveel mogelijk te imiteren voor deze oudere browsers, worden div#links en div#midden daarom naar links en div#rechts naar rechts gefloat.

Dat levert het volgende resultaat op:

Afbeelding 4: door floaten staan de divs naast elkaar

We zien hier in al z'n glorie één van de problemen die door flexbox worden opgelost. div#voor-flex heeft drie kinderen, die alle drie worden gefloat. Normaal genomen zou div#voor-flex precies hoog genoeg worden om de inhoud ervan weer te geven. Maar als die inhoud alleen uit gefloate elementen bestaat, gebeurt dat niet. div#voor-flex heeft geen enkele hoogte. De border staat daardoor bovenaan div#voor-flex als 'n dubbel streepje. Het rechter witte blok wordt absoluut gepositioneerd ten opzichte van div#voor-flex. Omdat div#voor-flex geen hoogte heeft, gaat ook dat mis.

Door overflow: hidden; bij div#voor-flex te zetten, wordt #voor-flex toch hoog genoeg om de inhoud weer te geven. Hierdoor wordt niet alles opgelost, maar het kader rondom #voor-flex staat weer goed, er is een achtergrondkleur en het rechter witte blokje staat niet meer te hoog.

Normaal genomen moet je voorzichtig zijn met overflow: hidden;, want als de inhoud niet in het element past, kan niet worden gescrold. Het teveel verdwijnt gewoon aan de onderkant. Hier kan het echter veilig worden gebruikt, want div#voor-flex heeft geen hoogte gekregen. Als de inhoud van #voor-flex hoger wordt, kan #voor-flex hierdoor gewoon ook hoger worden.

Als een browser flexbox wel ondersteunt, heeft deze regel geen enkele invloed. Een float wordt binnen flexbox volledig genegeerd. In browsers die flexbox ondersteunen, levert floaten dus geen enkel probleem op.

border: black solid 1px;

Zwart randje.

position: relative;

Om een nakomeling van een element te kunnen positioneren ten opzichte van dat element, moet het element zelf een positie hebben. Omdat er verder niets wordt opgegeven bij top en dergelijke, heeft dit geen invloed op het element zelf.

De nakomeling die gepositioneerd moet worden is #rechts div, de <div> binnen div#rechts. Normaal genomen zou je dan div#rechts een relatieve positieve geven en de binnen #rechts div positioneren ten opzichte van z'n ouder div#rechts. Dat kan hier echter niet.

De <div> binnen div#rechts moet halverwege de hoogte van div#rechts komen te staan. Bij #rechts wordt div#rechts, een flex item, met align-self: stretch; even hoog gemaakt als de flex container div#voor-flex. Maar dit werkt niet in browsers die flexbox niet kennen. Daarin heeft div#rechts helemaal geen hoogte, dus er kan ook niets halverwege de hoogte van div#rechts worden gezet.

Bovendien werkt align-self: stretch; bij div#rechts niet goed in alle browsers die flexbox wel ondersteunen. Weliswaar krijgt div#rechts overal de goede hoogte, maar als je vervolgens de <div> in div#rechts op de halve hoogte van div#rechts positioneert, blijken veel browsers toch te denken, dat div#rechts geen hoogte heeft.

Door te positioneren ten opzichte van div#voor-flex, werkt het overal goed.

#links div

Voor dit element is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat. (Alleen wat binnen deze media query geldig is, wordt binnen dit blokje herhaald.)

#links div {background: #0ff; color: black; padding: 5px;}

De <div>'s binnen het element met id="links". Dat is er hier maar eentje: de <div> met het blauwe blok.

width: 87%;

Breedte. Een breedte in procenten is normaal genomen ten opzichte van de ouder van het element, dat is hier div#links.

Waarom 87%? Daar is geen reden voor, vrees ik. Mocht ik ooit nog, na grondig zelfonderzoek, een diep verborgen reden vinden, dan zal ik dat alsnog onmiddellijk melden. Als je geluksgetal 83 of 93 is, dan kun je ook dat percentage veilig gebruiken.

#midden

Voor dit element is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat. (Alleen wat binnen deze media query geldig is, wordt binnen dit blokje herhaald.)

#links, #midden, #rechts div {padding: 5px;}

#midden, #rechts {background: white; color: black; width: 180px; margin: 20px auto 0; border: black solid 1px;}

Het element met id="midden". De <div> met het kleine witte blokje in het midden.

Normaal genomen wordt een <div> op een eigen regel gezet, maar omdat de ouder div#voor-flex met display: flex; bij #voor-flex in een zogenaamde 'flex container' is veranderd, is div#midden in een zogenaamd 'flex item' veranderd. Daardoor kunnen, als je dat wilt, <div>'s op dezelfde regel blijven staan. Hier is dat het geval.

Met align-items: center; is bij #voor-flex opgegeven dat de flex items, waaronder deze <div>, verticaal gecentreerd moeten worden binnen de flex container. Dit werkt ook als, zoals hier, de hoogte van de <div> onbekend is.

width: auto;

Voor kleinere browservensters is eerder bij #midden, #rechts een breedte van 180 px opgegeven. Die wordt hier weggehaald. Normaal genomen wordt een <div> dan even breed als z'n ouder, maar niet als het een flex item is. Nu wordt de <div> niet breder, dan nodig is om de inhoud weer te kunnen geven.

De breedte van flex items kan op allerlei manieren worden gestuurd. In dit geval is voor de meest luie oplossing gekozen: een <br> tussen de woorden 'Verticaal' en 'gecentreerd'.

float: left;

Browsers die flexbox niet ondersteunen, zouden de <div> gewoon op een eigen regel zetten. Door de <div> naar links te floaten, wordt dat voorkomen. Browsers die flexbox kennen, negeren een float bij een flex item.

#rechts

Voor dit element is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat. (Alleen wat binnen deze media query geldig is, wordt binnen dit blokje herhaald.)

#midden, #rechts {background: white; color: black; width: 180px; margin: 20px auto 0; border: black solid 1px;}

Het element met id="rechts". De <div> waarin het witte blokje rechts zit.

Normaal genomen wordt een <div> op een eigen regel gezet, maar omdat de ouder div#voor-flex met display: flex; bij #voor-flex in een zogenaamde 'flex container' is veranderd, is div#rechts in een zogenaamd 'flex item' veranderd. Daardoor kunnen, als je dat wilt, <div>'s op dezelfde regel blijven staan. Hier is dat het geval.

align-self: stretch; Afbeelding 5: div wordt niet hoger dan nodig is

Met align-items: center; is bij #voor-flex opgegeven dat de flex items, waaronder deze <div>, verticaal gecentreerd moeten worden binnen de flex container. De <div> wordt daarbij niet hoger, dan nodig is om de inhoud ervan weer te kunnen geven. Dat zou er uitzien als op de afbeelding hiernaast: de <div> is niet hoger dan nodig en netjes verticaal gecentreerd binnen div#voor-flex, de flex container.

In dit geval moet div#rechts hoger worden dan de erin zittende tekst, omdat de erin zittende tekst later met translateY() verticaal gecentreerd wordt binnen div#rechts. En verticaal centreren kan uiteraard alleen, als div#rechts hoger is dan de erin zittende tekst.

Met behulp van align-self: stretch; wordt div#rechts, even hoog gemaakt als div#voor-flex, de flex container.

Met flexbox kun je bij de flex container (hier div#voor-flex) css opgeven voor álle flex items. Vervolgens kun je bij de afzonderlijke items die css weer overrulen. Wat flexbox inderdaad ongelooflijk flexibel maakt. In dit geval wordt het flex item div#rechts als enige flex item even hoog gemaakt als div#voor-flex.

(Om de afbeelding te maken moest ook even position: absolute; weg bij de in div#rechts zittende <div>, omdat div#rechts anders helemaal geen hoogte had gekregen. Absolute gepositioneerde elementen tellen niet mee voor de hoogte van hun ouder, vandaar.)

Browsers die flexbox niet ondersteunen, negeren deze regel. In die browsers krijgt div#rechts helemaal geen hoogte, omdat er alleen een absoluut gepositioneerde <div> in zit. Bij Bekende problemen (en oplossingen) is te zien, hoe dat eruitziet.

float: right;

Browsers die flexbox niet ondersteunen, zouden de <div> gewoon op een eigen regel zetten. Door de <div> naar rechts te floaten, wordt dat voorkomen. Browsers die flexbox kennen, negeren een float bij een flex item.

margin: 30px 10px 30px auto;

Met behulp van align-self: stretch; is div#rechts iets hierboven even hoog gemaakt als div#voor-flex, de flex container. Hier wordt aan boven- en onderkant een marge van 30 px aan div#rechts gegeven, waardoor boven en onder div#rechts een lege ruimte ontstaat. In die ruimte is de gele achtergrond van div#voor-flex te zien. Hoewel div#rechts verticaal gecentreerd lijkt, is dat dus niet het geval. div#rechts vult, met de marge erboven en eronder, de volle hoogte van div#voor-flex.

Rechts een kleine marge van 10 px voor wat afstand tussen div#rechts en de rechterkant van div#voor-flex.

Links auto als marge. Dit werkt binnen een flex container anders erbuiten. Binnen flexbox betekent margin-left: auto;: zover mogelijk naar rechts zetten. Het heeft hetzelfde effect als float: left;, maar dan zonder de nadelen die 'n float soms kan hebben.

#rechts div

Voor dit element is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat. (Alleen wat binnen deze media query geldig is, wordt binnen dit blokje herhaald.)

#links, #midden, #rechts div {padding: 5px;}

Alle <div>'s binnen het element met id="rechts". Dat is er hier maar eentje: de <div> waarbinnen de tekst in het witte blok rechts zit. Deze <div> is alleen maar nodig om translateY() te kunnen demonstreren. Met behulp daarvan wordt deze <div>, en daarmee de erin zittende tekst, verticaal gecentreerd binnen div#rechts.

background: white;

Witte achtergrond.

Bij #midden, #rechts is al een witte achtergrond gegeven aan div#rechts. Deze <div> staat binnen div#rechts, dus dit lijkt dubbelop. Dat is ook zo voor browsers die flexbox ondersteunen, want in die browsers wordt bij #rechts div#rechts met align-self: stretch; even hoog gemaakt als div#voor-flex. In browsers die flexbox niet ondersteunen, werkt dit niet. Normaal genomen zou div#rechts dan precies hoog genoeg worden om de inhoud ervan weer te geven, maar ook dat werkt hier niet. Alle inhoud van div#rechts zit in deze <div>, en die wordt iets hieronder absoluut gepositioneerd. En absoluut gepositioneerde elementen tellen niet mee voor de hoogte van de ouder. Kortom: div#rechts heeft geen hoogte in browsers die flexbox niet ondersteunen en kan dus ook geen witte achtergrond hebben.

Door aan deze <div> met de tekst ook een witte achtergrond te geven, staat er in ieder geval in deze browsers een witte achtergrond onder de tekst.

color: black;

Voorgrondkleur zwart. Dit is onder andere de kleur van de tekst.

Hoewel dit de standaardkleur is, wordt deze toch specifiek opgegeven. Hierboven is een achtergrondkleur opgegeven. Sommige mensen hebben zelf de voorgrond‑ en/of achtergrondkleur veranderd, bijvoorbeeld omdat ze slecht kleuren kunnen onderscheiden. Als nu de achtergrondkleur wordt veranderd, maar niet de voorgrondkleur, loop je het risico dat tekstkleur en achtergrondkleur te veel op elkaar gaan lijken.

Door beide op te geven, is redelijk zeker dat achtergrond- en tekstkleur genoeg van elkaar blijven verschillen. Als de gebruiker !important heeft gebruikt in een eigen stylesheet, is er nog niets aan de hand, want dan veranderen achtergrond- en voorgrondkleur geen van beide.

Dit is ook al bij <body> opgegeven, maar sommige mensen hebben bij álle elementen de kleuren veranderd. Het heeft immers weinig zin, als ze dat alleen bij de body doen, terwijl de sitebouwer de kleuren ook bij bijvoorbeeld de paragrafen heeft aangepast.

width: 170px;

Breedte.

position: absolute;

Om de <div> absoluut te positioneren. Er wordt gepositioneerd ten opzichte van de eerste voorouder die zelf een positie heeft. Dat is hier div#voor-flex, die bij #voor-flex een relatieve positie heeft gekregen.

Hier gelijk onder wordt de <div> met tekst met top: 50%; halverwege de hoogte van div#voor-flex neergezet. Iets verderop wordt de <div> met transform: translateY(-50%); weer met de helft van z'n eigen hoogte terug naar boven gezet. Nu staat de helft van de <div> met tekst beneden en de helft boven het verticale midden van div#voor-flex.

Speciaal om deze <div> met tekst te kunnen positioneren is aan div#voor-flex een relatieve positie gegeven. Normaal genomen zou je die relatieve positie aan de directe ouder div#rechts van deze <div> geven. Maar in browsers die flexbox niet ondersteunen, heeft div#rechts geen hoogte. De <div> met tekst zou dan halverwege de hoogte van 0 px van div#rechts komen te staan, en dat schiet niet op.

Min of meer toevallig heeft div#voor-flex dezelfde hoogte als div#rechts. Omdat div#voor-flex die hoogte in álle browsers heeft, ook in browsers die flexbox niet ondersteunen, kan worden gepositioneerd ten opzichte van div#voor-flex. En dat werkt in alle browsers.

In dit specifieke geval is er nog een andere reden om te positioneren ten opzichte van div#voor-flex. Met align-self: stretch; is div#rechts bij #rechts even hoog gemaakt als div#voor-flex. Dit werkt echter niet goed in alle browsers. Weliswaar krijgt div#rechts overal de goede hoogte, maar als je vervolgens de <div> met tekst in div#rechts op de halve hoogte van div#rechts positioneert, blijken veel browsers toch nog te denken dat div#rechts geen hoogte heeft. Door te positioneren ten opzichte van div#voor-flex, wordt dit opgelost.

(Dit soort dingen zijn ook de reden dat ik nog steeds zeer terughoudend ben met het gebruik van flexbox. Op internet zie je dat tal van mensen zich halsoverkop volledig op flexbox – en inmiddels ook grid – hebben gestort, maar zodra je iets ingewikkelder dingen wilt gaan doen, blijken er nog enorme verschillen tussen browsers te bestaan. Veel voorbeelden blijken, als je ze in 'n groot aantal browsers test, gewoon niet goed te werken in sommige browsers. Bovendien ondersteunen nog niet alle browsers flexbox, en grid al helemaal nog niet. Maar over – hopelijk – niet al te lange tijd is flexbox gewoon zonder meer te gebruiken, en dan is het fantastisch.)

top: 50%;

Een waarde in procenten bij top is ten opzichte van de hoogte van de eerste voorouder die zelf een positie heeft. Dat is hier div#voor-flex, die bij #voor-flex relatief is gepositioneerd. Hier gelijk onder wordt de <div> met tekst weer de helft van z'n eigen hoogte terug naar boven gezet. Nu staat de <div>, en daarmee de erin zittende tekst, verticaal gecentreerd bonnen div#voor-flex.

-webkit-transform: translateY(-50%); transform: translateY(-50%);

Hier staat in feite twee keer hetzelfde: transform: translateY(-50%);. Waarom dat zo is, staat bij De voorvoegsels -moz-, -ms- en -webkit-.

Met behulp van translateY() wordt een element ten opzichte van zichzelf verplaatst. Bij een positieve waarde naar beneden, bij een negatieve waarde naar boven.

Ook als procenten worden gebruikt, zoals hier het geval is, geldt de verplaatsing ten opzichte van het element zelf. Meestal worden procenten als een percentage van de ouder genomen, maar hier is dat niet het geval. translateY(-50%) betekent hier: zet de <div> de helft van z'n eigen hoogte terug naar boven. Dat die hoogte onbekend is, maakt niets uit. Bij het weergeven van de pagina kent de browser grootte, resolutie, en dergelijke van browservenster en scherm, dus de browser kan dan de precieze verplaatsing berekenen.

Hier gelijk boven is de <div> met top: 50%; halverwege de hoogte van div#voor-flex neergezet. Door de <div> de helft van z'n eigen hoogte terug naar boven te verplaatsen, staat de helft van de <div> nu boven het verticale midden van div#voor-flex, en de helft staat eronder. Oftewel: de <div> is verticaal gecentreerd binnen div#voor-flex. En daarmee ook de in de <div> zittende tekst.