A practical example

In the last two chapters we’ve looked at how objects and good naming conventions can simplify how we write CSS and make our code smarter and more flexible. Let’s look at how all of this would work within the context of a larger project.[1]

Recently, researchers at the fictional University of Cowville have been researching new ways to index web pages and they’ve come up with a new, patented system, affectionately known as “Cowrank”, to create highly relevant search results for cows. They suspect that Cowrank will transform the Cow economy and revolutionize the way that cows select pastures, detect predators, maintain appropriate dental hygiene, and even find suitable soulmates (among other things). Knowing the reputation of your firm, they’ve come to you for help polishing off the initial version of their site.

After some back and forth, you’ve finally settled on the following design for the home page:

Moogle: a search engine for cows

Okay, enough backstory. Let’s look at how we might code this up using the Oxygen naming conventions!

Start with a neutral CSS reset

Using a CSS reset is a way of setting up the default styles for a document. Different web browsers have different default styles, so it makes sense to reset them to something sensible.

I would encourage you to use a reset that removes (or zeros out) all styles on each element. This will give you a completely neutral foundation to layer additional styles on.

For modern browsers, you can use something something as simple as:

// Reset styles on all elements
*, *::before, *::after {
  margin: 0;
  padding: 0;
  border: 0;
  border-collapse: collapse;
  border-spacing: 0;
  box-sizing: border-box;
  outline: none;
  font-size: 100%;
  font: inherit;
  vertical-align: baseline;
  list-style: none;
  quotes: none;
}

// Make new HTML 5 elements display block
footer, header, hgroup, menu, nav, section, small {
  display: block;
}

// Ah, yes. Quote me bro!
blockquote:before, blockquote:after, q:before, q:after {
  content: '';
  content: none;
}

A neutral CSS reset may not be an option on every project, but wherever possible use one! It will help you avoid a number of common bugs and make it easier to reason about your CSS.

Base font styles

The next thing we should do is set up the initial font styles. Font styles are inherited in CSS for the most part, so it makes sense to set the defaults on the <body> element:

body {
  color: #444;
  font-family: 'Open sans', sans-serif;
  font-weight: 100;
  font-size: 15px;
  line-height: 1.4;
}

Remember to set the line-height on the body element to something useful. Most modern designs use a line height between 1.2 and 1.4. (Don’t include units on the line-height value and it will scale with the font-size of the element.)

Basic layout

The Moogle layout can be loosely broken up into three parts:

  • Header
  • Search
  • Footer

Mapped out in our markup, we can express this as:

<body class="site">
  <header class="site-header">
    Header
  </header>

  <div class="site-search">
    Search
  </div>

  <footer class="site-footer">
    Footer
  </footer>
</body>

So we need one main object: “site”, with three child-objects “site-header”, “site-search”, and “site-footer.” Simple enough.

Let’s create some object definitions:

.site {
  display: flex;
  flex-direction: column;
  min-height: 100vh;

  background: #e3e4e5;
}

.site-header {
  padding: 0 10px;
}

.site-search {
  flex: 1;

  padding-top: 150px;
  text-align: center;
  margin-left: auto;
  margin-right: auto;
}

.site-footer {
  background: #d6d7d9;
  padding: 0 10px;
}

Not bad. Using flexbox, we’ve neatly achieved a layout with a header and sticky footer.[2]

In a web browser, this renders something like this:

Basic layout

Quite plain. As it should be. Now that we have the basic structure, let’s put the other objects into place.

Search controls

The heart of this design is the search box. Let’s add a logo, a textbox, and a pair of buttons:

<form ...>
  <div class="row">
    <img src="images/logo.svg" width="390" alt="Moogle">
  </div>
  <div class="row">
    <input class="textbox" type="text" name="q" size="60" autofocus>
  </div>
  <div class="row">
    <button class="button" type="submit">Moogle search</button>
    <button class="button" type="submit" name="lucky" value="true">I’m feeling lucky</button>
  </div>
</form>

To, consistently space the objects vertically, we will add a simple utility object called “row”:

.row {
  margin: 1.5em 0;
}

And some styles for a “textbox” object:

.textbox {
  background: white;
  border-top-color: #bbb;
  border-radius: 4px;
  box-shadow: #bcbec0 0 2px 0;
  font-size: 18px;
  padding: 8px 12px 7px;

  &:focus {
    box-shadow: #95989b;
  }
}

And finally, our “button” object definition:

.button {
  color: white;
  cursor: pointer;
  background: #494c56;
  border: none;
  border-radius: 4px;
  box-shadow: #32343a 0 2px 0;
  font-size: 18px;
  font-family: 'Open sans', sans-serif;
  font-weight: bold;
  -webkit-font-smoothing: antialiased;
  padding: 8px 20px 7px;

  &:focus, &:hover {
    background: #787d8d;
  }

  &:active {
    background: #32343a;
  }

  & + & {
    margin-left: 0.5em;
  }
}

There are a number of things that are going on here, but it should be relatively straightforward. We’ve defined styles for regular buttons and also styles for focus, hover, and active states. One of my favorite tricks is the final rule that begins with & + &. This is a fancy way of using Sass to generate:

.button + .button {
  margin-left: 0.5em;
}

This is a simple way of stating that when a button appears next to another button, add additional space.

This markup and CSS will now render something like this:

Search controls

Nicely done! The heart of the search interface is now complete.

Navigation

We need a few more objects to complete the header and footer. If you look back at the mockup, you will observe that the header and footer contain very similar navigation. This is a great oportunity to create a couple of objects that share the same definitions.

We’ll call the main navigation object “blocknav” because this site will likely contain a lot of different types of navigation so we’ll need some unique names. Calling it “blocknav” sounds good because this navigation is kind of blocky.

We will follow conventional wisdom and use an unordered list for navigation:

<ul class="blocknav">
  <li class="blocknav-item"><a class="blocknav-item-link" href="#">MooMail</a></li>
  <li class="blocknav-item"><a class="blocknav-item-link" href="#">Images</a></li>
  <li class="blocknav-item"><a class="blocknav-item-link" href="#">Dating</a></li>
  <li class="blocknav-item"><a class="blocknav-item-link" href="#">MooTube</a></li>
  <li class="blocknav-item"><a class="blocknav-item-link" href="#">Account</a></li>
</ul>

With this markup structure, we require three object definitions:

.blocknav {
  display: block;
}

.blocknav-item {
  display: inline-block;
}

.blocknav-item-link {
  display: inline-block;
  padding: 10px;
  color: inherit;
  text-decoration: none;
  line-height: 32px;

  &:focus, &:hover {
    color: black;
  }

  &:hover {
    text-decoration: underline;
  }
}

This gets us almost all the way there. We’ll also add two attribute modifiers for floating left and right:

.float-left {
  float: left;
}

.float-right {
  float: right;
}

We’ve decided to make these global modifiers because they can be used in a lot of different places. I use float modifiers on almost every project.

With these additions we can now use this markup for the header navigation:

<ul class="blocknav float-right">
  <li class="blocknav-item"><a class="blocknav-item-link" href="#">MooMail</a></li>
  <li class="blocknav-item"><a class="blocknav-item-link" href="#">Images</a></li>
  <li class="blocknav-item"><a class="blocknav-item-link" href="#">Dating</a></li>
  <li class="blocknav-item"><a class="blocknav-item-link" href="#">MooTube</a></li>
  <li class="blocknav-item"><a class="blocknav-item-link" href="#">Account</a></li>
</ul>

And, this markup for the footer:

<ul class="blocknav float-left">
  <li class="blocknav-item"><a class="blocknav-item-link" href="#">Advertising</a></li>
  <li class="blocknav-item"><a class="blocknav-item-link" href="#">Business</a></li>
  <li class="blocknav-item"><a class="blocknav-item-link" href="#">About</a></li>
</ul>
<ul class="blocknav float-right">
  <li class="blocknav-item"><a class="blocknav-item-link" href="#">Privacy</a></li>
  <li class="blocknav-item"><a class="blocknav-item-link" href="#">Terms</a></li>
  <li class="blocknav-item"><a class="blocknav-item-link" href="#">Settings</a></li>
</ul>

Simple enough. Here’s how it all renders:

Moogle navigation

Almost done!

Avatars

The last object definition we need is for the avatar of the currently logged in cow. Fortunately, our backend code crops and resizes avatars to an 128 x 128 pixel image, so we don’t need to worry about the image proportions. But we do want to size the image with CSS and turn it into a circle.

Here’s the markup which we can use to replace the “Account” text in the navigation:

<img class="avatar" src="images/cow-avatar.png" alt="Account" title="Account">

And here’s the object definition in the CSS:

.avatar {
  border-radius: 100%;
  vertical-align: middle;
  width: 32px;
  height: 32px;
}

The final render:

Moogle: a search engine for cows

And, we’re done! Nice work.

In summary

The Moogle example is a bit contrived, but hopefully this chapter has given you more insight into how to practically apply Oxygen in your work. Notice how much easier code is to read that is structured according to the Oxygen naming conventions. In real life your CSS will likely be more complicated, but observe how far we got focusing on breaking everything up into small, discrete, multi-purpose objects.

As projects mature the need to write new CSS should diminish to the point that it is rare that you need to write additional CSS to achieve a new layout or interface. Finding good ways to break your code apart takes a lot of practice. We will talk about some good patterns for structuring objects in the next chapter.


  1. You can find the complete source code for this chapter on GitHub at: https://github.com/jlong/oxygen-moogle-example ↩︎

  2. Flexbox is a set of CSS properties that provide a range of new layout options for CSS. Philip Walton has put together an excellent demo site, called Solved by Flexbox which demonstrates how to achieve a number of layouts including a sticky footer demo that I’ve basically repurposed for my own use here. ↩︎

Subscribe to the Oxygen newsletter to be notified as chapters are written!

Discussion