Fronteers — vakvereniging voor front-end developers

Patronen voor de groei

Zelf, met de hand, een website maken is tegenwoordig zo lastig nog niet. Echter, een grote maatwerk website is heel andere koek. In het begin lijkt het wel simpel maar iedere beslissing heeft invloed op je volgende beslissing en één verkeerde beslissing kan heel snel tot frustratie leiden. Mocht je toevallig het (on)geluk hebben om meerdere grote websites te maken en te onderhouden, dan ben je, als je niet uitkijkt, al heel snel de sigaar.

Waarom? Niets blijft hetzelfde en het maken van een website is een oefening in constante verandering.

HTML wil je zo hebben dat je het achteraf niet hoeft aan te passen voor CSS of JavaScript. Dergelijke aanpassingen zijn duur, omdat je met nog meer onderhoud wordt opgezadeld, wat uiteindelijk ook de duurzaamheid van je product aantast. Erger nog, het is meestal onnodig en makkelijker te voorkomen dan je denkt.

De truc is om binnen de drie front-end gebieden (HTML, CSS en JavaScript) generiek te zijn waar deze gebieden elkaar raken en specifiek te zijn binnen een enkel gebied.

Structuurpatroon

Generiek: HTML & JavaScript:

<script src="init.js"></script>

Specifiek: JavaScript:

require(['jquery','jquery-ui','validation'],function(){ … });

Generiek: HTML & CSS:

<link href="main.css" />

Specifiek: CSS:

@import url(../normalize.css);
@import url(../forms.css);

Preprocessors zijn uitermate geschikt voor dit soort concatinatie

Op deze manier is de kans vele malen groter dat de HTML bij aanpassingen aan de website buiten schot blijft.

OO CSS en de recentere SMACSS zijn ontstaan, omdat grote schaalbare websites een robuuste front-end structuur nodig hebben. Er is simpelweg geen ruimte om even wat te proberen en weer bij te sturen.

Doordat front-end kennis over de jaren iets beter is geworden hebben we de wat starre OO CSS minder hard nodig. De komst van HTML5, CSS3, preprocessors en dependency loaders maken het namelijk eenvoudiger om een duurzaam semantische website op te leveren. SMACSS, bijvoorbeeld, is door de huidige ontwikkelingen eenvoudiger aan te leren, wat de duurzaamheid weer ten goede komt.

Nulpatroon

Resets lijken best handig. Websites in meerdere browservarianten (cross-browser) gelijkend te krijgen is precies wat we allemaal nodig hebben, zou je denken. Om resets echt handig te maken moet ze je van patronen voorzien om ze niet achteraf weer recht te trekken. Aan elementen die op nul zijn gezet heb je niets. Een paragraaf heeft normaliter een witregel aan de onderkant. Een tabelkop is meestal vet 'gedrukt'. Laat ik het zo zeggen: een site moet met een 'reset' vergelijkbaar weergeven en vooral cross-browser gelijkend weergeven alsof men geen CSS had toegepast.

Basistoevoegingen die projectspecifiek zijn, zijn uiteraard welkom. Mogelijk met een specifieke font-family en/of font-size voor de headings, <h1>, <h2>, enz.

Browsers die het heel anders doen bestaan niet meer (zwaait naar IE6), wat de nul-reset onzinnig gemaakt heeft, maar CSS zoals normalise.css* zal als een startpunt waarschijnlijk wel nuttig blijven.

* normalize.css bevat nog wel browserspecifieke hacks en hierdoor kan ik het niet zonder reserveringen aanbevelen. Wel kan ik het aanraden om door te nemen; er valt veel van te leren en te lenen.

Content patronen

ID-attributen zijn lastig, omdat ze vaak de basis vormen voor koppeling met de back-end. Je bespaart jezelf een hoop ellende door ze uit je CSS te houden. Beperk ze desnoods tot een handjevol, want ze kunnen ook handig zijn voor performance. Class-attributen zijn ook lastig, maar daar hoeven we ons minder zorgen over te maken. Een deel van de semantische attributen zijn door HTML5-tags opgevangen. Dat scheelt een heleboel onnodige attributen!

  • Niet altijd mogelijk, maar probeer het gebruik van ID’s voor CSS te vermijden
  • Overdadig gebruik van het class-attribuut is net zo slecht als overal <div>'s plaatsen
  • Schrijf functionele ID's en classnames zoals; 'progress', 'sign-in' of 'contact'
  • Niet functioneel? Maak deze attributen generiek; 'module','warning' of 'information'
  • Schrijf attributen in de taal van de opmaakcode. HTML is Amerikaans Engels (en-US)
  • Uitzondering is uiteraard een ID voor een 'hash tag' (<a href=”#informatie”>Lees meer</a>, <section id="informatie">Lorem ipsum…</section>)

Contentspecifieke namen zoals 'dataGridProgress' zijn eigelijk uit den boze en geven meestal dezelfde problemen als attributen die de presentatie spiegelen, zoals:

.blue { color: blue; }

Webformulieren kunnen eenvoudig generiek worden opgemaakt om vervolgens met een productpatroon te worden aangevuld. Een eenvoudig formulier voor een aanmeldmodule:

<form id="sendToBackEnd" class="module log-in">
<fieldset>
<div>
<label for="">E-mail</label>
<input type="email" value="" placeholder="Enter you e-mail address" />
</div>
<div>
<label for="">Password</label>
<input type="password" placeholder="password" />
</div>
</fieldset>
<div class="buttons">
<button type="submit">log in</button>
</div>
</form>

Maar waarom die extra <div>'s? Semantisch gezien zijn labels met invoervelden nu gescheiden maar belangrijker is dat we dit HTML-patroon op verschillende manieren kunnen vormgeven dankzij de extra <div> om de <label> en <input>. Met grote websites is het altijd moeilijker om de HTML aan te passen dan de CSS. HTML dat continue groeit zorgt er vaak ook voor dat de CSS meegroeit. Idealiter beperk je de impact van dergelijke groei, maar de realiteit denkt daar vaak anders over. Zelfs de grootste controlfreak kan daar weinig aan doen. Jens Meiert mag het nog een keer uitleggen: Get the HTML right.

Zoals je het wellicht is opgevallen ga ik hier niet in op de discussie over semantiek; daar is door de jaren heen alles over gezegd en er sindsdien weinig veranderd.

DRY

Patronen worden pas nuttig als deze zijn vastgelegd. Productiecode van een website is op zichzelf geen documentatie en is als zodanig ongeschikt. Achteraf discussies voeren over de semantiek in die code heeft op zichzelf weinig waarde. Bepaal vooraf de basispatronen die je voor een website nodig hebt zodat je niet iedere keer het wiel moet uitvinden. Discussies steeds opnieuw moeten voeren is zonde van je tijd. Tip: Pattern Primer van Jeremy Keith.

Maatwerkpatroon

Met de basis- en standaardpatronen onder je arm kun je nu los met maatwerk CSS. Dit is meestal waar het meteen al scheef gaat. Omdat 'nieuw' vaak gelijk is aan 'we proberen wel wat' en we vervuilen hiermee de HTML en CSS door het te laten staan. Wat niet werkt meteen verwijderen! Dit is waar SMACSS je als gids kan helpen. Beperk je HTML, beperk je classnamen en ID-attributen en beperk je selectorlengte in CSS! Specificity kills! Om dit te realiseren zul je regelmatig moeten beoordelen of je een refactorronde moet inlassen.

  • Een basis die geschikt is om te bootstrappen; FE-Patterns, HTML5 Boilerplate of (ik ben er geen fan van: 960 grid)
  • Gebruik een modulaire aanpak; SMACSS of OO CSS.
  • Overweeg een pre-parser; LESS, Sass of Stylus (met mixins en variabelen mag je weer wat specifieker zijn omdat die binnen de CSS zuil blijven)

Dit is uiteraard maar een begin en patronen zijn een goed begin voor ieder project. Daar worden ze namelijk groot en sterk van.

Dus, waar wacht je nog op!? Start je volgende project met een van de bovenstaande patronen of bouw ze zelf!

Reacties

1 Blaise op 03-12-2011 om 12:24 uur:
Mijn ervaring met grote websites, die steeds verder uitdijen zonder dat je daar van tevoren zicht op hebt, is om modulair te werken, met een nette, strakke basis als gemene deler.

Basis voor CSS is een reset, de groffe structuur van pagina's, typografie, en terugkerende elementen zoals sidebar, formulieren, menu's, buttons.

De basis voor Javascript is een framework, en eventueel plugins voor validatie van formulieren en andere terugkerende (DOM) interactie, zoals een lightbox script.

Voor HTML zorg je dat je een template engine hebt die template inheritance ondersteunt zodat je meerdere basistemplates kan maken die je later kan extenden.

Als je later nieuwe secties toevoegt aan een website hoef je alleen nog maar toe te voegen en niets weg te halen. Als er iets aan de basis moet veranderen hoeft dat maar op een plek.

Dit werkt vooral goed als ook de ontwerper van consistentie houdt, want dan heb je bij een nieuwe sectie al bijna alles in de basis gedefinieerd.

Of je dan id's of classes gebruikt, voor welke CSS reset je kiest en of je een CSS preparser gebruikt maakt niet uit. Dat zijn implementatiedetails. Modulariteit als concept is belangrijk. Dat kan op verschillende manieren, waarbij iedereen zijn eigen voorkeur heeft.
2 Sander Aarts op 03-12-2011 om 18:43 uur:
"ID-attributen zijn lastig, omdat ze vaak de basis vormen voor koppeling met de back-end."

Aan wat voor backend-koppeling moet ik hierbij denken?
3 Egor Kloos op 04-12-2011 om 00:01 uur:
Denk maar aan JSF bijvoorbeeld, die zelf de javascript regelt. Dergelijke 'web' systemen schrijven zelf de ID's uit in de HTML en dan is het niet handig om daar CSS aan te hangen.
4 Tom Greuter op 04-12-2011 om 00:15 uur:
Mee eens. Noem eens een Java- of .Net-CMS dat niet een spervuur van ID's op de HTML opent.
5 Sander Aarts op 04-12-2011 om 11:49 uur:
Lijken me sowieso geen systemen waar je als front-end developer mee wil werken dan.
Om het op z'n Brabants te zeggen: "Wie 's hier nou de front-end, gij of ik?"
6 Mathijs de Jong op 05-12-2011 om 00:06 uur:
@Sander mee eens, maar helaas heb je als frontend dev niet altijd het laatste woord over welk backend product gebruikt gaat worden. Frontend staat nooit helemaal op zich zelf. Vaak heb je te maken met backend dev's die of niet capabel genoeg zijn of nu eenmaal met een bepaald product / taal werken, waardoor je niet om gegenereerde ID's heen kunt.

Controle op ID's op niet dynamische elementen is meestal geen probleem; dynamische en dus gegenereerde elementen kunnen ID's hebben die puur de relatie met backend in stand houden. Zolang je als frontend dev maar duidelijke, inhoudelijk beschrijvende en generieke classNames gebruikt kun je prima modulaire code schrijven.

Ik ben heel benieuwd naar conventies voor modulaire frontend voor custom data attributen (html5 data-*). Heb recent te maken met .Net MVC 'client-side form validation' volgens Microsoft; waarbij bijv. data-val="true" en data-val-required="message" een validatie voor een required field opleggen. In mijn ogen niet semantisch en beschrijvend, laat staan modulair...
7 Bjorn op 05-12-2011 om 09:55 uur:
Ben het grotendeels eens met jouw artikel, op de spatiefoutjes na dan. En JSF? Niet gebruiken dat ellendige ding!
8 Krijn op 05-12-2011 om 10:34 uur:
@Bjorn: spatiefoutjes fixed, thanks!
Plaats een reactie