Parker and WordPress Menus

As a sort-of follow up to my previous posts, I ran across an issue with styling menu items and found a great way to add classes so I can style those items directly.

Many of our designs have a vertical bar between menu items. While there are several ways to accomplish this, I’ve been using something like this in recent projects to style the top-level menu items:

.primary-menu-item-0 :not(:first-child) a {
 border-left: 1px solid;
 padding-left: 1em;
 }

Basically, add a left border and some padding to every menu item, except the first child. This results in a vertical bar between each menu item and the first child just has nothing. You can further refine it by targeting the first and last children to remove the outside padding as well.

Since using Parker to style as directly as possible, it struck me that having a selector that complex shouldn’t be necessary. Thankfully, there’s a simple way around it.

Adding Menu Item Classes

In the menus part of the Parker series, we added classes to each menu item and menu item link. The functions we used can have up to 4 parameters, which are passed in from the filter.

In the nav_menu_css_class hook, the $item parameter is the menu item object. We’re going to check the menu_order property value and if its either the first or last menu item, we’ll add classes so we can style those two menu items directly.

/**
  * Adds a class with the menu name and depth level to each menu item.
  * Makes styling menus much easier.
  *
  * @hooked nav_menu_css_class 10
  * @param array $classes The current menu item classes.
  * @param object $item The current menu item.
  * @param array $args The wp_nav_menu args.
  * @param int $depth The menu item depth.
  * @return array The modified menu item classes.
  */
 function example_add_menu_order_to_menu_item_classes( $classes, $item, $args, $depth ) {

 if ( empty( $item ) ) { return $classes; }

 if ( 1 === $item->menu_order ) {

 $classes[] = $args->menu_id . '-item-first';
  $classes[] = $args->menu_id . '-item-' . $depth . '-first';

 }

 if ( $args->menu->count === $item->menu_order ) {

 $classes[] = $args->menu_id . '-item-last';
  $classes[] = $args->menu_id . '-item-' . $depth . '-last';

 }

 return $classes;

} // example_add_menu_order_to_menu_item_classes()

 add_filter( 'nav_menu_css_class', 'example_add_menu_order_to_menu_item_classes' ), 10, 4 );
 

To add the “first” classes, we check is $item->menu_order equals 1. If so, add a class that will allow for styling any first menu item and a second class that allow for styling the first menu item at that particular menu depth. Now, we can style all the first menu items and any first menu item at any depth directly using single class.

To add the “last” classes, we compare the menu item count from the menu $args object against the $item->menu_order. If they are equal, we’re on the last menu item, so we can add the appropriate classes.

Adding Menu Link Classes

However, my first example was actually styling the menu item link. We can add classes using the nav_menu_link_attributes filter, just like we did when we added the depth classes.

/**
  * Adds classes to menu item links.
  *
  * Adds the depth class to make styling easier.
  * Adds the "coin" class if the menu item has the text-coin class.
  *
  * @hooked nav_menu_link_attributes 10
  * @param array $atts The current menu item link attributes.
  * @param object $item The current menu item.
  * @param object $args The wp_nav_menu args.
  * @param int $depth The menu item depth.
  * @return array The modified menu item link attributes.
  */
 function example_add_menu_order_to_menu_item_links( $atts, $item, $args, $depth ) {

if ( empty( $item ) ) { return $atts; }

 if ( 1 === $item->menu_order ) {

 $atts['class'] .= $args->menu_id . '-item-link-first ';
  $atts['class'] .= $args->menu_id . '-item-link-' . $depth . '-first ';

 }

 if ( $args->menu->count === $item->menu_order ) {

 $atts['class'] .= $args->menu_id . '-item-link-last ';
  $atts['class'] .= $args->menu_id . '-item-link-' . $depth . '-last ';

 }

return $atts;

} // example_add_menu_order_to_menu_item_links()

 add_filter( 'nav_menu_link_attributes', 'example_add_menu_order_to_menu_item_links' ), 10, 4 );

This function follows the same basic pattern, except how the class is added. Now, the first menu item links and last menu item links can be styled using a single class. We can also style the first or last menu item link at any depth using a single class.

Wrapping Up

So instead of this:

.primary-menu-item-0 :not(:first-child) a {
 border-left: 1px solid;
 padding-left: 1em;
 }

We do this:

.primary-menu-item-link-0 {
  border-left : 1px solid $teal;
  padding : 0 1em;
}

.primary-menu-item-link-0-first {
 border-left: none;
 padding-left: 0;
}

These are much simpler selectors, so maintainability and troubleshooting will be easier. We also have some really useful classes for styling menu items as needed. Admittedly though, its not as fun as doing it all in one selector.

Finishing the Underscores Stylesheet

Summary

In the previous posts in this series about Parker, we used the stylesheet analysis tool to optimize the stylesheet for the _s starter theme. We also used hooks and functions to customize the WordPress menus and as a result we have a simpler stylesheet. Here are the goals we were trying to achieve:

  • Reduce stylesheet complexity
  • Increasing maintainability
  • Making more CSS classes reusable

After using Parker’s metrics and optimizing, lets compare our baseline results to our final results:

Baseline

  • Total Stylesheets: 1
  • Total Stylesheet Size: 15432
  • Total Rules: 134
  • Total Selectors: 280
  • Total Identifiers: 508
  • Total Declarations: 243
  • Selectors Per Rule: 2.08955223880597
  • Identifiers Per Selector: 1.8285714285714285
  • Specificity Per Selector: 10.446428571428571
  • Top Selector Specificity: 120
  • Top Selector Specificity Selector: #content[tabindex=”-1″]:focus
  • Total Id Selectors: 1
  • Total Unique Colors: 15
  • Unique Colors: #FFFF00,#000000,#C0C0C0,#404040,#EEEEEE,#666666,#FFF9C0,#FFFFFF,#CCCCCC,#BBBBBB,#E6E6E6,#AAAAAA,#111111,#F1F1F1,#21759B
  • Total Important Keywords: 2
  • Total Media Queries: 1
  • Media Queries: screen and (min-width: 37.5em)

Final

  • Total Stylesheets: 1
  • Total Stylesheet Size: 14405
  • Total Rules: 134
  • Total Selectors: 240
  • Total Identifiers: 350
  • Total Declarations: 243
  • Selectors Per Rule: 1.791044776119403
  • Identifiers Per Selector: 1.475
  • Specificity Per Selector: 8.566666666666666
  • Top Selector Specificity: 30
  • Top Selector Specificity Selector: .infinite-scroll.neverending .site-footer
  • Total Id Selectors: 0
  • Total Unique Colors: 15
  • Unique Colors: #FFFF00,#000000,#C0C0C0,#404040,#EEEEEE,#666666,#FFF9C0,#FFFFFF,#CCCCCC,#111111,#BBBBBB,#E6E6E6,#AAAAAA,#F1F1F1,#21759B
  • Total Important Keywords: 2
  • Total Media Queries: 1
  • Media Queries: screen and (min-width: 37.5em)

After all these optimizations and changes, lets finally look at how we did.

  • We reduced our stylesheet size from 15432 to 14405. That’s an over 1kb reduction!
  • We reduced the Total Selectors from 280 to 240.
  • We reduced the Total Identifiers from 508 to 350.
  • We reduced the Selectors Per Rule from 2.08955223880597 to 1.791044776119403.
  • We reduced the Identifiers Per Selector from 1.8285714285714285 to 1.475.
  • We reduced the Specificity Per Selector from 10.446428571428571 to 8.566666666666666.
  • We reduced the Top Selector Specificity score from 120 to 30.
  • We reduced the Total Id Selectors from 1 to 0.

Wrapping Up

Those are some pretty good results for a stylesheet that doesn’t really contain much. You’ll see much better results when working on a fully developed them. Having done all this work though, what does it all mean?

Reducing the size helps the site load faster. When a browser asks a server for a web page, a single roundtrip request is about 14kb in size. Our newly optimized stylesheet, at 14.4kb, is almost small enough to fit into a single request.

We’ve made the stylesheet much easier to read by refactoring the code to eliminate the longer selectors, so it should be easier to maintain in the future.

Finally, we’ve increased the reusability of our classes and made the rest of our rules less specific. Ideally, as a new theme is built from this optimized stylesheet, more thought it put into creating reusable classes and tweaking the default WordPress code to allow for more direct access to elements.

I’ll be submitting some pull requests to the _s repo based on some of these tweaks, so some of these changes may already be completed in future versions of _s. I highly recommend running Parker on your finished stylesheets to find ways to get these metrics as close to the ideals as possible. While Parker isn’t a solve-everything kind of tool, it is useful to constantly improve what we do and know how and why it’s an improvement.

I’m hooked on using Parker and plan to integrate it into my workflow during my next project. Integrating Parker into my gulpfile has been the simplest way to run it at the same time I pre-process my SASS files. Let me know how Parker is changing your stylesheets and/or development process!

Simplifying Menu Styling

In the previous post in this series about Parker, we optimized parts of the _s stylesheet and improved our Parker scores. However, one of the more difficult optimizations by working on the menus. This isn’t just a stylesheet tweak though, we’ll need to add some code to _s that adds classes to each menu ul tag, menu item, and menu item link.

The Menu

The styling for menus in _s involves some pretty insane selectors, like this one:

.main-navigation ul ul li:hover > ul

Lets look at how to add classes to each menu ul tag, menu item, and menu item link so we can reduce how many identifiers we use in each selector, improve our Parker scores, and simplify our stylesheet.

Menu Items and Links

In the inc/extras.php file, we’re going to create two functions. The first adds classes to the menu items and the second adds classes to the links in each menu item.

ADD DEPTH AS A MENU ITEM CLASS

The following function adds two classes, derived from the menu name and the menu item depth, to each menu item.

/**
  * Adds a class with the menu name and depth level to each menu item.
  * Makes styling menus much easier.
  *
  * @hooked nav_menu_css_class 10
  * @param array $classes The current menu item classes.
  * @param object $item The current menu item.
  * @param array $args The wp_nav_menu args.
  * @param int $depth The menu item depth.
  * @return array The modified menu item classes.
  */
 function _s_add_depth_to_menu_items( $classes, $item, $args, $depth ) {

    if ( empty( $item ) ) { return $classes; }

    $classes[] = $args->menu_id . '-item';

    $classes[] = $args->menu_id . '-item-' . $depth;

    return $classes;

} // _s_add_depth_to_menu_items()
 

add_filter( 'nav_menu_css_class', '_s_add_depth_to_menu_items', 10, 4 );

The function first checks if the item is empty and returns if it is. We’re not going to work invalid menu items.

The $classes parameter is an array, so we create the two new classes, add them to the array, and return the modified array. Here are examples of the resulting class names for a menu titled “Primary Menu”:

.primary-menu-item

.primary-menu-item-0

The class that includes the depth changes for each menu item according to its depth in the menu:

.primary-menu-item-1

.primary-menu-item-2

.primary-menu-item-3

So instead of using:

.primary-menu ul ul ul li

We could use this to style just the menu items at this depth:

.primary-menu-item-2

Or this to style the menu items at this depth and all its descendants:

.primary-menu-item-1 li

This works great for the menu item, but what about the link inside the menu item?

ADD DEPTH TO MENU ITEM

The following function adds two classes, derived from the menu name and the menu item depth, to each menu item link.

/**
  * Adds classes to menu item links.
  * Adds the depth and menu name to make styling easier
  *
  * @hooked nav_menu_link_attributes 10
  * @param array $atts The current menu item link attributes
  * @param object $item The current menu item
  * @param object $args The wp_nav_menu args.
  * @param int $depth The menu item depth.
  * @return array The modified menu item link attributes.
  */
 function _s_add_depth_to_menu_item_links( $atts, $item, $args, $depth ) {

    if ( empty( $item ) ) { return $atts; }

    $atts['class'] .= $args->menu_id . '-item-link ';
    $atts['class'] .= $args->menu_id . '-item-link-' . $depth . ' ';

   return $atts;

} // _s_add_depth_to_menu_item_links()

add_filter( 'nav_menu_link_attributes', '_s_add_depth_to_menu_item_links', 10, 4 );

The function first checks if the item is empty and returns if it is. We’re not going to work with invalid menu items.

Since the classes for menu item links aren’t arrays, like the menu items, we append each newly created class to the existing class string. In this case, I’m adding two new classes:

  • menu-name-item-link
  • menu-name-item-link-depth

This allows for styling menu links in this menu and menu links in this menu at any particular depth. So we can apply styles to:

.primary-menu-item-link-2 

Rather than:

.primary-menu ul ul ul li > a

Custom Menu Walker

Now that we have the depth and menu name added to each menu item (li tag) and menu item link (a tag), we still need to add it to each menu level (the ul tag). Unfortunately, there’s not a filter for the menu ul tags, so we’ll need to create a new file in the “inc” folder called “main-menu-walker.php”. In functions.php. copy the last require statement and paste it at the bottom of the file. Change the file name to main-menu-walker.php and change the comment to “Load main menu walker”.

In the main-menu-walker.php file, we’re going to create a simple class that only includes one method. This method replaces the one used by the default menu walker class used in WordPress and inserts the new classes in each menu and submenu. Here’s the entire main-menu-walker.php file code:

<?php

/**
  * Custom walker for adding a wrapper around submenus in the main menu
  *
  * @since 1.0.0
  * @package Rosh
  * @subpackage Rosh/classes
  */
 class _s_Main_Menu_Walker extends Walker_Nav_Menu {

    /**
      * Adds classes to the each menu.
      * Offsets the depth by one to allwo for the top-level menu to be level 0.
 *
      * @see Walker_Nav_Menu::end_lvl()
      *
      * @param string $output Passed by reference. Used to append additional content.
      * @param int $depth Depth of menu item. Used for padding.
      * @param array $args An array of arguments. @see wp_nav_menu()
      */
     public function start_lvl( &amp;amp;$output, $depth = 0, $args = array() ) {

        $indent = str_repeat( "\t", $depth );
 $offsetdepth = $depth + 1;
         $output .= "\n$indent<ul class=\"$args->menu_id-items $args->menu_id-items-$offsetdepth\">\n";

   } // start_lvl()

} // class

The function adds two classes to each ul tag in the menus:

  • menu-name-items
  • menu-name-items-depth

Before we can optimize our stylesheet with all these new classes, open the header.php file and find the wp_nav_menu function call (around line 45). We need to tell the primary menu to use our new walker class and add two classes to the top-level ul tag. Add the following just after ‘menu_id’ => ‘primary-menu’ and save the files:

, 'menu_class' => 'primary-menu-items primary-menu-items-0', 'walker' => new _s_Main_Menu_Walker()

At this point, you should have classes that include the menu name and depth on each menu item list, menu item, and menu item link, allowing us to apply styles to the correct element using a few identifiers per selector as possible.

Change the Stylesheet

Since we can now access each part of the menu directly with a class, lets look at what needs to change in the current stylesheet.Here are the rules we can change in the Menus section:

  • .main-navigation ul
  • .main-navigation li
  • .main-navigation a
  • .main-navigation ul ul
  • .main-navigation ul ul ul
  • .main-navigation ul ul a
  • .main-navigation ul ul li
  • .main-navigation li:hover > a, .main-navigation li.focus > a
  • .main-navigation ul ul :hover > a, .main-navigation ul ul .focus > a
  • .main-navigation ul ul a:hover, .main-navigation ul ul a.focus
  • .main-navigation ul li:hover > ul, .main-navigation ul li.focus > ul
  • .main-navigation ul ul li:hover > ul, .main-navigation ul ul li.focus > ul
  • .main-navigation .current_page_item > a, .main-navigation .current-menu-item > a, .main-navigation .current_page_ancestor > a, .main-navigation .current-menu-ancestor > a
  • @media screen and (min-width: 37.5em) { .main-navigation ul

We’re going change these, respectively, to:

  • .primary-menu-items
  • .primary-menu-item
  • .primary-menu-item-link
  • .primary-menu-items-0 ul
  • .primary-menu-items-1 ul
  • .primary-menu-items-1 a
  • .primary-menu-items-1 li
  • .primary-menu-item:hover > a, .primary-menu-item.focus > a
  • .primary-menu-items-1 :hover > a, .primary-menu-items-1 .focus > a
  • .primary-menu-items-1 a:hover, primary-menu-items-1 a.focus
  • .primary-menu-item:hover > ul, .primary-menu-item.focus > ul
  • .primary-menu-item-1:hover > ul, .primary-menu-item-1.focus > ul
  • .current_page_item > .primary-menu-item-link, .current-menu-item > .primary-menu-item-link, .current_page_ancestor > .primary-menu-item-link, .current-menu-ancestor > .primary-menu-item-link
  • @media screen and (min-width: 37.5em) { .primary-menu-items

As you can see, we can get now apply styles to elements deep in a menu without needing to add more identifiers to select them. This also allows us to get rid of qualifying identifiers like “.main-navigation … ” because the menu name is now in a class in each item.

A quick note about the numbering before we move on. Computers start counting at 0, rather than 1, so the top-level menu items will be level 0, the next level is 1, etc.

Here are the results from our changes:

  • Total Stylesheet Size: 14405, up from 14344, but this expected since the class names are longer, therefore increase the byte size.
  • Total Identifiers: 350, down from 389
  • Identifiers Per Selector: 1.475, down from 1.6375
  • Specificity Per Selector: 8.566666666666666, down from 8.729166666666666

Wrapping Up

We’ve now performed the more difficult optimizations and seen the improvements in our Parker scores. In the final post, we’ll look back at our changes and see the overall improvement in our Parker scores. We’ll also talk about where to go from there.

Improving Underscores Stylesheet Using Parker

In the previous post in this series about Parker, we created a baseline for the _s stylesheet and went through the results to understand them better. We also get some ideal scores for each metric. Now that we understand what we’re trying to do and why, let’s see how we can change the default _s stylesheet to get better scores from Parker and create a simpler, more maintainable stylesheet.

Changing the _s Stylesheet

When examining the baseline results, we can spot several places where the results differ from the ideal score and we can achieve:

  • Reduced Total Stylesheet Size
  • Reduced Total Selectors
  • Reduced Total Identifiers
  • Reduced Selectors Per Rule
  • Reduced Identifiers Per Selector
  • Reduced Specificity Per Selector
  • Reduced Top Selector Specificity
  • Reduced Total ID Selectors

Top Selector Specificity

Let’s start with the Top Selector Specificity. This one actually knocks out the Total ID Selectors as well since its the same selector. In style.css (and/or sass > modules > accessibility.scss), remove the “#content” at line 682 to become:

[tabindex="-1"]:focus {

There’s no reason any element with a tabindex value of -1 would need an outline. It’s simply more efficient to apply this style to any and every element with that attribute value, so this is an easy win.

Now, if we rerun Parker on the style.css file, we get:

  • Total Identifiers: 507
  • Identifiers Per Selector: 1.825, down from 1.8285714285714285
  • Specificity Per Selector: 10.089285714285714, down from 10.446428571428571
  • Top Selector Specificity: 30, down from 120
  • Total Id Selectors: 0

In addition to improving several of our stats, the Top Selector Specificity Selector has changed to the next “worst offending” selector. However, all the infinite-scroll classes fall into the “we can’t control what other coders give us” category, so we’ll leave that alone.

Identifiers Per Rule

Another fairly easy tweak will decrease the Identifiers Per Rule and the Selectors Per Rule. In the style.css, we’re going to remove all input selectors before a [] selector. Look at the Forms section, which starts around line 420. Many of the selectors here are structured like: input[input=”sometype”]. Parker and browser see two selectors here: “input” and “[type=”sometype”]”. However, its extraordinarily rare that any other element is going to use the type=”text” attribute or any of the others listed here, so the prefix of “input” can be removed entirely.

While that’s all well and good for the button selectors, the field selectors are another story. Do we really need to specify each type of field here? Its more efficient to take all the input[type=”text”], input[type=”password”], etc and make the entire selector just: “input, textarea”. Then move all the button selectors below this edited selector, so they get different styling than the generic “input” styling. If we need different styling for a particular input type, we can add that in after the input selector’s declaration. So the Forms sections goes from this:

Forms Screenshot Before

To this:

Forms Screenshot After

When we rerun Parker on the updated stylesheet, we get:

  • Total Stylesheet Size: 14647, down from 15424
  • Total Selectors: 252, down from 280
  • Total Identifiers: 423, down from 507
  • Selectors Per Rule: 1.8805970149253732, down from 2.08955223880597
  • Identifiers Per Rule: 1.6944444444444444, down from 1.825
  • Specificity Per Selector: 9.305555555555555, down from 10.089285714285714

Normalize

We can reduce that even further by changing the Normalize.css section to update it closer to the current version (v 5.0.0 as of this writing). Remove all the “input” prefixes in the Normalize section at the top. This changes results in:

  • Total Identifiers: 413
  • Identifiers Per Selector: 1.6547619047619047
  • Specificity Per Selector: 9.265873015873016

Clearings

Another easy win is in the Clearings section. Currently, the stylesheet has 12 selectors in the first declaration, and 6 in the second. Almost all of the selectors besides “clear” can be removed by adding the “clear” class to the elements in the theme. The one exception is the comment-content class since the comments content is output from WordPress and there isn’t currently a way to add the clear class to that output.

Open the template-parts/content-page.php and template-parts/content.php files, add the clear class to the entry-content div. Then remove the corresponding “.entry-content” selectors from the Clearings section of the stylesheet.

Open header.php and add the clear class to the header element and the .site-content element. Then remove the “.site-header” selectors and the “.site-content” from the Clearings section in the stylesheet.

Open footer.php and add the clear class to the footer element, then remove the “.site-footer” selectors from the Clearings section in the stylesheet.

The results from this change have no affect on the styling or appearance, but we get much better stats from Parker:

  • Total Selectors: 240, down from 252
  • Total identifiers: 389, down from 413
  • Selectors Per Rule: 1.791044776119403, down from 1.8805970149253732
  • Identifiers Per Selector: 1.6375, down from 1.6547619047619047
  • Specificity Per Selector: 8.729166666666666, down from 9.265873015873016

Wrapping Up

We’ve gone through the majority of the _s stylesheet and optimized it to improve our Parker scores. However, the biggest optimization we can make is with the menus. In the next post, we’ll go through all the code and changes we’ll need to add, in addition to the changes to the stylesheet.

Creating a Baseline for Parker

In the previous post in this series about Parker, we installed the stylesheet analysis tool and all its dependencies. Now, we’re going to create a baseline measurement of the default _s stylesheet and explain the results from Parker.

Create a Baseline

First, open Finder/Windows Explorer and navigate to the folder where you cloned _s. Open Terminal (or your preferred command line app), type in:

parker 

Note the space at the end! Drag the _s stylesheet file to Terminal. This puts the path to the stylesheet in Terminal. Hit enter to run Parker. The results will be something like this:

PARKER-JS

Total Stylesheets: 1

Total Stylesheet Size: 15432

Total Rules: 134

Total Selectors: 280

Total Identifiers: 508

Total Declarations: 243

Selectors Per Rule: 2.08955223880597

Identifiers Per Selector: 1.8285714285714285

Specificity Per Selector: 10.446428571428571

Top Selector Specificity: 120

Top Selector Specificity Selector: #content[tabindex="-1"]:focus

Total Id Selectors: 1

Total Unique Colors: 15

Unique Colors: #FFFF00,#000000,#C0C0C0,#404040,#EEEEEE,#666666,#FFF9C0,#FFFFFF,#CCCCCC,#BBBBBB,#E6E6E6,#AAAAAA,#111111,#F1F1F1,#21759B

Total Important Keywords: 2

Total Media Queries: 1

Media Queries: screen and (min-width: 37.5em)

Before we move on, let’s briefly go through the terminology in the results so we understand everything and what may need to change.

Selector vs Declaration vs Identifier vs Rule

If you’re like me and find all the terms confusing, this diagram maps it out. At minimum, I’m adding this for my future self who doesn’t remember what’s what.

parker-css-parts
This entire thing is a rule.

Parker Results, Explained

Total Stylesheets

The total quantity of stylesheets Parker examined. You can add multiple stylesheets at once and Parker will spit out results for all of them. If you do examine multiple stylesheets at once, Parker combines the results into one set of results. I’d advise testing each sheet separately.

Total Stylesheet Size

The size, in bytes, of the stylesheet. While there’s not really an “ideal” size, smaller is better.

Total Rules

The total quantity of CSS rules in the stylesheet. A “rule” is the selector and the styles applied to it. There’s not an ideal number of total rules to achieve, but a smaller number means the stylesheet is simpler.

Total Selectors

The total quantity of selectors used in the stylesheet. Selectors are combinations of identifiers for selecting an element on the site to which styles are applied. There’s not an ideal number of total selectors to achieve, but a smaller number means the stylesheet is simpler. Here are some examples, each of these counts as one selector:

  • .this-is-a-class
  • .this-is-a-class a
  • .this-is-a-class a:hover
  • .main-navigation ul ul ul li a

Total Identifiers

The total quantity of identifiers used in the stylesheet. Not to be confused with IDs, identifiers are each part of a selector. There’s not an ideal number of total identifiers to achieve, but a smaller number means the stylesheet is simpler. Here are some examples with their identifier count:

  • .this-is-a-class – 1
  • .this-is-a-class a – 2
  • .this-is-a-class:hover- 2 (pseudo selectors count separately)
  • .main-navigation ul ul ul li a – 6

Total Declarations

The total quantity of declarations in the stylesheet. Declarations are the CSS property and value. There’s not an ideal number of total declarations to achieve, but a smaller number means the stylesheet is simpler. An example declaration is:

color: #fff;

Selectors Per Rule

The total quantity of selectors used in each rule. Rules can apply to more than one selector, like “.this-is-a-class, .this-is-another-class”. This metric shows the mean of selectors used for each rule. Ideally, this number would 1 and each class would be reusable and only contain the styles needed for that class. This is one of those opinionated things I mentioned before. In Harry’s opinion, using multiple selectors like this should be avoided:

button, [type="button"], [role="button"], [type="reset"], [type="submit"]

We should create a single class and apply that class to all elements requiring those styles. However, as theme developers, we are often stuck having to cover all possible bases, since we can’t control the code output from plugins and sometimes WordPress itself.

The ideal for this value is 1, but I would advise getting as close to 1 as possible. Getting this number under 2 is doing really well.

Identifiers Per Selector

The total quantity of identifiers per selector. An ideal value is between 1 & 2. A single identifier per selector makes the minimum score of 1: “.this-is-a-class” is one identifier and one selector. This is one of the more challenging metrics to achieve the ideal score since we can’t control the code and classes we get from plugins and sometimes WordPress. Particularly, the default WordPress menu classes cause many developers to use selectors like: “.nav-primary ul ul ul li a”. While this gets the job done, it also results in an abysmal score for this metric: 6. Later, we’ll go over a method to reduce this particular selector down to a 1.

Specificity Per Selector

The mean of the specificity score of each selector. The easiest way to explain specificity is through examples:

a { color: #000; }

Applies to all links, so its not very specific.

.link-to-home {color: #000; }

Applies to any element with the class “link-to-home”. More specific than styling all the “a” tags, but less specific than using an ID.

#link-to-home {color: #000; }

Only applies to the element with the ID “link-to-home”. There should only be one of these elements, so it is extremely specific.

Parker is intended to help make your CSS classes reusable, so your specificity score should be as low as possible. This means your styles are reusable and don’t apply to super-specific elements. Typically, between 10 and 20 is doing pretty well, since we’ll mostly use classes for applying styles. Here’s the scoreboard used by Parker:

  • Universal selectors (like *): 0
  • Element selectors (like input or a): 1
  • Classes, attributes, and pseudo selectors: 10
  • IDs: 100

Top Selector Specificity

The highest specificity score in the stylesheet. There’s not really an ideal, but I’d say if you’re most specific selector is 30 or less, you’re doing pretty good.

Top Selector Specificity Selector

The selector with the highest specificity score in the stylesheet. This makes is easier to find the “worst offender” and refactor your code to eliminate it.

Total Id Selectors

Total quantity of IDs used in the stylesheet. Ideally, this is 0 since we shouldn’t style using IDs – they are too specific and the style rule cannot be reused.

Total Unique Colors

The total quantity of colors used in the stylesheet. This could be useful to spot small color variances (like multiple shades of light gray) and refactor them to use fewer colors throughout. A stylesheet with fewer colors is a simpler stylesheet.

Unique Colors

A comma-separated list of all the color codes used in the stylesheet.

Total Important Keywords

The total quantity of the use of “!important” in the stylesheet. Ideally, this number would be 0, but there are still valid uses of !important, so make sure your usage is justified.

Total Media Queries

The total quantity of media queries in the stylesheet. There’s no ideal number, but a smaller number of total media queries means a simpler stylesheet.

Media Queries

A comma-separated list of all the media queries used in the stylesheet. Useful for refactoring media queries for simplicity.

Wrapping Up

Now that we’ve learned what each result from Parker means and the ideal scores for each metric, we can start tweaking the _s stylesheet to get better scores and create a simpler, more maintainable stylesheet. In the next post, we’ll cover some easy wins to get closer to our goal.

Installing Parker

In my introductory post, I shared about the CSS analysis tool named Parker. In this post, we’ll cover installing Parker on your local machine so you are able to analyze your own code.

Before performing any of the following steps, you’ll need to install Parker and its dependencies. Parker runs from the command line, so you’ll need to open your favorite terminal app. I’m on a Mac, so I’ll be using Terminal. I’ll provide the instructions here for installing everything on a Mac, sorry Windows peeps. If you need assistance or run into difficulties with installing any particular thing, visit that tool’s site or try StackExchange. Here’s what you’ll need to install to follow along:

  • Xcode dev tools
  • Homebrew
  • node.js & npm
  • Parker
  • _s

 

Installing Xcode and the Developer Tools

Install Xcode before installing ParkerOpen Terminal and hit enter after typing/pasting:

xcode-select --install

This should open an application installer wizard for the developer tools. Go through the prompts and install the package. (Source: OS X Daily)

Installing Homebrew

Once that’s finished, install Homebrew, which makes installing packages on OS X easier. In Terminal, hit enter after typing/pasting:

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

This script installs Homebrew. It will ask for confirmation that you want to install it. Follow the prompts. (Source: Homebrew)

Installing node.js and npm

Once Homebrew is installed, installing node.js is fairly simple. In Terminal, hit enter after typing/pasting (Source: George Ornbo):

brew install node

Installing Parker

Installing Parker at this point should be fairly simple. In Terminal, hit enter after typing/pasting:

npm install -g parker

The “-g” installs Parker globally, so you can access it from anywhere in your system (rather than just inside a specific project or folder). (Source: Harry Roberts)

Copy _s

Lastly, we’ll need a copy of _s. Open Finder and decide where you want to save _s. This can be any folder; I put my copy of _s in Dropbox. In Terminal type/paste:

cd 

Be sure to leave a space at the end! Drag your work folder from Finder to Terminal. This puts the path to your work folder into Terminal. Hit enter and your working directory in Terminal changes to your work folder. Use git to clone the _s repo from Github and work with it on your computer. In Terminal, hit enter after typing/pasting:

git clone git@github.com:Automattic/_s.git

Wrapping Up

In the next post, we’ll use Parker to create a baseline measurement so we can see if any of our optimizations are effective. I’ll also explain what each  result in the report from Parker means.

Parker and WordPress Theme Development

Lately, I’ve been playing with a CSS analysis tool called Parker created by Katie Fenn. Parker examines your stylesheet and gives a treasure trove of metrics. While some of these metrics are merely interesting factoids (like the number of CSS rules), others offer constructive criticism for improvement. The general philosophy is to create more maintainable CSS by simplifying your stylesheet.

Harry Roberts, of csswizardry.com, has an excellent write-up about using Parker. He explains some of the options and offers some ideal scores to shoot for, which I’ll list and explain in later posts. WordPress developers will need additional code to change the WordPress-generated code, like in menus.

In the following posts, I’m going to use Parker to test my fork of the _s starter theme and made optimize it based on the results. I’ve based every project over the past two years on _s and advise anyone learning theme development to start there. This post will serve as a sort of table of contents; I’ll link to each post as they are published.

Why Use Parker?

As I mentioned above, Parker is good for reducing the size and complexity of your stylesheet. While that’s not a big concern for small projects, for larger projects, this can be a lifesaver. Maybe other developers come along and start adding new features, new CSS methods (floats vs flexbox vs grid) or using different methods (BEM vs Atomic vs random…) and your stylesheet gets more and more complex.

Ideally, the newer developer(s) would check the stylesheet for existing styles that accomplish what they want. Since this doesn’t happen many times, Parker can at least tell them whether their code and existing code can be simpler.

Posts in This Series