28 januari, 2011
Iedere front-end developer kent het probleem: je hebt een onbekend aantal blokken, waar je steeds bijvoorbeeld vijf blokken per rij wilt weergeven, met een klein beetje ruimte tussen ieder blok. Je site is de gangbare 960 pixels breed, en de blokken moeten de volledige breedte bestrijken. Om dit passend te krijgen moet het laatst blok geen marge meekrijgen. Javascript, server-side, pseudo-classes; is er geen elegantere oplossing? Jawel hoor; de blokkendoos.

Laat ik vooraf het volgende duidelijk maken; ik kan niet wachten tot de :nth-of-type pseudo-class door alle browsers wordt ondersteund, want deze wonder-selector bespaart ons als front-end developers flink wat tijd, en flirt er ondertussen lustig op los met mijn codepuristische hersenkwab. Toch is dat – ook semantisch gezien – niet de meest nette oplossing, omdat het suggereert dat deze elementen anders zijn dan de overige elementen, terwijl het probleem een niveau hoger ligt. Dus moeten we het ook daar oplossen.
Stel: we willen 3 gelijke blokken van 310 x 310 pixels op een pagina met een breedte van 960 pixels uitvullen tot de beide randen met steeds netjes 15 pixels marge er tussen. Drie elementen is 930 pixels plus 3 x 15 pixels marge aan de rec… Inderdaad. Eenmaal marge teveel.

Normaliter geef je dit derde element een class-name die de marge aan de rechterzijde verwijderd voor alleen dit element. En als je de luxe van een CMS hebt geef je de back-end developer de opdracht om íeder derde item deze class mee te geven, of je kunt automatisch classnames toekennen middels Javascript. Of desnoods via een stagiair die het handmatig toevoegt aan de betreffende elementen. En ik heb de afgelopen jaren eigenlijk alle methodieken wel geprobeerd (met uitzondering van het inzetten van een stagiair natuurlijk!…), maar vond het vrijwel altijd simpelweg de verkeerde beredenering. Deze elementen zijn helemaal geen zonderlingen, dus moeten we ze ook niet als zodanig behandelen.
In plaats daarvan plaats ik de elementen in een container (in dit geval #blokkendoos) die de breedte van het parent-element + eenmaal de marge is. Dit element plaats je met position: relative; 15 pixels naar links, zodat er visueel niets veranderd en de elementen netjes uitlijnen.
.wrapper {
width: 960px;
}
.item {
display: block;
width: 310px;
height: 310px;
margin: 0px 15px 15px 0px; /* = width = 325px */
}

.wrapper {
width: 960px;
}
.blokkendoos {
width: 975px;
position: relative;
left: -15px;
}
.item {
display: block;
width: 310px;
height: 310px;
margin: 0px 0px 15px 15px;
}
Wat ik prettig vind, is dat de blokken zowel visueel als sematisch gelijk blijven aan elkaar. Je zou dit kunnen lezen en denken: waarom creëer je een nieuw element om items heen om een paar classjes te besparen? Het voordeel is dat dit extra element alleen maar bevestigd dat deze elementen bij elkaar passen. De allermooiste oplossing is dan ook om – indien dit semantisch klopt – de elementen als <li>‘s in een <ul> of <ol> te plaatsen en deze als blokkendoos te gebruiken.
Ik ben erg benieuwd naar jouw mening over deze methode, dus deel je visie en ideeën door een reactie te plaatsen!
Categorieën: Best Practice, Inspiratie, Schone code
Yep, ik gebruik deze methode ook. Af en toe wel problemen in IE6/7 die moeite hebben met negatieve margins, maar door de container hasLayout te geven werkt het (meestal) prima.
Wat wel lastiger is, is als je te maken krijgt met items zonder vaste hoogte. Tuurlijk kun je iedere :nth-child via JS een class mee geven, zodat de floats correct worden gecleard – maar dat gaat niet werken als een sublayout op meerdere plekken (met verschillende breedtes) wilt gebruiken.
Meestal werkt display:inline-block i.c.m. een vertical-align dan wel – maar de support hiervoor ontbreekt grotendeels in IE6/IE7 – dus moet je daar display:inline gebruiken e.d.
Uitstekende oplossing. Grootste voordeel is nog dat (bij een volledig flexibele layout) wanneer de blokkendoos smaller is dan de oorspronkelijke breedte (en er dus minder blokken op één rij passen), de blokken nog steeds goed vallen omdat ze allemaal hun rechtermarge hebben. Je kunt dus fixed width blokken en een blokkendoos met flex width plaatsen en het gaat altijd goed. De blokken vullen alleen niet meer de volledige breedte, maar dat is te overzien. Progressive enhancement :)
@jaspervdkamp Ja, inderdaad, dat is nog wel een mooi bijkomend voordeel inderdaad. Thanks! ;-)
in het 960-gridsystem wordt het opgelost door de blokken zowel een linker- als een rechtermarge te geven, maar in jouw voorbeeld is dat ook weer geen echt goed alternatief. Fijn, zo’n puzzel :)
Jouw oplossing lijkt me goed, maar als je een ander element links naast jouw blokkendoos hebt staan, kan die daar weer last van gaan krijgen.
ik denk stiekem dat ik het zelf toch zou zoeken in een linker+rechtermarge; doe ik in mijn huidige project ook, tot volle tevredenheid (voor zover je in ons mooie vak überhaupt ooit tevreden kan zijn ;)
@grimmweb Buiten dat ik 960.gs echt semantische rommel vind uitspugen denk ik dat deze oplossing prima werkt met andere blokken er naast, omdat het niets vreemds doen met de hiërarchie. Door de position: relative verandert er niets ten opzichte van de omgeving maar is het puur een kleine tweak waarmee het element los uit het lood staat zonder beinvloeding van de omgeving.
yes, de classnamen van 960.gs zijn semantisch ruk, maar de layout is wel lekker vloeibaar. Ik pas daarom ook alleen het principe toe (en hun hele fijne reset.css), niet de code ;)
V.w.b. dat uit het lood trekken ben ik in IE6 wel eens tegen een probleempje aangelopen, daarom probeer ik dat toch zo min mogelijk te doen.
@grimmweb Dat is waar, IE6 kan issues geven met deze aanpak, maar in mijn testbestanden was dat allemaal af te vangen met de hasLayout-fix, maar het blijft tricky inderdaad.
En ach, hoewel ik dat als codepurist natuurlijk niet hardop mag uitspreken; IE6 kan de boom in ;-)
.. en als in die boom een touw geknoopt is, weet-ie wat-ie ermee kan doen :)
Ik heb in mijn huidige project (Nationaal Archief) de wedstrijdleiding eindelijk zover dat we IE6 alleen nog functioneel ondersteunen, dus een scheve box hier en daar moet kunnen, hoewel het tot nu toe best meevalt (afkloppen) ;)
@grimmweb Het is ook mijn bescheiden mening dat een IE-stylesheet ook de grootste nonsens is. Als je voor een goede opbouw kiest is er bijna geen noodzaak voor zo’n aparte stylesheet, op een paar kleine bekende bugs na. En zelfs die zijn dan nog te verwaarlozen.
Wel mooie klant trouwens, veel plezier daarmee, cool! :)