Leveraging the Most out of CSS Classes

To harness or exploit the most out of CSS classes is to take advantage of what truly is the unsung hero of advanced RIA development as it relates to the presentation layer. When we observe our markup, we find that various portions of the DOM may require styling influences on the initial page load as well as interaction events or cues to adjust its structure, positioning, visibility, state, and skin. For this classes are the clear suitor, as it brings flexibility, modularity, inheritance, and a dynamic and unobtrusive nature to the table.

Benefits

One benefit in particular is in a nodes ability to support multiple class declarations at a time, which in a sense facilitates a multiple inheritance of sorts. This gives us the unique ability within CSS to separate an element’s various states and differing characteristics to create a more modular approach in our stylesheets. By doing so, we can create classes that are in no way specific to any one element but merely represents a characteristic or group of characteristics that any node can adopt provided the class name.

Inheritance can also play a key role in the design process, by letting the cascade flow through the DOM we can leverage the styles of ancestor nodes and avoid a rigid implementation with redundant style declarations. If we employ this technique, we can easily alter state of descendant nodes by adding or removing a class to or from that of an ancestor node while avoiding the need to traverse the DOM to manipulate each descendant node individually in our script.

As far as client-side scripting is concerned, classes are the preferred window to CSS from JavaScript. By hiding styling characteristics behind class names, JavaScript can merely alter a node’s className attribute to activate or deactivate a specific state of that node. In this case, JavaScript is not concerned with what styling influences are taking place on page load or even after event triggered changes in state. This allows us to quickly consult our CSS to make minor styling changes rather than JavaScript.

Abstract Classes

Abstract classes are those that do not necessarily reflect a state or any specific node but common characteristics shared between nodes of varying purpose and context. Take for instance the following:

.widget {
    font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif;
    font-size: 1.1em;
}
 
.overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}
 
.content {
    display: block;
    -khtml-box-sizing: content-box;
    -webkit-box-sizing: content-box;
    -moz-box-sizing: content-box;
    -ms-box-sizing: content-box;
    -o-box-sizing: content-box;
    box-sizing: content-box;
    zoom: 1;
}

As you can see these examples are of a very generic nature both in name and styling influences as they represent a very high level abstraction. Typically classes such as these should always be combined with others as part of a node’s class declaration to round out its structure, positioning, state, and skin.

The advantage of abstract classes do not come solely in their ability to apply styles to a node in a modular fashion, but also in the relationships they create. Think of it from the perspective of object-oriented programming, provided the overlay class, a node will inherit the role of an overlay. For example:

<div class="widget">
    <div class="overlay widget">
        <!-- widget markup -->
    </div>
</div>

In this case, the parent node is a widget and has a widget and has a overlay while the child node is a widget and is a overlay. Although the child node is both an overlay and a widget, it is important to recognize that this node can be referenced by either statement together or independently of the other, like so:

.widget .overlay {
    /* target overlays that belong to widgets */
}
 
.widget .widget {
    /* target widgets that belong to widgets */
}
 
.widget .widget.overlay {
    /* target overlays that are also widgets that belong to widgets */
}

By grouping nodes together in this manner we can target nodes based on their role, state, structure, positioning, document position, or relativity to other nodes. From here we let inheritance fill in the gaps; as we move further down the DOM hierarchy the more precise and relevant our styles become to the specific nodes to which they are applied. Width and height, for example, should typically be reserved for styling in a low level context, while font (family, size, and color) is best served at a high level. Not to mention that this grouping makes it very easy for JavaScript to quickly reference or query for various nodes in various contexts for fast and easy manipulation.

Character Classes

Similar to abstract classes, character classes work on a lower level context and are designed to fulfil one purpose relating to a characteristic or group of characteristics. They help to achieve both visual and cross-browser consistency across an application in the purpose that they serve. For example, the following are some character classes of varying purposes:

.hidden {
    display: none;
}
 
.float-left {
    float: left;
    display: inline;
}
 
.center {
    margin-left: auto;
    margin-right: auto;
}
 
.text-overflow {
    width: 100%;
    text-overflow: ellipsis;
    -o-text-overflow: ellipsis;
    white-space: nowrap;
    overflow: hidden;
}

Typically character classes do not need to be overridden in a lower level context as they should be mutually exclusive from your structure and skin. You’ll also want to avoid depending on character classes to target descendants as part of a selector statement. Doing so will expand the scope of the class beyond its original purpose, this can snow ball into further dependencies that result in a loss of modularity and flexibility.

Exploiting character classes to the fullest means easy adoption of shared markup conventions and allow for ease in code integration. By putting together a small component library, you will find that they will not only provide reusable classes throughout an entire application but also amongst projects.

Themed Classes

As you might have guessed, themed classes have everything to do with your skin, this means fonts, colors, background images, formatting, icons, and states. Take for instance the following:

.loading {
    cursor: wait;
}
 
.active {
    border: 1px solid #327E04;
    background: transparent url(active-state.png) 50% 50% repeat-x;
    font-weight: normal;
    color: #ffffff;
    outline: none;
}
 
.disabled {
    cursor: not-allowed;
    -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)";
    filter: alpha(opacity=60);
    opacity: 0.6;
    -moz-user-input: disabled;
    -moz-user-focus: ignore;
    -moz-user-modifty: read-only;
    -khtml-user-modify: read-only;
    -webkit-user-modify: read-only;
}

Classes such as these are most useful when theming various user interface widgets. We can use a group of semantic presentation classes to indicate the state of a widget such as default, hover, active, and disabled. As the user interacts with the page, we dynamically apply the appropriate class to the widget to represent its current state. This level of class consistency makes it easy to ensure that all nodes with a similar role or state will look the same across all widgets.

Like abstract classes, themed classes also create relationships, however these relationships are more targeted towards a node’s state as opposed to its role. This makes it simple to target nodes based on their current state, for instance active nodes:

.overlay.active .header {
    /* target the header of active overlays */
}
.overlay.active .body {
    /* target the body of active overlays */
}

Here we can add additional rules to automatically style the descendants of a node based on its state without directly referencing the descendants in CSS via additional class names or in JavaScript via DOM traversal.

Progressive enhancement also falls under the cloud of themed classes as it can be utilized to bring greater aesthetics to your skin. It differs in the sense that a class will be responsible for providing a single detail (rounded corners, drop shadow, gradient backgrounds, etc.) to the theme in a cross-browser and consistent manner:

.shadow {
    -khtml-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5);
    -webkit-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5);
    -moz-box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5);
    box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5);
}
 
.corners {
    -khtml-border-radius: 5px;
    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
    border-radius: 5px;
}

By grouping vendor specific styles together (-webkit-, -moz-, -o-, -ms-) nodes will adopt the behaviour in supported browsers and degrade gracefully in unsupported browsers. This helps to keep code not only backwards compatible but also future proof:

If properly implemented we can achieve visual consistency across an application and allow components to be themeable in a rather simplied and modular fashion.

Conclusion

When we combine all these techniques, we find utter simplicity in forming both the structure and skin of a node, while minimizing the amount of node specific style declarations in our stylesheet. If done right, you will find your markup will greatly improve as a result and it will be as easy to write as the following:

<div class="widget overlay corners shadow active">
    <div class="header content">
        <!-- header markup -->
    </div>
    <div class="body content">
        <!-- body markup -->
    </div>
    <div class="footer content">
        <!-- footer markup -->
    </div>
</div>

These techniques help to serve as an advantage not only to your CSS but also your markup and JavaScript for a truly unobtrusive implementation. Changing the theme of your application could be as easy as switching a stylesheet and a few background images to provide a whole new look & feel. To learn more techniques or to read further on a few I’ve discussed here, please refer to Nicole Sullivan’s OOCSS (Object-Oriented CSS) project, it is truly a great read and highly recommended.

This entry was posted on Thursday, August 26th, 2010 at 10:06 PM and is filed under Articles, CSS, UI, XHTML. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

Leave a Reply