Writing a CSS Parser in JavaScript

We have a lightweight, battle-tested, CSS parser and utility library written in JavaScript. It’s open source; Go and grab it here.

We recently put forth a huge effort to build a cutting edge web designer for web forms. The project took 6 months to complete. The team was cross functional and included both developers and designers. I led the effort to write a CSS Editor and Inspector for the Form Designer. Today, I will share the hard lessons we have learned while building the CSS Editor.

The CSS Editor is a tool that lets you design forms simply by pointing, clicking and editing. It’s similar to the Firefox Firebug or Chrome Inspector. Here is a short video showing how it works:

Here is another video showing more advanced features:

The Idea

Originally, we had a deeply hidden feature on Jotform that allowed you to add CSS code to your forms. The feature was called “Inject CSS.” No matter how much we hid it, our users continued to use it like crazy.

When you see users doing something you don’t expect, there is usually an important lesson to be learned. You need to be humble and think hard about it.

It reminds me of a story I heard. Some guy was designing a university campus. Instead of making the paths that connected the buildings, he just made it all grass and waited for students to walk around. Once people walked on the grass for a while, the most optimal paths became clear. Only then did they pour the concrete. It is a great lesson: Be humble and watch your users.

Our Form Designer/Inspector came to life in a similar way. The users were so crazy about this deeply hidden Inject CSS feature, we knew we had to implement a full blown, point and click CSS editor for them.

Initially, we were only planning to have a point & click inspector, so that users could select an element inside the form. Upon selecting an element, only the styles affecting that specific element would then be shown to the user. Later we decided upon added the editor as well.

The Hard Question

So, how do you find out which styles were affecting a selected element? We looked for a simple workaround or an existing solution. Unfortunately, we couldn’t find anything. If such a parser exists, we didn’t discover it. We needed a CSS parser to convert a CSS string to a data structure so we could easily find the corresponding styles.

The Solution: A Simple Pattern for Parsing CSS

We started with a simple regular expression:

([\\s\\S]*?){([\\s\\S]*?)}

This translates into

([\\s\\S]*?) => any string as selector
{ => then an opening bracket
([\\s\\S]*?) => any string as CSS rules
} => then a closing bracket

We ran the above pattern continuously over the CSS string. It worked like a charm. We easily parsed the CSS string into an array of objects. For example:

.someClass {
margin : 20px;
}

would be parsed into:

[
{
“selector” : “.someClass”,
“rules” : [
{
“directive” : “margin”,
“value” : “20px”
}
]
}
]

This is a very convenient form of CSS for making adjustments to it. For example, it’s easy to find the styles affecting a given element.

Not So Fast!

Once we saw that this working well, we thought the roads were all clear ahead. But then something happened, that occurs far to frequently when developing a new feature. We discovered an unanticipated scenario that completely invalidated our simple solution. We had to go back to the drawing board.

CSS does not solely consist of selectors followed by rule declarations enclosed with curly braces. A co-worker pointed out that our CSS parser was breaking if the CSS contained media queries.

What is a Media Query?

In simple terms, a media query is just another type of CSS code. It tests a condition, and if the test passes, the enclosed CSS styles are applied. For example a common test is for the width of a browser window. This is frequently used to make web designs look good across devices and screens of all shapes and sizes. We needed our parser to support them.

Here is an example media query:

@media (max-width: 600px) {
.facet_sidebar {
display: none;
}
}

Media queries seemed easy to parse at first, but trying to parse them using regular expressions was hard. We updated our regular expression to this:

((\\s*?@media[\\s\\S]*?){([\\s\\S]*?)}\\s*?})|(([\\s\\S]*?){([\\s\\S]*?)})

Another Hard Lesson Learned: Thou Shalt Not Forget to Write Unit Tests

I saw how quickly the CSS parser was becoming complex. I felt helpless knowing even smallest change could break things in remote parts of the project. So I started to write unit tests. These entailed parsing CSS strings with a broad range of features including @media queries, @font-face rules, and @keyframe directives.

The result? Unit tests saved us countless hours of testing and debugging. Upon writing unit tests, I immediately noticed and fixed bugs in the CSS parser or in logic operations. With them in place, the development became a piece of cake. No matter how complex the CSS parsing code became, I could continue to refactor it and improve the code with confidence.

Finally, Out of the Woods

After much effort, we successfully completed the CSS inspector. You can now click an element in your form, and it displays the selector code in the editor. Once you change the CSS code, it’ s parsed and the updated version of the form styling is displayed.

We accomplished our goal of creating a CSS editing experience similar to Chrome or Firefox dev tools, and are very proud of it. Try out the Form Designer to see it yourself!

form design with css editor
People are creating stunning designs with the Jotform CSS Editor!

P.S. We open sourced the CSS parsing utility library under the MIT license: css.js. We hope it will save developers time, and that they will use in their own projects. Feel free to fork it, comment, or send pull requests.

AUTHOR

Send Comment:

Jotform Avatar
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Podo Comment Be the first to comment.