How to Change the CSS of a WordPress Theme (and Not Go Crazy)

CSS going crazy

The subject we’ll be tackling is how to make clean, logical, stable changes to the CSS of your WordPress site. We’ll be accounting for the fact that this often involves overriding existing CSS styles from the original parent theme, as well as plugin files, while leaving them intact—meaning that you’ll be working within a large, often complex landscape of overlapping CSS styles.

For this article, it’s best if you have general understanding of the following:

If any of the above is new to you, now’s a great time to learn those things! We’ll be here.

We’ll look at the two core concepts you need to make intelligent CSS changes to your WordPress site, and then look at a couple of case studies to draw out principles to work from.

Core concepts: breadth and specificity

Every styling change you make needs to get two things right:

  1. Breadth: The style applies to elements it should apply to, and doesn’t apply to elements it shouldn’t apply to.
  2. Specificity: The style shows up under the correct circumstances, by overriding more general styles that also apply to the same elements, and being overridden by more specific styles.

More on breadth

Breadth is using the right CSS identifiers to make sure which elements you talk to.

So breadth is using the right CSS identifiers to make sure which elements you talk to.

There are a few ways to achieve breadth. For starters, * means “everything,” so html * targets everything inside the HTML document—everything but the HTML tag itself. More common is to target multiple elements in a single style declaration: p, div.contains-text will target all p elements, plus all div elements with class “contains-text.” There’s also the “implied breadth” of writing a style directly to a very common element, like img or p; these changes will show up wherever these elements are used across your site.

Achieving narrowness (low breadth) is at least as important as achieving high breadth. .single #main .entry-body is a narrow CSS identifier we use on the site. It specifies that inside posts with class “single,” and further inside the element with ID “main,” the element with class “entry-body” should have a particular style. That’s a lot more targeted: It’ll ignore everything that isn’t a single blog post (for example, anything in a WordPress page, or a WordPress post archive), and furthermore anything that isn’t the particular “entry-body” element within the main body of a single post.

In WordPress, you’ll spend about equal time making your changes apply everywhere they’re supposed to, and don’t apply where they don’t belong.

In a WordPress context, you’ll spend about equal time trying to make sure that your changes apply everywhere they’re supposed to, and that they don’t apply where they don’t belong. The diversity of page and post templates and other sorts of markup environments across a typical WordPress site can make this tricky, as we’ll see below.

More on specificity

Overruled | CSS specificity in WordPressOverruled!

Specificity is actually a defined technical quantity in CSS. If you haven’t read up on it yet, please do so; you won’t regret it.

Technical details aside, specificity is about determining which styles get priority when multiple styles address the same element. For example, body div is less specific than body div#content, so if those two style declarations conflict on a detail (say, font-size), the latter will win out: its styles will be implemented by the browser, and those styles that contradict it in the less specific declaration won’t be.

Much of your work will be to ensure that your styles are more specific than existing styles from another stylesheet.

Much, but not all, of your work with CSS specificity in WordPress will boil down to ensuring that the style you’re declaring is more specific than an existing style from another stylesheet that talks to the same element.

Case study 1: image margins for featured images

I recently realized that the featured images in our single posts need a larger bottom margin to look good. Marking this up properly turned out to require a bit of creativity.

Working with CSS in WordPress

The Chrome inspector revealed that the element was inheriting two relevant styles: a 5px bottom margin assigned to all img elements, and a bit of border styling assigned to all .entry-body img elements.

Neither of these styles make sense to modify. We’re trying to change the margins for our featured image—not every image on the site (that’d be way too much breadth). The .entry-body img rule would certainly override the img rule, as it has higher specificity, but it’s still a lot more breadth than we want: as its name suggests, .entry-body wraps around the main body of post or page content, so targeting that in our rule would change the margins of every image within the main content of every post and page.

So all of our existing rules are too broad. What we need to do is target only featured images inside single posts. After I looked around the markup a bit, I found that the best way to do this is probably as follows:

.single-post img.wp-post-image {
	margin-bottom: 1em;
}

This targets the img with class “wp-post-image” inside the element with class “single-post”—which equates to the featured image inside single posts, which is exactly as narrow as we want it. The rule is also specific enough to override the 5px bottom margin given to all img elements across the site.

Takeaways

  • Before making your styling changes, always use the Chrome inspector (or something like it) to inspect the existing styling rules in place. If you don’t do this, you’re flying blind.
  • You can’t always add to or modify existing style declarations; sometimes you need to target elements in a new way.
  • Make liberal use of the body classes that most themes assign to different page templates, like single-post for individual posts, single for individual posts (including custom post types), home for whichever page is the homepage, blog for the main blog index, and page for pages. These help you make sure you’re talking to the right kind of posts—otherwise, you could be making changes to your blog posts that spill over to your homepage as well.
  • Also use the WordPress classes that go on specific elements. The wp-post-image class is pretty obscurely named, but it only applies to featured images. Targeting the correct img elements without access to this class would have been possible, but would have required a much more verbose styling rule.

Case study 2: Working with WooCommerce buttons

WooCommerce is a giant plugin, and the range of markup it can generate is staggering. As a result, styling rules applied to WooCommerce elements, such as purchase buttons, tend to be dizzyingly broad, because they’re designed to capture all possible permutations of button markup that could appear on a given page. This e-commerce site is an example:

CSS styling WooCommerce buttons

Let’s say that our job is as follows: turn all buttons red, but only on the Cart page.

First, let’s use the Chrome inspector to look at the breadth of markup possibilities that inherit that goofy background: #333 !important style. They’re as follows:

.woocommerce a.button, .woocommerce-page a.button, .woocommerce button.button, .woocommerce-page button.button, .woocommerce input.button, .woocommerce-page input.button, .woocommerce #respond input#submit, .woocommerce-page #respond input#submit, .woocommerce #content input.button, .woocommerce-page #content input.button

Another important thing to notice is that the style that’s making the button gray is a product of the parent theme (“Salient”), not WooCommerce itself. This presumably means that the button color is intended to be a theme customization option accessible from the WordPress admin area—but that doesn’t really help us, unless they’ve got a specific option for “buttons on the Cart page.”

So the first thing we’ll want to do is restrict our breadth to the Cart page. Luckily, WooCommerce has a body class called woocommerce-cart that should handle that.

On the other hand, we’d like our changes to persist no matter what kind of button is appearing on the Cart page. It’s currently a “Return To Shop” button, but who knows what markup will come along with our “Proceed To Checkout” buttons?

!important is the “nuclear option” of specificity.

The final thing we’ll want to do is actually get our change implemented, which is complicated slightly by the !important slapped on the current rule. !important is the “nuclear option” of specificity—it overrides anything that doesn’t have an !important on it as well.

So we know we’ll need to do the following:

  1. Put an !important on our style declaration, to override the competing !important on the original style.
  2. !important aside, find a way so that our code overrides the existing code in terms of conventional specificity.
  3. Apply our changes everywhere that the current style is being applied, but only on the Cart page.

We can combine #2 and #3 above by adding .woocommerce-cart to the beginning of every targeted object in the style declaration. This will add specificity relative to the original declaration, while confining the style’s breadth to Cart page contents.

The finished product is this monster:

.woocommerce-cart .woocommerce a.button, .woocommerce-cart .woocommerce-page a.button, .woocommerce-cart .woocommerce button.button, .woocommerce-cart .woocommerce-page button.button, .woocommerce-cart .woocommerce input.button, .woocommerce-cart .woocommerce-page input.button, .woocommerce-cart .woocommerce #respond input#submit, .woocommerce-cart .woocommerce-page #respond input#submit, .woocommerce-cart .woocommerce #content input.button, .woocommerce-cart .woocommerce-page #content input.button { 
	background: #d33 !important;
}

Once we’ve put this in place, we want to test to make sure our changes are as persistent as we want. It seems sane to mistrust that the theme authors got every permutation of button on the Cart page, so let’s add something to our Cart and see what the buttons look like. If some of them haven’t listened to our new rule, we’re going to look at the giant set of elements that do talk to our disobedient buttons, add .woocommerce-cart to each of them, and repeat.

Takeaways

Working in WordPress can feel silly. This is normal; proceed with your head held high.

  • Know where existing styles are coming from. Knowing that the big dumb !important styles are from the site’s parent theme, and not any stylesheet inside WooCommerce itself, gives confidence that modifying it won’t break anything important.
  • Work on different levels. In this case, we’re matching the dizzying breadth of the existing style, and prepending a body class both to contain that breadth to the Cart page, and to get the bit of extra specificity that ensures our styles will be adopted.
  • In general, don’t use !important, particularly not in theme or plugin development. It sets off an arms race, and pretty soon everyone is back where they started except with !important stuck to everything.
  • Working in WordPress can feel silly, when you’re trying to surf on top of the questionable decisions of a host of prior theme and plugin authors—or even when you’re just trying to change the tip of a huge and poorly comprehended styling iceberg. This is normal; proceed with your head held high.

Conclusion

Thanks for reading! I hope this has given you a sense for some of the issues you’ll face modifying CSS in WordPress, as well as the two key concepts—breadth and specificity—that’ll allow you to do it correctly. I also hope you’ve gained a bit of sense for the problem-solving aspect of making CSS decisions in a WordPress context. Once you do it long enough, it’s a strange kind of fun!

What do you do to make your CSS changes go smoothly in WordPress? We’d love to hear from you in the comments below.


8 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
Ashutosh Jha
August 1, 2015 12:45 pm

This was an awesome post

Custom Scripts and Styles In WordPress | robii
February 20, 2015 11:54 am

[…] and WordPress takes care of the rest. Used well, this lets you avoid some of the more painfulspecificity olympics—or, worse, !important contests—you’d otherwise […]

Don't Over-@extend Yourself in Sass (Or: There's a Class for That!) - Press Up
November 12, 2014 4:46 pm

[…] This type of unusable, uninterpretable styling rule frequently and needlessly complicates working in WordPress, and requires unreasonable amounts of creativity to work around. […]

Everything You Should Know About Using Custom Scripts and Styles In WordPress - Andrew Good
August 21, 2014 6:22 am

[…] and WordPress takes care of the rest. Used well, this lets you avoid some of the more painful specificity olympics—or, worse, !important contests—you’d otherwise […]

Everything You Should Know About Using Custom Scripts and Styles In WordPress | WPShout.com
August 19, 2014 1:00 pm

[…] and WordPress takes care of the rest. Used well, this lets you avoid some of the more painful specificity olympics—or, worse, !important contests—you’d otherwise […]

toko online murah
May 7, 2014 6:04 am

I actually do not know much about css, but I am curious about the colors and layout tatak my website. so I often try
(but I’ve backup my website before I practice)

Hugh C
May 6, 2014 7:23 pm

The one thing that keeps my CSS sane and legible is not to edit it directly at all, but instead to use less and compile it to CSS every time I save (I use WinLess, there are many other compilers to choose from). Although it may seem like another thing to learn, a grounding in just the basics of the syntax with respect to hierarchy make things an order of magnitude easier to rea, and much less verbose.

The end result of selectors like the button example above may be spaghetti, but trying to craft such code by hand is grief, and considerably more error-prone.