CSS is a language that is employed by almost every developer for some purpose. Moreover, it is the language where typically it's taken for granted. It’s powerful and has several nuances that may facilitate (or damage) your theme styles.
The readability of your CSS is incredibly important, though most people overlook why it's important. Great readable CSS makes it much easier to expand and maintain it in the future.
There are several good styling conventions that may help you keep your styles organized and in good shape, each with its strengths and weaknesses depending on the project scale. For the theme-boilerplate in particular, we have choose to use a modular approach.
SCSS Folder Structure
Base
Styles defining the scaffold of the theme. You can use this folder to import fonts, define typography, mixins, utility functions.
Components
Components are self contained pieces of UI. They can be very small, like a breadcrumb or a button. They can also be complex and composed of other components like the Advanced Search. Each component must have a unique class. They should also get a SASS partial with the same name.
Variables specific to a component should be defined on the top of the component’s .scss
file with a proper default and should only be used for that component.
Sections
Sections are present in almost every page. For example the main header is considered to be a section. Variables to be used in a section should be on the _variables.scss
file since those variables may be inherited by a component.
Styles on this folder can overwrite components.
Pages
Styles inside this folder should only be effective on a particular page. For example, you may want to add different styles specific to the profile page. In this case, you create a file _profile.scss
and start your SCSS like this:
.Section-Profile {
...your styles here...
}
This way, styles described in the file above will only affect the layout in the profile page.
Styles in this folder can overwrite components and sections.
Naming Convention and Good Practices
CSS classes should follow a similar naming convention as its variables. This allows for quick and easy search and replace, also makes it easy to know where it’s supposed to be used.
Classes are in camel case. This allows you to keep your classes "flat" in your stylesheet. The names are also unique and avoid conflicts with other elements.
If you feel like you need another "level", then you should make another block. Example:
blockA-subElement-subElement
should be refactored to be blockB-subElement
.
Be descriptive
Good classes won't be ambiguous as to where they are used. For example, using "user" is too vague. There will definitely be many references to users elsewhere in the application. .discussion-author
would be a much more descriptive name.
Dont' style on base elements
The only places where we should be styling on base elements without a class are:
- Nested basic HTML elements in user content
- In a reset/scaffolding stylesheet
You may need to target a specific style on a type of element, but try to avoid this as much as possible.
Nesting
Even though it's quite easy to nest selectors in CSS, it's to be avoided. It's only appropriate if the style of an element is different based on its context. If you feel the need to nest, most of the time it really means you're missing a class.
Example of good nesting: .mobileNav.isOpen .morePanel
This makes sense, we're changing the styles of the panel when the menu is open.
Bad example of nesting: .someModule > ul > li > a
The lower the specificity the better (i.e. just ONE class) to target an element.
The "&"
Don't use "&" for making new class names. It makes the styles look like they're nested, but they're not.
Example we DON'T want:
.classA {
color: blue;
&-subElement {
color: pink;
}
}
At a quick glance, it seems like the sub element is nested into classA
, but it's not. It's generating this:
.classA {
color: blue;
}
.classA-subElement {
color: pink;
}
The above code would be the proper way to write it. You are repeating some text, but it's much clearer to the reader. We want to maintain "flat" stylesheets as much as possible (excluding cases where nesting changes the style). It also makes it much easier to search for class names in the project.
You can use &
but reserve it for separate classes:
.classA {
color: blue;
&.isActive {
color: pink;
}
+ .classB {
background: orange;
}
}
States
States start with "is" or "has" and should never be styled alone. Example, the .advancedSearch
block will get the .isOpen
class when it's open. You can then style the open advanced search with .advancedSearch.isOpen
. This makes for easy to read class names that are descriptive.
Groups of elements
Whenever you have an element that contains a list or a group of elements, the wrapper should be plural and the elements inside should use the same name, but singular. Example: for meta data, we have metas
as the wrapper and meta
for a single element. They both are defined in _metas.scss
.
User Content
User content will not have classes, since it comes from an editor. The contents of user content need to be wrapped in a .userContent
or .UserContent
CSS class with styles on base elements inside.