Hello!
I am working on the front-end of a huge project - Yandex search results. And we, like any other large web project, have a huge amount of css-code and a rather big team that interacts with it.
When many people write and edit css using different tools, over time this css can turn out to be very confusing, inconsistent and generally begins to look bad. For example, it is more convenient for someone to write vendor prefixes in the same order, for someone in another, someone puts quotes around the url, someone does not, and someone fixes an urgent bug to release could, for example,
position: relative
at the beginning of the property block, without noticing that somewhere between
color
and
box-shadow
, is already
position: absolute
, and wondering for a long time why nothing works.
')

But despite the fact that everyone writes code differently, we have an ideal order in the repository: the css-code is completely consistent and looks great. The whole.
As we have achieved, you can read under the cut.
The first steps
If we want the entire css to be written on a code style, then the first obvious thought is for some top boss to say: “You need to write this and that, follow it,” and catch inconsistencies with the review code. It sounds cool, but, unfortunately, it only sounds, but in practice it turns out so-so:
- We are all human beings - and it is a little difficult for a person to remember the exact-recommended-order of the whole heap of css properties, and never make mistakes in it.
- The revision code in this case turns into a set of code style revisions, but I would like it to discuss logic and architecture.
- All errors in this place need to be corrected by hand, and all inconsistencies clarified in some dock.
In general, it looks somehow not very good, it takes a lot of time and, most importantly, it is very frustrating for developers.
To make the developers happy, I had to look for some other solution, and it was found.
Little about robots
There was one old robot -
CSScomb , which solved the most important part of our task:
he could sort properties in a given order. But he had several drawbacks:
- In addition, he could not do anything, and in fact he really wanted both quotes where there was no need to remove, and build a vendor prefix with a ladder ...
- It was written in PHP and regexp, and also did not provide for expansion.
And although, of course, PHP in the js-programmers environment is a little more famous than c ++, it’s still not quite what you want.
Mishanga from our team, looked at the whole thing and decided to make a tool that would be deprived of these shortcomings: he knew a lot of different things, would be written in js, and could easily be expanded. And although Yandex employees are actively involved in the development, CSScomb.js is a full-fledged open source project that has long gone beyond Yandex.
Meet
CSScomb.js - this is a new version of the old CSScomb, which can do a lot of cool things.
What does this look like?
Consider the current development process by example. For example, for educational purposes only, we want to commit such code:
.block { -webkit-box-shadow: 0 0 0 1px rgba(0, 0, 0, .1); -moz-box-shadow: 0 0 0 1px rgba(0, 0, 0, .1); box-shadow: 0 0 0 1px rgba(0, 0, 0, .1); z-index: 2; position: absolute; height: 2px; width: 2px; color: #FFFFFF; }
It does not look very good, and not at all on the code type, and therefore when trying to commit, we will see this:
% git commit block.css -m"Add My awesome css" Code style errors found. ! block.css
Committing such a css-file will not succeed. This happens because in our repository in the git there is a precommitte hook that checks with CSScomb all changes in the css-files that we want to commit. It works in linter mode. The hook is pretty smart, so it only checks what we are going to commit, and not everything.
Having seen such a message, we are not upset, but simply ask CSScomb.js to fix everything:
% csscomb block.css
Here, now another thing:
.block { position: absolute; z-index: 2; width: 2px; height: 2px; color: #fff; -webkit-box-shadow: 0 0 0 1px rgba(0, 0, 0, .1); -moz-box-shadow: 0 0 0 1px rgba(0, 0, 0, .1); box-shadow: 0 0 0 1px rgba(0, 0, 0, .1); }
He did quite a lot of routine minor edits for us in the code: he moved the bracket to another line, translated the color to lower case, built the vendor prefixes in the ladder, and the properties in the correct order. Now such a code will successfully pass an automatic check and will be taken on a further review of its already functional qualities.
Thus, the developer no longer needs to think about how to correctly write css by code type, he simply writes as he likes, and the rest is done automatically. This is exactly what we wanted to achieve.
And inside her neonka
Such a system consists of two parts - the CSScomb itself and the precommit hook that uses it. I will tell you about the hook in the next section, and in this section I will focus on how CSSComb.js works.
CSScomb.js is based on two things: the plug-in system and the
gonzales-pe css-parser is a very cool thing that can work not only with pure css, but also with preprocessors like Sass or LESS.
Let's start with the parser. It is set on the css-code and builds on its basis AST. For example, for:
.block { position: absolute }
AST will look like this:
[ "stylesheet", [ "ruleset", [ "selector", [ "simpleselector", [ "class", [ "ident", "block" ] ], [ "s", "\n" ] ] ], [ "block", [ "s", "\n " ], [ "declaration", [ "property", [ "ident", "position" ] ], [ "propertyDelim" ], [ "value", [ "s", " " ], [ "ident", "absolute" ] ] ], [ "s", "\n" ] ] ], [ "s", "\n" ] ]
This format is very bulky and inconvenient for people to read, but it is very convenient for automatic processing, which
plugins do . It is they who are involved in all further css conversions, and the plugins work not directly with css-code, but with AST, which is much easier to handle. What plugins to use, as well as their settings are specified in a separate configuration file.
In the example above, we did not put a semicolon after
absolute
. The plugin that is responsible for detecting and correcting semicolons is noticed and corrected through an AST modification (I cut down the tree a bit so as not to duplicate a large piece of code):
... [ "block", [ "s", "\n " ], [ "declaration", [ "property", [ "ident", "position" ] ], [ "propertyDelim" ], [ "value", [ "s", " " ], [ "ident", "absolute" ] ] ], >>>[ "declDelim" ],<<< [ "s", "\n" ] ...
After all the plugins have worked, using the same gonzales-pe AST turns back into css code,
and the forgotten semicolon is in its place:
.block { position: absolute; }
How to start using it?
Step one
It is necessary in one way or another to add CSScomb.js depending on your project.
If the project uses npm, you need to add it to devDependencies in package.json
{ ... "devDependencies": { ... "csscomb": "2.0.4", ... } ... }
Step Two
In order for the plugins to bring the code to the form we need, you need to put the
file with the configuration of the plugins in the root of the project. Details on what each plugin does and what options it has can be read
here .
CSScomb.js can do this to some extent automatically, because it can generate a config, based on some existing css-ku.
csscomb -d example.css > .csscomb.json
This way all plugins can be configured. The only exception is the sorting of properties, which you still have to write yourself, or copy from somewhere else with your hands.
Last step
You need to make CSScomb.js in linter mode run before a commit, along with jscs / jshint-groups or other tools that usually run before a commit. In the case of git and linux / BSD, it might look something like this:
This hook has an interesting feature. It would seem, why not run CSSComb.js immediately in repair mode and then automatically silently commit? In most cases, this really works fine, but problems arise in a situation where we make several edits in the file, and we want only one of them (
git add -p
). In this case, if we find an error in the version of the file that you commit, unpleasant situations begin:
- We can run CSScomb.js on the version of the file we are going to commit, and in some situations get conflicts when applying the patch.
- Either run CSScomb.js on the current file entirely, but edits that we don’t want to commit can be anything, including the wrong code.
On the whole, this is not very pleasant when the file suddenly changes by itself. Therefore, we came to the conclusion that CSScomb.js should be run by the developer.
Done!
Everything. Now CSScomb.js will not commit the code not by a code type, and it gives an opportunity to bring the code to the desired form in one command.
So simple in general, an idea and an uncomplicated tool help keep the code in order, and also save time and developer nerves.
Such a bundle can be used in many projects, and if you are missing some basic functionality or plug-ins, then you can always start an issue or
fix the necessary things yourself.