-
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.
DO:
- 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”.
DON’T:
- 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>
</h3>
<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>
<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?
</p>
</li>
</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)
- Feed
- Wiki
- 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">
<fieldset>
<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
</p>
</legend>
<table class="oc-form">
<tbody>
<tr class="oc-form-row">
<th scope="row" class="oc-form-label">
<label for="">Username</label>
</th>
<td class="oc-form-value">
<input type="text" name="__ac_name" id="__ac_name" />
</td>
<td class="oc-form-help">
<span class="oc-form-context">
Pick something funny
</span>
<span id="oc-username-validator" class="oc-form-validator">
Sorry, that username is taken
</span>
</td>
</tr>
<tr class="oc-form-row">
<th scope="row" class="oc-form-label">
<label for="">Full Name</label>
</th>
<td class="oc-form-value">
<input type="text" />
</td>
<td class="oc-form-help">
<span class="oc-form-context">
(optional)
</span>
<span class="oc-form-validator">
</span>
</td>
</tr>
</tbody>
</table>
</fieldset>
</form>
This markup will make the following naked html:
Add CSS, and you get the finished product: