A case study in semantic markup and clean css

Here's an example from a recent template-building project for a major online retailer.

Often when I've found myself working in a busy web production environment, things like semantic Html markup and efficient, well-structured and logically named Css rules seem to be low on the priority list (as long as things look ok on FF3, IE 6 and IE7). In fact there may be a lack of awareness as to how much these practices contribute to workflow and make maintenance easier, as well as making the page load faster.

What is the aim of semantic Html?
A good habit to get into is coding the page purely according to its informational content. Paragraphs, lists and headers should always be enclosed in their appropriate tags. We want to aim at adding the least possible number of divs and classes to the Html. A good way to achieve specific control of the elements is to use a containing div with both an id and a classname. Where you are using multiple stylesheets or need to play it safe with potential clashes of id or classnames, the format #body_shape .item h2 can provide the necessary specificity. I'm also not against using important rules where the level of control over main stylesheets is not available and certain rules need to be overridden.

Always try to correct any mistakes and code bloat if you inherit someone else's code, and introduce best practices wherever possible (as well as checking FF2, Safari and IE8 in addition to the above). It's also a good idea where multiple platforms and OS are not readily available for testing, to make use of online screenshot services like browsercam and Litmus.

When working with templates that are likely to get re-used in full or part this is especially important. It surprises me how often I still encounter horrors like table-based layouts or their Css equivalent of <div class="row"><div class="column">, which Photoshop is known to belch out when slicing and exporting as Html and Css. Just as a web designer or front-end developer who knows his onions is most likely using Notepad++ instead of Dreamweaver, he or she will also know that Photoshop Html and Css is only a guide. This is another reason why we hand-code!

The case study
Here's an example of a template I created with comments explaining my simplifications, naming conventions and browser-specific hacks.
In this example control over the page and Css is restricted by the master templates being powered by a third-party Cms for which we have very limited access. In fact only the center area of the page can be dropped into these templates and no further Css files are allowed. We also cannot use head and body tags, and the Css needs to be placed at the top of the document, above the containing div. In this case we made use of a script to render out includes and Css into a single properties file (all the code generated into a single Html file, with each line escaped with a backslash and a couple of lines of Cms-proprietary code at the top).
The 'Be Inspired' section contains 'Get the Look' and further subcategories, so I have created Css includes for each section. Buttons go in a default Css include, Be Inspired content-wide elements are declared in be_inspired_css.inc etc. Each page uses a containing div like this:
<div id="be_inspired" class="get_the_look">

This allows me to keep the Html clean and free of clutter like unnecessary divs and class names on elements. Remember, good Html markup should be about logically and semantically presenting the information, not the layout.

The Css:

  1. <style type="text/css" media="screen">
  2.  
  3. /*
  4. Default Styles
  5. **************
  6. These get included as default_css.inc
  7. Note we are declaring some global properties for body, html and links, buttons etc that will get re-used, either across the whole site, or at least across the 'Be Inspired' pages.
  8. Hence we use 'be_inspired' as an id name
  9. The button is named dark_button as it is not specific to be inpired etc
  10.  
  11. */
  12.  
  13. body, html {
  14. margin: 0;
  15. background-color: #fff;
  16. text-align: left;
  17. }
  18. a.button {
  19. background: url(images/dark_button_right.jpg) no-repeat scroll top right;
  20. color: #fff !important;
  21. display: block;
  22. float: left;
  23. height: 24px;
  24. margin: 10px 13px 0 0;
  25. padding-right: 10px;
  26. text-decoration: none;
  27. font-weight: bold;
  28. }
  29. a.button:hover {
  30. background: url(images/dark_button_right_over.jpg) no-repeat scroll top right;
  31. text-decoration: none;
  32. color: #fff !important;
  33.  
  34. /*
  35. !important rule forces specificity (overrides any inherited style rules)
  36. */
  37.  
  38. }
  39. a.button span {
  40. background: url(images/dark_button_left.jpg) no-repeat;
  41. display: block;
  42. padding: 4px 0 5px 10px;
  43. }
  44. a.button:hover span {
  45. background: url(images/dark_button_left_over.jpg) no-repeat;
  46. }
  47.  
  48. #be_inspired {
  49. width: 761px;
  50. font-family:Tahoma,Arial,sans-serif;
  51. font-size:11px;
  52. margin: 0 auto;
  53. }
  54. #be_inspired a:hover {color: #cc0000;}
  55.  
  56. #be_inspired_footer {
  57. clear: both;
  58. width: 761px;
  59. height: 100px;
  60. background: url(images/body_shape/body_shape_footer.gif) no-repeat bottom;
  61. }
  62.  
  63. /*
  64. So we can display the header and footer image contents as h1 and h2 for accessibility and SEO:
  65. */
  66.  
  67. #be_inspired h1 {
  68. display: none;
  69. }
  70. #be_inspired_footer h2 {
  71. display: none;
  72. }
  73.  
  74. /*
  75. Page Styles
  76. ***********
  77. The specific Css for this page.
  78. We don't need to use every id to declare specificity.
  79.  
  80. So:
  81. #body_shape_top
  82. #body_shape_top_right
  83. #body_shape_details_box {
  84.  
  85. can be simplified to:
  86. #body_shape_details_box {
  87.  
  88. The name just needs to be specific to the page or template ('body_shape') to ensure that no conflicts are created with parent style sheets.
  89.  
  90. */
  91.  
  92.  
  93. #body_shape_header {
  94. width: 761px;
  95. height: 120px;
  96. background: url(images/body_shape/body_shape_header.gif) no-repeat;
  97. margin-bottom: 16px;
  98. }
  99.  
  100. /*
  101. The header image should be a gif. Same goes for footer
  102. */
  103.  
  104. #body_shape_header p {
  105. margin: 0;
  106. font-size: 120%;
  107. padding: 72px 20px 0 276px;
  108. }
  109. #body_shape_main {
  110. float: left;
  111. position: relative;
  112. }
  113. #body_shape_top {
  114. float: left;
  115. }
  116. #body_shape_top img { /* style the img instead of using a containing div */
  117. display: inline-block;
  118. padding-right: 20px;
  119. float: left;
  120. }
  121. #body_shape_top h2 {
  122. color: #333333;
  123. font-size: 250%;
  124. font-weight: normal;
  125. text-transform: uppercase;
  126. }
  127. #body_shape_top h3 {
  128. color: #333333;
  129. font-size: 150%;
  130. text-transform: uppercase;
  131. font-weight: normal;
  132. }
  133. #body_shape_top h4 {
  134. margin: 0;
  135. color: #333333;
  136. font-size: 110%;
  137. }
  138. #body_shape_top p {
  139. margin: 0;
  140. color: #333333;
  141. font-size: 120%;
  142. padding: 8px 10px 26px 0;
  143. }
  144. #body_shape_top ul {
  145. display: inline-block;
  146. padding-left: 20px;
  147. margin: 15px 0 5px -10px;
  148. }
  149. #body_shape_top ul li {
  150. list-style: none;
  151. color: #333333;
  152. font-size: 120%;
  153. padding: 0 0 10px 30px;
  154. text-transform: uppercase;
  155. background: url(images/be_inspired/be_inspired_tick.gif) no-repeat 3px 0;
  156. /*
  157. The tick and bullets are common elements (2 sizes max) across be inspired pages,
  158. so should be named be_inspired_tick.gif and not body_shape..
  159. */
  160. }
  161. #body_shape_details_box {
  162. width: 290px;
  163. float: left;
  164. border: 1px solid #333;
  165. margin: 8px 0 26px 0;
  166. }
  167. #body_shape_bottom {
  168. width: 759px;
  169. float: left;
  170. border: 1px solid #8c8c8c;
  171. margin: 16px 0 20px 0;
  172. background: url(images/body_shape/body_shape_style_tips.jpg) no-repeat top left;
  173.  
  174. /*
  175. Browser specific hacks:
  176. ***********************
  177. * targets IE7 and below (commonly mistaken for the star HTML hack)
  178. _ targets IE6 and below
  179. We don't need to support IE5.5!!
  180.  
  181. IE8 needs some more attention as IE7 and IE8 installations cannot currently be run side by side
  182. (as can be done with MultipleIE (<a href="http://tredosoft.com/Multiple_IE" title="http://tredosoft.com/Multiple_IE">http://tredosoft.com/Multiple_IE</a>)
  183. IE Tester (<a href="http://www.my-debugbar.com/wiki/IETester/HomePage" title="http://www.my-debugbar.com/wiki/IETester/HomePage">http://www.my-debugbar.com/wiki/IETester/HomePage</a>) is a good emulator but we should also be keeping at least one machine
  184. running IE7 for bulletproof testing
  185. IE8 compatibility view, which is meant to emulate IE7 rendering is not entirely accurate and shouldn't be relied on for testing
  186. It can be forced like this if necessary:
  187. <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
  188. though this is not advisable
  189. */
  190.  
  191. padding-top: 60px;
  192. *padding: 60px 0 20px 0; /* IE 7 and below */
  193. _padding: 60px 0 20px 0; /* IE 6 and below */
  194. }
  195.  
  196. #body_shape_bottom
  197. .item {
  198. width: 330px;
  199. float: left;
  200. margin: 0 20px 20px 20px;
  201. _margin: 0 20px 20px 10px;
  202. }
  203. #body_shape_bottom
  204. .item img {
  205. _display: inline-block;
  206. float: left;
  207. margin-right: 10px;
  208. }
  209. #body_shape_bottom
  210. .item h2 {
  211. margin: 0;
  212. padding: 0 0 0 10px;
  213. font-size: 146%;
  214. color: #333333;
  215. text-transform: uppercase;
  216. }
  217. #body_shape_bottom
  218. .item ul {
  219. _display: inline-block;
  220. overflow: auto;
  221. margin: 10px 0 0 0px;
  222. padding: 0;
  223. }
  224. #body_shape_bottom
  225. .item li {
  226. list-style: none;
  227. font-size: 110%;
  228. padding: 4px 10px 6px 20px;
  229. color: #333333;
  230. background: url(images/be_inspired/be_inspired_bullet.gif) no-repeat 0 8px;
  231. }
  232.  
  233. </style>

The Html:

  1. <div id="be_inspired">
  2. <div id="body_shape_header">
  3. <!-- <h1> is specified and set to display: none for accessibility and SEO -->
  4.  
  5. <h1>Body Shape Guide: Tips for your shape</h1>
  6. <p>To help you shop for your shape we&rsquo;ve devised a handy guide that will ensure effortless style is easy to accomplish. Take a look at the body shape profile below and learn some tricks of the trade for flattering your figure.</p>
  7. </div>
  8.  
  9. <div id="body_shape_top">
  10. <img src="images/body_shape/body_shape_main.jpg" />
  11. <h2>Athletic</h2>
  12. <h4>You fit this shape if you have:</h4>
  13.  
  14.  
  15. <div id="body_shape_details_box">
  16. <ul>
  17. <li>A lean rectangular torso</li>
  18. <li>Long slim legs</li>
  19. <li>A small bust</li>
  20. </ul>
  21. </div>
  22.  
  23.  
  24. <h3>Cameron Diaz</h3>
  25. <p>With a naturally slim figure, Cameron Diaz is toned and slender making it easy for her to experiment with trends and patterns.</p>
  26. <h3>Your think rule before you buy</h3>
  27. <p>The key to dressing for your shape is to create the illusion of curves with tailored shapes and styles.</p>
  28. <a href="#" class="button"><span>Shop Womenswear</span></a>
  29. </div>
  30.  
  31.  
  32. <div id="body_shape_bottom">
  33.  
  34. <!--
  35. Rather than using rows and columns, and left, middle, top, bottom divs for everything,
  36. we can use one div box ('item') and control layout by styling the img, h2 and ul.
  37. The aim should always be to avoid nesting divs and declaring classes where simple markup can achieve the same layout.
  38. Position: relative is only really required where you want to ensure specific positioning of a child element,
  39. not necessary to declare it on every div!
  40. If you want to do that, for example to set a default margin: 0, declare it on body, html {margin: 0;}
  41.  
  42. -->
  43.  
  44. <div class="item">
  45. <img src="images/body_shape/body_shape_tops.jpg" />
  46. <h2>Tops</h2>
  47. <ul>
  48. <li>Make the most of your slender arms with short-sleeved or sleeveless tops</li>
  49. <li>Add volume to your top half with ruffle and bead detailing</li>
  50.  
  51. </ul>
  52. </div>
  53.  
  54. <!--
  55. Compare the above to the original markup:
  56. <div class="row">
  57. <div class="column">
  58. <div class="item">
  59. <div class="item_left">
  60. <img src="images/body_shape_tops.jpg" />
  61. </div>
  62. <div class="item_right">
  63. <h2>Tops</h2>
  64. <ul>
  65. <li>Make the most of your slender arms with short-sleeved or sleeveless tops</li>
  66. <li>Add volume to your top half with ruffle and bead detailing</li>
  67. </ul>
  68. </div>
  69. </div>
  70. </div>
  71. </div>
  72. -->
  73.  
  74. <div class="item">
  75. <img src="images/body_shape/skirts_and_trousers.jpg" />
  76. <h2>Skirts &amp; trousers</h2>
  77. <ul>
  78.  
  79. <li>Keep it short with flared or A-line skirts that fall to the knee or above</li>
  80. <li>Skinny jeans are a must for accentuating your long lean legs</li>
  81. </ul>
  82. </div>
  83.  
  84. <div class="item">
  85. <img src="images/body_shape/body_shape_dresses.jpg" />
  86. <h2>Dresses</h2>
  87.  
  88. <ul>
  89. <li>Experiment with interesting patterns and horizontal lines that create curves in all the right places</li>
  90. <li>Be brave in strapless, Grecian and one-shoulder style dresses</li>
  91. </ul>
  92. </div>
  93.  
  94. <div class="item">
  95. <img src="images/body_shape/body_shape_coats.jpg" />
  96. <h2>Coats &amp; Jackets</h2>
  97.  
  98. <ul>
  99. <li>Smart jackets or tailored blazers are shaped to give you extra waist definition</li>
  100. <li>Don’t hide your body beneath baggy, oversized or shapeless clothing</li>
  101. </ul>
  102. </div>
  103.  
  104. <div class="item">
  105. <img src="images/body_shape/body_shape_accessories.jpg" />
  106. <h2>Accessories</h2>
  107.  
  108. <ul>
  109. <li>A stack of bold bangles will show off nicely toned arms</li>
  110. <li>Go for slouchy or hobo bags to soften the angles of your body</li>
  111. </ul>
  112. </div>
  113.  
  114. <div class="item">
  115. <img src="images/body_shape/body_shape_lingerie.jpg" />
  116. <h2>Lingerie</h2>
  117.  
  118. <ul>
  119. <li>If you want to enhance your bust, try a well fitting, push up or gel-filled bra</li>
  120. <li>Avoid low plunging necklines and bare your back and shoulders instead</li>
  121. </ul>
  122. </div>
  123. </div>
  124.  
  125. <div id="be_inspired_footer">
  126.  
  127. <!--
  128. <div class="clear"></div> is not necessary here as that style can be applied in the stylesheet like this:
  129. #generic_footer {clear: both;}
  130. <h2> is included and set to display: none for accessibility and SEO
  131. -->
  132.  
  133.  
  134. <h2>Be Inspired: Real Advice for Real Women</h2>
  135. </div>
  136. </div>