Debugging CSS

profile photo
Filip Hric
CSS doesn’t throw an error when something goes wrong. This can make it particularly tricky to debug why your application doesn’t look as expected. Here is an approach to debugging CSS, and some things to keep in mind that are specific to CSS.

Approaching CSS bugs

The first step is to isolate the styles that are affecting your element. It may be tempting to just comment out random CSS rules until you find something that hits (we’ve all been there), but if you can zero in on the offending element and its styles, you’ll have a much easier time debugging.
This can often be easier said than done. CSS can be applied from multiple sources and to multiple elements at the same time, so tracing the source can be like searching for a needle in a haystack.
This is where an inspector in a debugger like Replay can come in handy. It will let you see all the applied styles for a given element, the source, and any styles that were overridden.

Viewing applied styles in a debugger

The following screenshots are from this replay of a React Calculator app. Feel free to follow along!
In this screenshot, we’ve selected the - button on our calculator, and can see the corresponding HTML and CSS in the Elements panel.
Image without caption
We can see what selectors were used to target this element, the properties defined, and their values. We can also see where in the code our styles are defined, so if there is something unexpected, we know where to go looking for it!
To the right of each rule, it states our styles were defined inline on lines 24, 20, and 11. This corresponds to the Button.css file for our button component below.
Image without caption
Now we know what CSS rules are being applied to our element, and the source.

Understanding specificity

Let’s dig in to the CSS Rules pane to understand why this button is orange, and not gray like the other buttons.
Image without caption
These are ordered based on specificity. Specificity refers to the order of importance that rules are applied to an element when using CSS. For more on specificity, check out this great article from Smashing Magazine.
In our example, we see the first selector is component-button.orange which has a background-color set to orange via an rgb value. This is more specific than the component-button class selector two sections down, which has a background-color set to gray.
This means that the orange background-color value will override the gray. An overridden value is indicated by a strikeout in the debugger. So, we know that while this value would have applied, it was overridden by something more specific.
Let’s say I wanted to update all the buttons to blue because it’s my favorite color. I might think that just changing the background-color in the component-button class would do the trick. As we’ve just seen, however, I’d also need to remove or update the component-button.orange class due to specificity.

CSS and JavaScript frameworks

So we know that component-button.orange is applied to this element, and we found where the rule is defined. But it’s not entirely clear yet where this style rule is being attached to the element.
Traditionally, CSS classes are defined in an HTML element. With a JavaScript framework like React which uses JSX, CSS classes can be added to an element dynamically based on application logic. This can make it more complex to identify the source of a CSS selector.
Image without caption
In this case, we are using React props to designate if a button should have a class of orange. We can see this in the replay under the React DevTools tab. In the props pane, orange has a value of true.
Image without caption
In our Button.js component file on line 20, an additional class of orange will be applied if this.props.orange is true.
This is tricky because if we tried to search our codebase for component-button.orange to see where the class was applied, the component file wouldn’t match. If you know your application has applied styles based on props, reviewing the React props using Replay or React DevTools can be helpful for targeting these classes.
Image without caption
Let’s go back to our blue button example. If we want all the buttons to be one color, we need to remove the orange props being passed in the ButtonPanel.js component file for our component-button class update to work. With modern frameworks, we may have to change JavaScript files to resolve an issue with CSS.
Image without caption

CSS debugging concepts

Now that you know how to leverage developer tools to isolate assigned styles with CSS, here are some concepts to keep in mind when debugging the root cause of CSS issues.

Selectors, specificity, and sources

If you isolate an element and don’t see a style applied as expected, there is likely an issue with the selector. Selectors can be based on element type, class, or id, but can also be altered with combinators that select an element based on relationship like descendent or sibling. You can also group selectors so a single style rule is applied to multiple selectors at once. Then, there are the pseudo classes and elements! It’s a lot.
When inspecting the element in a debugger, if the rule is being overridden, you’ll want to update the selector to account for specificity. You also may have competing rule definitions based on the cascade (the C in CSS). If you have multiple style sheets, review the cascade algorithm to confirm the order sources are being applied.
If the rule isn’t being applied at all, then the selector will need to be rewritten to correctly target the element. Read more about CSS selectors here.

Box model

Debugging issues with the spacing of elements can be especially difficult. In CSS, every element is represented by a box — even text, and even empty divs. This box has defined marginborder, and padding, and then the content itself, which has a width and height.
Let’s say I wanted to change the color of the border for one of the buttons in our calculator example.
Image without caption
In my code, I notice that the CSS rule for this button has a border value of 0. So what’s going?
Replay helpfully displays the box model properties within the Layout tab in the Elements panel.
Image without caption
The button looks like it has a gray border, but here we can see that there is a border of 0 but a 1px margin on the right of the element. This means what looks like a border is actually the gray background showing through. This could be tricky to debug if we wanted to update this “border” that doesn’t actually exist.


The box model also applies to the layout of elements. In the same image above, we see the following properties and their values:
  • box-sizing: sets what is included when calculating the width and height of an element (content only or inclusive of border and padding)
  • display: sets whether the element is block or inline and/or sets the layout of the element’s children (flex, grid, etc.) Potentially the most important property for element layouts.
  • float: if set, aligns an element to one side of its container (left or right) so inline elements can move around it.
  • line-height: primarily used to set the distance between lines of text.
  • position: sets how an element is positioned on the document. Not typically needed if using Flexbox or Grid.
  • z-index: sets the stacking order of the element. Elements with a higher z-index cover lower z-index items.
Reviewing these values in a debugger can identify the root cause of unexpected layout behavior. If you are interested in better understanding Flexbox and Grid layouts, I recommend checking out the Flexbox Froggy and Grid Garden games.

Media queries

Media queries will alter CSS rules based on the type of device, and are often used to create responsive styles across different size screens. If something with your layout suddenly breaks when switching to a mobile viewport, a media query issue may be to blame.
Additionally, if you have media queries but they aren’t rendering as expected, you may need to update the viewport meta tag in your HTML.

Browser compatibility

Finally, if everything else is correctly defined but your styles still aren’t appearing as expected, you may have a browser compatibility issue. MDN has a browser compatibility table for every CSS property that will show if it is supported in the browser you’re using to view the application.
Image without caption
There is also caniuse.com that lets you search properties and view their browser support.

More resources

If you’re still stuck, here are some more great resources that dive into common issues with CSS.
Related posts
post image
In this failure, we look into a bug where a React component calls Math.round and gets a different value when the test passes and fails!
post image
This week we’re excited to share Elements Panel V3, which brings one second element loads.
post image
Today we’re excited to share an entirely new version of React DevTools which Brian Vaughn wrote from scratch.
Powered by Notaku