• CSS Best Practices

last modified March 23, 2009 by ejucovy

What we're shooting for: simple, semantic, reusable markup, tied to organized CSS.

  • Simple: Keep class names as simple as possible while using The OC and sticking with our naming conventions.
  • Semantic: Use <h1>, <h2>, etc. for headings, <ul> for unordered lists, <ol> for ordered lists, etc. Use generic <div>s & <span>s as little as possible. (Almost) never use tables for layout.
  • Reusable: Find patterns and use existing markup whenever possible. Keep developers out of the CSS file as much as possible.



  • Focus on structure. Build proper XHTML rather than trying to make things look a certain way.
  • Nest your html properly. A tab is equal to 2 spaces.
  • Comment the end of your elements.
    eg, </div><!-- end .myLongDiv -->
  • Use reusable components.
  • Set scope on table headers. For <th>s that describe columns then scope=”col”. For rows, then scope=”row”.


  • Implement wireframes. We love Mouna’s magnificent mockups, but you should be working to build the structure and functionality, not the presentation.
  • Create unnecessary classes or IDs. Do use the ones already provided and talk to us if you need new ones.
  • Use arbitrary headings. Pick heading tags for outline hierarchy, not for size.
  • Use tables for layout. But do use them for tabular data and forms as appropriate.

Class naming conventions

  • Since our markup and CSS will need to be ported into other people’s sites via Deliverance, we’ll add an oc- namespace to all our classes and IDs (in addition to following our other naming rules). This will avoid any conflicts with styles in the parent site.

Hierarchical classes:
Hierarchical elements take class names from their parents, within reason. The idea is to keep it consistent while avoiding 10-part class names. Use your best judgement here.

<div class="oc-widget oc-widget-feed“>
  <h2>Recently updated projects</h2>
  <ul class=”oc-widget-feed-list“>
    <li class=”oc-feed-item oc-clearAfter” tal:repeat=”project view/recentprojects”>
      <img class=”oc-avatar” src=”" tal:attributes=”src project/image_src | nothing” />
      <h3 class=”oc-feed-item-title“>
            <a href=”" tal:attributes=”href project/absolute_url” tal:content=”nocall: project/title”>Project Title</a>
      <p class=”oc-feed-item-data oc-discreetText” tal:define=”nmembers python: len(project.projectMemberIds())”>
        <span tal:replace=”nmembers”>YY</span> member<span tal:condition=”python: nmembers > 1″ tal:replace=”string:s” />, active since <span tal:replace=”python: view.create_date(project)”>Jan 1937</span>
      <p class=”oc-feed-item-description” tal:content=”project/mission | string: project mission statement goes here”>
        This is the descriptive text for a project. Apparently it doesn’t quite work right yet. Is there even a field for users to fill out or entry to call from a database?
  </ul><!– end .oc-widget-feed-list –>
</div><!– end .oc-widget-feed –>

Reusable/generic classes:
Reusable / generic classes can go anywhere, without specifying anything more. For example, an oc-headingBlock can go inside any block-level element, including “widgets”.

<div class="oc-headingBlock">
   <h1>Projects on OpenPlans</h1>
   <p class="oc-headingContext">Currently serving <span tal:replace="view/nprojects"/> projects</p>
</div><!-- end .oc-headingBlock -->

Two-class naming structure for generics.
First class name defines generic. Second enables customizations.

<div class="oc-widget oc-widget-feed“>

<!– some stuff –>

</div><!– end .oc-widget.oc-widget-feed –>

Case studies:
A few code examples here… (simple to complex)

  1. Feed
  2. Wiki
  3. Forms


Forms can be complicated. Here are a few guidelines to take the pain away.

  • Use fieldsets to group sections of forms and related inputs
  • Use tables to group labels, inputs, and help.  Using tables to lay out forms isn’t the best, in terms of semantic markup, but we’re making a slight compromise here to ease development.

<form id="oc-join-form" name="edit_form" method="post" enctype="multipart/form-data" action="/portal_memberdata/portal_factory/OpenMember/openmember.2007-05-08.0523490218/reg_form">
	  <legend class="headingBlock">
		<h1>Join OpenPlans</h1>
		<p class="oc-headingContext">Registration is free and your email will not be
		shared with anyone, however, you will need to confirm your email address in order to avoid
		spam bots abusing this system
	  <table class="oc-form">
		  <tr class="oc-form-row">
			<th scope="row" class="oc-form-label">
			  <label for="">Username</label>
			<td class="oc-form-value">
			  <input type="text" name="__ac_name" id="__ac_name" />
			<td class="oc-form-help">
			  <span class="oc-form-context">
			  	Pick something funny
			  <span id="oc-username-validator" class="oc-form-validator">
			  	Sorry, that username is taken
		  <tr class="oc-form-row">
			<th scope="row" class="oc-form-label">
			  <label for="">Full Name</label>
			<td class="oc-form-value">
			  <input type="text" />
			<td class="oc-form-help">
			  <span class="oc-form-context">
			  <span class="oc-form-validator">


This markup will make the following naked html:


Add CSS, and you get the finished product: