Enforcing a Consistent CSS Property Order with Stylelint
As developers, we have many tools to ensure our code is valid, properly formatted, and consistently written. However, the order in which things are declared is often overlooked.
For example, you can declare all your variables at the top of your JavaScript/CSS files, or scatter them between other code. While both approaches might work, having a consistent structure across your files significantly improves readability and maintainability.
The same principle applies to CSS. By enforcing a specific order for CSS property declarations within a selector, you always know where to find a specific property. This consistency makes your code easier to read and maintain.
This can be done with Stylelint. It can enforce the property order and automatically fix this order for you.
Why Does Order Matter?
Let’s take a look at an example.
Before
.some-element {
background-color: var(--primary-color);
top: 0;
position: absolute;
width: var(--toggle-size);
transform: scale(1.29) translateX(0%);
left: 0;
height: var(--toggle-size);
border-radius: 50px;
content: "";
transition: transform $ease-in-out $pace-quick, background-color $pace-page-transition ease-in-out;
@include high-contrast {
border: 2px solid var(--black);
box-shadow: 0 0 0 1px var(--white);
}
}
After
.some-element {
content: "";
position: absolute;
top: 0;
left: 0;
width: var(--toggle-size);
height: var(--toggle-size);
background-color: var(--primary-color);
border-radius: 50px;
transform: scale(1.29) translateX(0%);
transition: transform $ease-in-out $pace-quick, background-color $pace-page-transition ease-in-out;
@include high-contrast {
border: 2px solid var(--black);
box-shadow: 0 0 0 1px var(--white);
}
}
Adding Whitespace for Clarity
Personally, I also prefer adding whitespace between logical groups of properties:
.some-element {
content: "";
position: absolute;
top: 0;
left: 0;
width: var(--toggle-size);
height: var(--toggle-size);
background-color: var(--primary-color);
border-radius: 50px;
transform: scale(1.29) translateX(0%);
transition: transform $ease-in-out $pace-quick, background-color $pace-page-transition ease-in-out;
@include high-contrast {
border: 2px solid var(--black);
box-shadow: 0 0 0 1px var(--white);
}
}
What do you think of the difference? The second example is much easier to read, right? It easier to find the property you want to change.
Imagine the CSS within every selector is always in the same structure and is grouped logically. Sounds good?
The Benefits for Teams
While enforcing a standard for yourself is useful, the real value shines when applied to a team or a large codebase.
- Every developer adheres to the same structure.
- Consistency improves throughout the codebase.
- Code reviews become faster since reviewers don’t need to focus on the readabillity of the order.
Getting Started with Stylelint
Let’s set it up!
1. Install Dependencies
Install the following dependencies:
- stylelint:
npm install stylelint --save-dev
- stylelint-order:
npm install stylelint-order --save-dev
- stylelint-scss (if you use
SCSS):
npm install stylelint-scss --save-dev
2. Create a Stylelint Configuration
Create a .stylelintrc.js
file and add your settings.
3. Define the Property Order
Within the rules
property, define an "order/order"
property that
expects an array. You can declare your own order or use one of the existing examples.
There are examples that sort properties alphabetically (blegh), by type, etc. But, after a lot of research, none of these examples worked for us (the company I used to work for before). Therefore, we setup our own and shared it with the world to use as a new default.
The order is based on the impact the property can have. So, the most impactful properties are at the top. Just above that, are the mixins, so you can always overwrite them.
When looking at properties that contain a long and shorthand option, we have put the shorthand at the top. So for `margin`, the list is:
- margin
- margin-block
- margin-block-start
- margin-block-end
- margin-inline
- margin-inline-start
- margin-inline-end
- margin-top
- margin-right
- margin-bottom
- margin-left
This order ensures you can always overwrite the shorthand.
Automating the Fix
1. Add an Autofix Command
Add this command to your package.json
. You can use it in your pre-commit
hooks, CI etc.
"scripts": {
"lint:css": "stylelint '**/*.scss' --fix"
}
2. Enable Editor Fixes on Save
If you use VS Code, you can configure it to fix the property order automatically when a
file is saved. Add the following to your settings.json
:
{
"editor.codeActionsOnSave": {
"source.fixAll.stylelint": true
},
"stylelint.validate": ["css", "scss", "less"],
"stylelint.autoFixOnSave": true
}