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.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.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.
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.
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
.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.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.
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 margin
, border
, 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.
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.
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.Layouts
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.
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.
- A Guide to CSS Debugging — Smashing Magazine
- Debugging CSS — MDN Web Docs
- Debugging Tips and Tricks — CSS-Tricks