Reusable List Styles

Abstracting styles so they are reusable and clearly named is rarely straightforward. Here are some patterns to look for that will ease the pain when styling lists.

Lists come in three flavors. Content, Collections and Navigation.

Content

Content lists are simple <ul> and <ol>. These are the default lists styles that appear in the body of an article. If a content author were to create a bulleted list in the WYSIWYG, it would look like this. Typically you only need to style these once per site.

See the Pen xyjBq by John Ferris (@pixelwhip) on CodePen.

From a design perspective, it's best to keep the style of content lists simple. This list style will be the basis for all lists, including Collections and Navigation described below. Any complicated design treatment, such as icons for bullets or even just a change in font size from the default body copy size or a different color bullet, will require a bunch of otherwise unnecessary overrides for the rest of the site. If the design can't budge, consider looking into ways you can limit the style to only body copy areas. That has its own implications, but it may be the lesser of two evils.

Collections

Collections are lists of other components. For example, these lists might be a list of; search snippets on a search results page; teasers of the 10 most recent blog posts; or 3 upcoming events. You get the picture.

Styling of collections should be limited to the outer list element and list items. Styles should not affect the components inside the collection list. This means style declarations that cascade into child elements, mainly typographic styles, should be avoided. Instead, stick to layout and decoration styles that only affect the ul and li in the list. You’ll find this makes your classes far more reusable as list styles are completely independent of their content.

Example classes might look like this:

  • .list--no-bullets
  • .list--ruled
  • .list--promoted
  • .list--3up
  • .list--4up

Here is an example of a ruled list of blog post teasers.

See the Pen aqcel by John Ferris (@pixelwhip) on CodePen.

Here is the same list of teasers, using the 3-up list style.

See the Pen rhLyx by John Ferris (@pixelwhip) on CodePen.

Navigation

Navigation lists are lists used for marking up, wait for it... navigation! They typically look like ul > li > a. Unlike collections, the content of navigation lists, typically a single <a> tag, is essential to the component's whole and therefore included in the styles.

I still find it helpful to keep the typographic style declarations out of the <li> opting to apply them to the <a> instead. The <li> in a navigation list typically only serves to make the navigation inline as needed and padding and margin are typically set to 0. This way padding can be applied directly to the <a> elements to maximize the hit area of the link, making it an easy target for touch interfaces.

In the case of navigation items not having an <a> tag, such as currently active or disabled items, it’s helpful to wrap the link text in a <span> element so it can share the layout styles.

  • .nav--main
  • .nav--sub
  • .nav--footer
  • .nav--local

Here is an example of a main navigation list.

See the Pen sudEe by John Ferris (@pixelwhip) on CodePen.

Here is the same navigation using an alternative tab style.

See the Pen eCsAv by John Ferris (@pixelwhip) on CodePen.

List Modifiers

I often find the need for variations in spacing of the basic list styles. For vertical lists I typically use ‘tight’ and ‘loose’ modifiers. For variations in horizontal spacing, I use ‘condensed’ and ‘expanded’.

  • .list--ruled--tight
  • .list--ruled--loose
  • .nav--main--condensed
  • .nav--main--expanded

About the > child selector

As you've probably noticed, I've made a habit of using the direct child selector when dealing with lists, especially collection lists. This selector creates an explicit relationship between a parent and child element and prevents the applied style from cascading into nested elements. This selector is widely supported and will keep styles from bleeding into unintended places. Be about it!

In the past, we've also used a more strict sub-component naming convention in which each element of a list component had a specific class. For example

.nav--main > li > a { ... }

.list--ruled > li { ... }

Used to look like:

.nav--main > .nav-item > .nav-link { ... }

.list--ruled > .list-item { ... }

While the consistent looking selectors provided the developer warm fuzzies when looking at a stylesheet, this naming convention added overhead in actually applying these classes to the markup. It also provided no real benefit over the direct child selector which was still needed to prevent styles from bleeding to nested lists. For that reason we reverted to styling the tag directly using the direct child selector.

I've found the above patterns extremely helpful when styling lists. They make code more reusable and help keep stylesheets organized and tidy. The naming conventions also help when communicating with other developers and designers on a project. I hope you find these patterns as helpful as I do!

Code

Read This Next