In Part 1 of Welkup's How to Build a Great Website series, we discussed the importance of structuring your website with great markup. The next step is to breathe life into that structure with great styling. In part 2, we delve into the world of Cascading Style Sheets (CSS). We will look at some best practices to achieve consistency, maintainability, and performance.
CSS is the outlet for creativity in web design. It gives the designer access to virtually every aspect of a website's appearance. The trick is turning all of those options into something perceived as beautiful. Like any other art form, it all starts with a blank canvas.
Laying the Groundwork
Unfortunately, the browser doesn't offer up a blank canvas. Each browser has a slightly different set of default styles for the various HTML tags. Discrepancies in elements' default styles disrupt so called cross-browser pixel perfection. The first step in styling your website is defining your own defaults via a CSS reset style sheet. A CSS reset style sheet will, for instance, zero out the padding and margin on all elements. Padding and margin are the more common points of difference between browsers. Default font properties may also be inconsistent.
Styling fonts in CSS requires styles for both resetting defaults and improving accessibility. Resetting defaults ensures the fonts appear consistently across browsers, and improving accessibility ensures the fonts work with a browser's font resizing capabilities. Nowadays, most browsers use a zoom feature to modify font sizes; however, some user agents still have the option to resize text exclusively. Because of this, it is important to define font sizes in relative units, such as
em, and not fixed units, such as
pt. If presented in fixed size, the browser's text resizing will have no effect, and some users may not be able to read the site's content.
Once all of the default CSS styles have been removed, it is up to the website to redefine those styles appropriately. This is done in what is known as a CSS base style sheet. The browser's base style sheet is what the aforementioned reset style sheet effectively erases allowing you to substitute your website's own base style sheet.
Your website's CSS base style sheet defines your website's look and feel. The base file will associate styles with HTML tags as well as define a tight set of CSS classes designed to give you a lot of mileage. A well designed page structure (see Part 1) is a prerequisite of a good base file. A good base file minimizes the number of class names and mostly eliminates the need for inline styles (i.e., styles in the HTML using the style attribute). When the set of class names is minimized, the site is more focused and becomes more maintainable.
Keeping the Sanity
Maintainability in CSS is important because CSS files are prone to disarray. Unlike with markup, CSS does not have any structure. A CSS file is simply a list of selectors and associated styles. By employing consistent formatting, descriptive commenting, and mindful classifying, the lives of your CSS files and your website will be extended.
CSS files really are a free-for-all so consistent formatting will help keep the sanity. Like with markup, proper spacing will make the file more readable. Use a tab or groups of 4 spaces, but do not mix the two. Maintain lower case in tag names and use consistently-cased class names. Selectors should flow from general to specific. Selectors matching HTML tags are the most general, and selectors matching element ids are the most specific. Related sets of styles, such as for absolutely positioning an element, should be grouped within a selector. Styles with different names that style the same feature, such as those styles named differently cross-browser (e.g. opacity), should be grouped together, as well.
The cross-browser CSS landscape is, metaphorically speaking, a desolate wasteland scattered with signs of life signaling a new beginning. Each browser supports its own subset of CSS styles and even has its own set of custom styles. As browsers have matured, this has become less and less of an issue. Supporting all of the major browsers has become especially easier with the silent departure of Internet Explorer 6 and 7. Developers have engineered many clever workarounds to manage the chaos. Fortunately, most of these hacks will soon become bad memories.
Any hacks or potentially confusing styles need to be explicitly commented. Otherwise, their purpose may be lost. Without knowing a style's purpose, it is apt to get modified erroneously or even deleted altogether. Shy away from awkward styles like giving a
display: block when a
<div> would be much more natural. Simplicity precedes elegance.
Class Name Management
The most important factor in achieving CSS maintainability is class name management. The ultimate goal is to define as few classes as needed to properly describe your website and no more. To do that, the structure of the web site should be known in advance. The structure of a website will be determined by its purpose. Websites generally take on one or both of two broad roles: a group of pages to be read or an interactive web application.
A website as a group of pages to be read usually has classes that correspond to parts of a book. The page will have a header, footer, content, and navigation (table of contents). The content area might have a class called
<p> tags within a
document could have special meanings apart from
<p> tags outside of a
document, such as more line spacing or margins, to make them easier to read. These paragraph styles would not necessitate new classes since HTML already provides the
<p> tag to accurately describe their purpose, and CSS can style based on tag names.
When HTML does not provide a suitable tag, a
<div> tag with a class name is often used instead. As HTML matures, a fuller set of tags will emerge. For example, HTML did not always have the
<footer> tags. In general, HTML tags should be favored over class names when defining selectors. This is critical towards keeping your set of class names small.
The other type of website is a web application. A web application is less likely to have the flow of a book and more likely to focus on blocks of functionality through the use of interactive widgets. Widgets are (generally) self-contained, reusable blocks of code that perform a core function. Often, each class of widget will have its own CSS file. This is an example of CSS file modularity, and it's another useful technique for managing CSS. This also occurs whenever a website includes its base style on each page and a separate CSS file unique to that page as a whole.
With the type of your website in mind, the next step is defining the minimal set of class names. Class names take on one of two flavors: representing a specific object (so called, object-oriented) or representing a specific style.
The more important flavor of class name, representing an object, is also the more familiar. This type is used to classify elements. For instance, you might want all of your form inputs to have a left margin and an amount of padding. This could be given the class name
form-input, and it could be applied to
<input>s. Although it is possible to style the tags using the tag names themselves, sometimes it is desirable to avoid polluting the raw tag namespace as it can make other modifications difficult.
The other type of class name represents stylistic qualities. It can be thought of as a reusable inline-style because it isn't used for classification purposes. For example, one might want to define a class name called
end that encapsulates
text-align: end behavior but falls back on
text-align: right behavior in older browsers.
Even with a well-designed and maintainable CSS framework, the presentation can still be degraded if you are not mindful of performance. Your site might load slowly or might exhibit flashes of unstyled content (FOUC), which can be jarring to a user's experience. Many techniques exist for maximizing the performance of CSS in your website.
As part of a the build process of a site, the size of a CSS file can be reduced by having its comments and white-space stripped in a process called minification. Minification also saves space by replacing CSS styles with shorter versions that do the same thing. For example,
black can be replaced with
#000 for the same effect. Once minified, the server has to serve up fewer bytes which reduces latency.
An additional technique that saves on latency is gzipping the file before sending it. All modern browsers support responses being encoded with gzip. Since the bottleneck for sending the CSS file to the client is latency, even though there is additional cycles required to compress the file, overall there will be significant savings.
The browser's caching mechanism will also reduce the number of bytes transferred. In fact, if a file is cached, it will reduce that files byte to zero! CSS files are a resource that browsers will automatically cache, but we can specify the parameters of the caching to maximize our benefits. We want to set the expire headers in the CSS file's HTTP response to a far future date. The browser's caching capability is also the reason to avoid the use of the
<style> tag and
style attribute as much as possible.
In theory, once a CSS file is cached, the browser does not even have to initiate an HTTP request for the file. In practice, however, the browser will perform a conditional GET and find that the CSS file was not modified so you still suffer the overhead of the HTTP request.
The life-cycle of HTTP requests is a second bottleneck in website performance. HTTP runs on TCP meaning that every time an HTTP connection is made, the browser must first do a handshake with the other server to ensure it is alive, which requires a round trip and, hence, latency. Reducing the number of requests will boost performance, and a number of techniques exist for doing so.
Previously, it was suggested that CSS files should be modular to increase maintainability. However, having more files means making more HTTP requests. This may look like another example of sacrificing performance for maintainability, but with a proper setup in place, we can again get the best of both worlds. The solution is to use a combo loader for your CSS. A combo loader is a program that is able to concatenate a number of files together and serve them back in a single HTTP request. Like with gzipping, there is a bit of extra overhead (concatenating the files), but the overall savings make it a smart investment.
Another technique for reducing requests is applicable to the use of images in CSS. Specifically, the
background-image style. This style normally expects a URL to an image that will be loaded in a separate HTTP request when it is needed. To save on these extra requests for small images, the image can be embedded into the CSS file itself as a base64 encoded string.
Alternatively, small images can be served through CSS sprites. With CSS sprites, a single HTTP request grabs an image, and parts of that image are cropped out for display. This way, a single request grabs "multiple" images. Embedded images are generally preferred over CSS sprites, but CSS sprites are easier to manage without an extensive build process.
CSS can be a practice in trial and error that gets frustrating at times. Combining styles into an appealing look is difficult enough to have to worry about consistency, maintainability, and performance. Following the guidelines set forth here will ensure that your remaining problems be the creative ones.