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:
- Cascading Style Sheets (CSS)
- Good ways of editing theme resources, either by working inside a child theme or a custom CSS plugin (not the original theme stylesheet!)
- Using Chrome Developer Tools (the “Inspect element” option when you right-click in Chrome), or a similar tool in another browser.
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:
- Breadth: The style applies to elements it should apply to, and doesn’t apply to elements it shouldn’t apply to.
- 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
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.
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, andpage
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 correctimg
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:
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:
- Put an
!important
on our style declaration, to override the competing!important
on the original style. !important
aside, find a way so that our code overrides the existing code in terms of conventional specificity.- 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.
This was an awesome post
For English speakers (thanks Google translate): “Although it may seem like another thing to learn, a grounding in just the basics of syntax with respect to hierarchy makes things an order of magnitude easier to read, and much less wordy.”
Well said!
[…] 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 […]
[…] This type of unusable, uninterpretable styling rule frequently and needlessly complicates working in WordPress, and requires unreasonable amounts of creativity to work around. […]
[…] 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 […]
[…] 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 […]
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)
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.