My Web Development Coding Standards
Posted in Microcode on August 13th, 2011 by admin – Be the first to commentSo, I was thinking about the best practices I use in my own development, especially in regards to HTML/CSS/JS and this is what I came up with. Obviously there are as many ways of coding as there are developers (and probably more), but these are ones I’ve found which works for me.
Note I assume a certain level of competency here. I won’t bother with advice like “Never use the FONT tag”, “Never use inline styles” or “Avoid infinite loops” because I think that should be obvious.
HTML:
- Use as few elements as you can.
- Use the appropriate elements.
- If you need the element to be on its own line, use a block element like p or div. If you need the element to flow with the text or be in the same line as other elements, use an inline element like span.
- If you have a list of links, use a UL with LIs.
- You can nest these if you have multiple levels of lists. A nested list should have the following structure:
<ul> <li><a href=”#”>List item in first level</a></li> <li><a href=”#”>Possible header for nested list</a> <ul> <li><a href=”#”>Nested list header</a></li> </ul> </li> </ul> - Avoid using the <br/> element.
- It is semantically meaningless and in almost all cases the appearance can be replicated with CSS.
CSS:
Definitions: (from)
- Rule set:
- The selector, curly braces and contained declarations.
- Selector:
- Everything before the left curly brace. Multiple selectors are combined with commas.
- Declaration:
- A single property/value line.
Naming conventions:
- Never use the same name for both a class and a name.
- This can get very confusing very fast. If there is a single element with id=”leftnav” class=”leftnav”, what does it mean to have another with id=”othernav” class=”leftnav”? One’s the “real” left navigation element, and the other is just kind of a left navigation element?
- Names should be descriptive of the content contained, not the style given.
-
Bad Examples:
#leftnav {} .underline {}Good Examples:
#globalNavigation {} .productList {}
Organization:
- Rule sets should be added to the stylesheet in the following order (comments should delineate each section):
-
- Reset styles which affect HTML elements (e.g., a, ins, del)
- Classes which are used on all (or several) pages (e.g., .clear, .error)
- Classes and IDs which are used for widgets used on the header/footer/gutter or on several pages (e.g., .scrollable, .navigation a)
- Page-specific classes and IDs, and page-specific overrides of classes and elements used above (e.g., #categoryList .scrollable)
A note on websites with large numbers of rule sets.
Before adding a class, look to see if it’s already there. I’ve worked at places with no fewer than five classes which exist solely to clear floats.
Also, realize that multiple classes may be applied to an element. So, in the case of clearing floats, if you need something to have a "clear:both" declaration, and something else, you can add class=”clear something” and both styles will be applied. That said, don’t create a bunch of one-declaration rule sets and have fifteen classes on an element.
Other points of contention
There is a trade off between readability/maintainability and performance. I generally prefer the former to the latter. I think the tools are available to automatically minify/compress CSS and JS such that the authors shouldn’t worry about it.
- One selector per line.
-
Bad Example:
#leftnav ul li,.leftnav,#egbdf,.iLikeLeftMargins{margin-right:11px;}Better Example:
#leftnav ul li, .leftnav, #egbdf, .iLikeLeftMargins { margin-right: 11px; } - Even if multiple selectors share the same declarations, do not group them in the same rule set if they apply to different pages/widgets/elements.
- While you’ll buy some performance gain, it is negligible compared to the maintenance risk.
Bad Example:
ins, .left_nav ul li a:hover, #header a:hover, #header_nav a, #someOtherPage .buttons span.link, #randomElement a, #main_wrapper .breadcrumb a, #idWhichOnlyOccursOnOnePage a{text-decoration:none}Good Example:
Assuming the following global rule sets:
a, a:link, a:active, a:visited { color: #000; text-decoration: none; } a:hover { text-decoration: underline; }This obviates the need for many of the selectors listed above.
/* Generic Styles */ ins { text-decoration: none; } … /* Left navigation */ .ms_left_nav ul li a:hover { text-decoration: none; } … /* Header */ #ms_header a:hover { text-decoration: none; } … /* Product Details */ #dr_ProductDetails .pd_buttons span.pd_Link { text-decoration: none; } … - Always end every declaration with a semicolon.
- This makes maintenance easier as you can add declarations without worrying about semicolons.
- Avoid using the
!importantdeclaration. - It overrides the cascade and makes debugging CSS more difficult. If you’re finding a declaration is not being applied, try changing the selector’s specificity (e.g., add another level to the selector).
ECMAScript (a.k.a., JavaScript™, JScript™)
Naming conventions:
- Be explicit in naming variables, methods, etc..
- In addition to CSS, I also feel readability is paramount in ECMAScript as well. Thus, I will always name a variable “selectedMonth” rather than “m”. Again, minifiers/compressors should be able to help mitigate any issues with verbosity.
- Prefer many shorter functions to one long one.
- I might get in trouble for this one, since there are people who love those functions, but I follow the maxim that a function should do one thing well. For instance, I’ve seen an event handler which was approximately 1000 lines long, which itself made other event bindings. I find it much easier to understand if the binding of the event points to a single function, and that single function is broken up into concrete units of work. This factorization helps with testing and debugging.
- Prefer a single object parameter to multiple simple type parameters
- I only started doing this recently, but it makes refactoring a lot easier if I don’t have to change the signature of a method. Obviously that also obscures what required properties the object parameter must have, etc., but I still find it easier.
- Don’t monkey with the built-in objects.
- I know, it’s very tempting and makes coding a lot easier if you just, say, add a
forEachmethod to theArrayobject if the browser doesn’t have one, but it makes debugging a PITA. How do I know if a bug I’m seeing is in the native implementation or some library’s override? I don’t, and that makes me a sad coder.
jQuery
Recently, I’ve been using a lot of jQuery, so this is a big topic for me.
Naming Conventions
- Prefix variables which will hold the results of a jQuery selection with a dollar sign ($).
- Since jQuery uses the lone dollar sign as its alias, this helps you remember you can use the jQuery methods on the object.
Coding Conventions
I’ve noticed a lot of code in the intrawebbers using jQuery almost exclusively with anonymous methods and the like. I’m not too keen on this trend, as it makes it somewhat difficult to debug and read. I prefer to used named functions and the like, which is not impossible to do with jQuery.
- Cache the results of a selection!
- This one gets the Bee in my Bonnet award for most annoying preventable performance hit. See the example below.
- Use context
- Where possible, use the overload of the jQuery method which takes a context, or use the
find()method. Both are faster than using document as the context as is the default.
Examples for caching and context
Consider the following:
$('a').click(function () {
if ($(this).parent().attr('id') == 'linky-poo') {
$(this).addClass('linky-doo');
$(this).parent().removeClass('linkage'));
$(this).parent().find('a').filter('#' + $(this).attr('id')).css({'font-weight':'bold'});
$('.expandme').each(function () {
if ($(this).attr('class') == 'smushable') {
$(this)[0].style.display = 'none';
$('.linky-doo').attr('data-dohickey', $(this).attr('id'));
$('.linky-doo').show();
$('.linky-doo').css({'color':'#ff0000'});
}
});
}
});
A made-up example, to be sure, but not far from what I’ve seen. So here’s how we can make it better:
- Use
this, if you can. In the event handler,thiswill refer to the current target of the event. Simple attribute queries and additions can be made without the overhead of jQuery, but, if you need it… - Cache $(this), if you need it many times. Every time $(this) is written, you’re asking jQuery to create another object. So, in the example above, a naive refactor would be:
$('a').click(function () { var $me = $(this); if ($me.parent().attr('id') == 'linky-poo') { $me.addClass('linky-doo'); $me.parent().removeClass('linkage'); $me.parent().find('a').filter('#' + this.id).css({'font-weight':'bold'}); $('.expandme').each(function () { var $expander = $(this); if ($expander.attr('class') == 'smushable') { this.style.display = 'none'; // or $expander.hide(); $('.linky-doo').attr('data-dohickey', this.id); $('.linky-doo').show(); $('.linky-doo').css({'color':'#ff0000'}); } }); } }); - Cache other selectors and traversals. Again, each time you call a function, work is done, so if you can only do it once, why not cache the result? Another pass:
$('a').click(function () { var $me = $(this), $myParent = $me.parent(); if ($myParent.attr('id') == 'linky-poo') { $me.addClass('linky-doo'); $myParent.removeClass('linkage'); $myParent.find('a').filter('#' + this.id).css({'font-weight':'bold'}); $('.expandme').each(function () { var $expander = $(this), $linkyDoo = $('.linky-doo'); if ($expander.attr('class') == 'smushable') { this.style.display = 'none'; // or $expander.hide(); $linkyDoo.attr('data-dohickey', this.id); $linkyDoo.show(); $linkyDoo.css({'color':'#ff0000'}); } }); } });
I may add more as I am inspired and comments are made.




