Written by Patrick Brosset✏️
You know the feeling when you’re trying to achieve some styling or layout with CSS and it just won’t work? I know I do and if you’ve done any kind of work with CSS you probably had that feeling many times too, especially when you were starting out.
CSS looks (and is) simple on the surface, and as a result people tend to not spend too much time learning much about it. Certainly not as much as they would another, perhaps more traditional, language.
However, the sheer number of properties, values, and ways you can combine them makes it a complicated language after all, and one where it’s hard to know just how to achieve a given result. On top of this, CSS is a very resilient programming language. It will apply to your page, at least partially. Even if you get it wrong, if you still follow the general syntax, your code will load, be parsed, and (partially) run.
JavaScript, being an imperative language, lets you describe how to do something. If the code you wrote doesn’t lead to the expected result, then you investigate why. This is often done by adding console logs or using a debugger.
On the other hand, CSS is a declarative language. With it, you tell the computer what to do, not how to do it. This means the browser engine is the one that figures out the “how” part and it’s all hidden from you. You don’t have access to that part of the code and you have no way of adding console messages to it or connecting a debugger to it.
You might get some error messages if your syntax is invalid, which is good, but it’s not enough to debug cases where your code parses and executes fine but just doesn’t do the thing you wanted it to do.
There may be a whole lot of CSS rules and properties you added that were accepted by the browser as totally valid but that didn’t actually produce the effect you were looking for, and that you can’t debug.
When CSS is invalid
Browsers do show certain CSS warnings when things are invalid. Below is a screenshot of a few different CSS warnings that get displayed in the web console in Firefox:
As shown above, Firefox warns about dropped declarations (when a property name is unknown), values that couldn’t be parsed, bad selectors, or at-rules.
These warnings are very useful, but there are times when you don’t get any of them when your code is valid but just doesn’t yield the expected result. What do you do then? You try stuff out until it works. You ask people. You learn CSS.
We’ve all internalized this as the normal way to go about working with the language, but let’s face it, it’s very ineffective and not a great developer experience.
Debugging CSS
Would it be useful if we could debug what the browser did as a result of applying some CSS code to a page? I’m not sure. It might actually be awfully complex given how complicated layout engines are.
There is something else that sets CSS apart from languages such as JavaScript that might come as an advantage here. CSS is a domain-specific language, it is in that sense, more constrained than JavaScript. Its only purpose is to style elements on a page.
Let’s take an example. If you’re using the width
property then it’s probably safe to assume you are trying to describe how wide an element should be, and if whether you add or remove this property does not visually impact the styling of the page, then that property didn’t do the thing you want to do. So perhaps what we need isn’t a debugger in the traditional sense of the term, but instead, a contextual helper that tells you when things don’t actually do what you think they do.
But before jumping to conclusions, let’s look at a few examples.
Common patterns
Let me list a few common examples for when CSS code applies fine but just doesn’t do anything.
Hiding overflowing text
Say you have a line of text and you want it to always fit in some container element, whatever its width. A common design pattern to solve this is cutting the text off before it overflows and displaying an ellipsis.
text-overflow
is the CSS property that can make that happen for you. It has a pretty self-explanatory name and a reasonable number of values that seem to make sense. On the surface, it’s a really simple property to use, right?
If you’ve already used this successfully, then please assume you haven’t for a second. Go back to when you didn’t know about it. Or go on Stack Overflow and look at how many people ask about it, and try to put yourself in their shoes.
It turns out this property only works on block elements, it also only works in the direction the line of text is progressing in (i.e. not at the bottom of a paragraph of text) and it also only works if the element also has overflow:hidden
applied to it.
Not that simple anymore, is it? It’s actually even more complicated than this as it does work with some inline elements that result in a “block frame” under the hood in the layout engine. For instance, a fieldset's legend
element is an inline element, but it still supports text-overflow
because the layout engine “blockifies” this element at run-time.
So, the point is, applying the text-overflow
property to the element is only one part of the puzzle. It will apply fine, but in my cases won’t lead to the result people expect. On the other hand, it will lead to a lot of frustration and time lost.
Sizing elements
width
and height
don’t apply to inline elements, only to blocks. That might seem very obvious to you, but again, assume that you’re starting out with CSS and don’t know it yet.
I certainly remember having to look it up a few times when starting out in my career and that it wasn’t obvious to me at the time why these, seemingly super useful properties, didn’t have any effect on my elements. Again, because CSS seems really simple at first, I think we just overlook the traditional learning phase that normally comes with most programming languages. If you wanted to use a JavaScript function, chances are, you’d probably look it up on MDN and checked what it applied to.
But with CSS, because things like color:blue
seems so simple, we assume the rest of it is simple too, and we just try to use it.
In the case of width
and height
, they only apply to block elements, which means you have to know what is a block element vs. an inline element first. But even more than that, you kind of also need to know what a replaced element is and that’s a lot more involved.
Replaced elements are elements that don’t get their content rendered by CSS. Examples include <img>
and <audio>
. Now, those can be (and are by default) inline elements, but width
and height
do work on them anyway!
Aligning elements
This is probably one of the most common sources of frustration for people. CSS has all of these useful-sounding properties like vertical-align
or align-items
that seems like they would do what you want them to.
However, it turns out you need to know a whole lot of complicated concepts such as what a block or an inline formatting context is or what a grid or flex layout is before you can start using these properties confidently (instead of, you know, trying them out until they work).
For example, align-*
properties only apply in the block/cross/column direction of a layout whereas justify-*
properties apply in the other direction.
So, as you can see, there are cases where CSS seems very simple on the surface when it actually requires expert knowledge for you to achieve a particular effect.
There are dozens of examples like the ones above. If you have examples of your own, I’d love to hear them! Tweet them at me @patrickbrosset.
Introducing Inactive CSS in Firefox
What if there was a way for developer tools to help you with the above? We have JavaScript debuggers and consoles to investigate when JS code doesn’t do what we want it to do. But we don’t have much for CSS.
Debugging CSS code in the traditional sense of the term might not be the right idea, but tooling can still help here. CSS is very expressive and it has a visual impact on the page. Based on this, it should be possible to inform DevTools users proactively when CSS doesn’t have any effect.
This is where Firefox’s Inactive CSS feature comes in. This is a feature my team and I worked on and shipped in Firefox 70 at the end of 2019.
Here’s a screenshot showing what this feature looks like:
At its core, it is very simple and intuitive. Any CSS declaration that is detected as being inactive will be shown greyed-out and will be followed by an information icon that provides an explanation about the problem.
An inactive declaration is one that is valid in terms of syntax, and which applies fine to the element, but just does not produce any effect on the element.
Here is another example screenshot:
Where did it come from?
Back in 2018, we asked a lot of questions to web authors out there related to what challenges they were having when writing CSS. Certain things came back over and over again, like why is this element not fitting in this space? Why doesn’t that property do anything? How did this element get to be that size? It was clear that people needed help with understanding what properties had an effect on an element.
The other thing that really made it click for us was Sarah Lim’s research paper and Ply Web Inspector tool. In the paper, Sarah and her colleagues describe how “visually ineffective properties” are a main source of frustration and time lost when working with CSS. Those are properties that, whether they are added or removed, don’t cause any difference on the page.
How did we do it?
Sarah Lim’s Ply tool uses visual diffing to detect inactive CSS properties. This essentially means taking a screenshot with the property applied, then another one without the property applied and diffing those two images.
This approach is very generic and will apply to all properties in the same way which is great, and it works great for Ply. It can also be a little costly in terms of processing required to do this for all properties applied to a specific element in DevTools. We knew this wasn’t an approach we could use.
In Firefox DevTools, the user experience we designed for Inactive CSS is such that you get a warning about properties as soon as you select an element in the Inspector panel and its applied CSS rules get displayed in the rules sidebar. This is such a common thing users do all the time that we couldn’t make this any slower. So diffing images wasn’t a viable approach for DevTools.
Instead, we added a simple rules engine to DevTools that would do this. In this engine, each rule is responsible for checking if a property (or a set of properties) is active or not, depending on the current conditions.
For example, here is the (simplified) code for one of these rules:
// Flex container property used on non-flex container
{
invalidProperties: ["flex-direction", "flex-flow", "flex-wrap"],
when: () => !this.flexContainer,
}
What that means is the engine will return a warning when the current element is not a flexbox container and one of flex-direction
, flex-flow
or flex-wrap
is used on this element.
Here are all of the rules currently implemented in DevTools.
What is it not?
I think it’s important to realize that this feature comes with a couple of constraints, so let me tell you what it is not.
This tool won’t tell you about all CSS properties. If you did look at the list of rules currently implemented, you probably realized that we’ve made it so it would tell you about the most common pitfalls only, to start with. The list of things Inactive CSS warns you about will grow over time, but starting with a small number of common cases first was important to make sure the feature was rock solid.
Secondly, it is not an audit tool. Such a tool would be awesome, but this is not what Inactive CSS is about. Many people ask if it can scan their entire CSS codebase and tell them about things that can be removed. This is not what Inactive CSS does! Instead, it can tell you things like on this given page, this specific element, under the current circumstances (window size, state, etc.) has a given property that does not have any effect at all.
In that sense, Inactive CSS is a debugging tool, not an audit tool. The way to approach it is if you are trying to create some layout, or center something, or align something and things are not working, then select this element in the Inspector panel, and let the tool tell you why some properties aren’t taking effect.
Is your frontend hogging your users' CPU?
As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.
LogRocket is like a DVR for web apps, recording everything that happens in your web app or site. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.
Modernize how you debug web apps — Start monitoring for free.
The post When CSS doesn’t do anything appeared first on LogRocket Blog.
Top comments (0)