Skip to content
This repository was archived by the owner on Aug 8, 2023. It is now read-only.

Commit b506c43

Browse files
authored
Merge pull request #98 from mobify/jeffkamo-patch-class-naming-conventions
[WIP] Update class naming conventions
2 parents 11f5366 + 2ca52c4 commit b506c43

File tree

1 file changed

+120
-47
lines changed

1 file changed

+120
-47
lines changed

css/class-naming-conventions/readme.md

Lines changed: 120 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
* [Components](#components)
99
* [Sub-Components](#sub-components)
1010
* [Modifiers](#modifiers)
11-
* [Component modifiers that affect subcomponents](#component-modifiers-that-affect-subcomponents)
11+
* [Component modifiers that affect sub-components](#component-modifiers-that-affect-sub-components)
1212
* [State](#state)
13+
* [Components That Style Components](#components-that-style-components)
1314
* [Class Prefix Conventions](#class-prefix-conventions)
1415
* [Us versus Them](#us-versus-them-aka-theres-an-x-ception-to-every-rule)
1516
* [When to use our selector naming scheme](#when-to-use-our-selector-naming-scheme)
@@ -20,14 +21,15 @@
2021
## Basic Conventions
2122

2223
* Class names are kebab-case (*words-are-dash-separated*)
23-
* Each class is prefixed with either `c-`, `t-` or `x-` ([consult this table](#class-prefix-conventions) for details)
24+
* Subclasses are indicated with double underscore, such as `root-name__sub-component-name`
25+
* Each class is prefixed with either `c-`, `t-` or `u-` ([consult this table](#class-prefix-conventions) for details and other rarer prefixes)
2426

2527

2628
## CSM
2729

28-
Our convention (which we call CSM or Component, Sub-Component, Modifier) uses [BEM principles](http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/) to denote types of classes while still maintaining full use of the cascade.
30+
Our CSS class naming convention (which we call CSM or Component, Sub-Component, Modifier) uses [BEM principles](http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/) to denote types of classes while still maintaining full use of the cascade.
2931

30-
> BEM stands for Block, Element, Modifier. Because Block and Element already have meaning in CSS, we use the terms Component and Subcomponent instead.
32+
> BEM stands for Block, Element, Modifier. Because Block and Element already have meaning in CSS, we use the terms Component and Sub-Component instead.
3133
3234
```html
3335
<div class="c-blog">
@@ -43,23 +45,23 @@ Our convention (which we call CSM or Component, Sub-Component, Modifier) uses [B
4345

4446
This example may seem confusing at first but if we break down each of the selectors that we have, it begins to make more sense.
4547

46-
`.c-blog` This is a component. It describes a high level module or component. In this instance, it describes the container for all of our blog posts.
48+
`.c-blog` This is a high-level component. In this example, it describes a wrapper that may contain blog content.
4749

48-
`.c-blog__title` This is a sub-component. It's always a child of a module or component. In this instance, it is a title for our blog post container
50+
`.c-blog__title` This is a sub-component. In this example, it is a title for a blog.
4951

50-
`.c-blog-post` This is another component. This one describes a specific blog post. We make this its own component because a blog post is not necessarily a child of the blog container. It can and should be able to live independently.
52+
`.c-blog-post` This is another high-level component. In this example, it describes the blog post itself. Notice that it is its own component instead of a sub-component of `c-blog` because a blog post does not need to be child of the blog container. This way the component is able to live anywhere.
5153

52-
`.c--featured` This is a modifier. It is always chained to a component or sub-component. In this instance, it describes a different way of displaying a component.
54+
`c-blog-post.c--featured` This is a modifier. Notice that the `c--featured` class is paired with the component or sub-component it belongs to. In this example, it describes a different way of displaying the `c-blog-post` component.
5355

54-
`.c-blog-post__time` Like before, this is another sub-component. This time it belongs to the c-blog-post. It's still a subcomponent even though it is not a direct child of the component.
56+
`.c-blog-post__time` Like before, this is another sub-component this time belonging to the `c-blog-post` component. It is still a sub-component even though it is not a **direct** child of the component. In other words, sub-components are not required to be direct children of its parent component.
5557

5658
### Components
5759

58-
The highest level of a module — it should describe an independent module that you are creating. Components should be able to exist on their own or within other components. They should always live at the root level of a file.
60+
Components are independent and self-contained units of UI. Styles belonging to a component should only affect the component itself, and any of its sub-components. They should not affect anything external to them, or any other components that might be nested within them.
5961

60-
* Prefixed with our component namespace `c`.
61-
* Hyphenated naming.
62-
* Not nested.
62+
* Prefixed with our component namespace `c-`
63+
* Kebab-cased
64+
* Not nested, these classes should be declared at the root level of the file
6365

6466
```scss
6567
.c-blog-post {
@@ -68,14 +70,13 @@ The highest level of a module — it should describe an independent module that
6870

6971
### Sub-components
7072

71-
This is a secondary element inside of a component. It is always written as a chain of its parent component to avoid any inheritance issues. Your subcomponents should be named in a way that keeps them from having to have subcomponents of their own. If you find you need to write a subcomponent for a subcomponent, consider breaking the parent out into its own component.
73+
Sub-components are elements that are child to its parent component. The classname should be formatted as such: `c-[parent-component-name]__[sub-component-name]`. Sub-components do not, and should not, have sub-components of their own. If you find you need to write a sub-sub-component, instead just treat it as a sub-component – sub-components are only ever child to the parent component.
7274

73-
Like components these should always live at the root level of a file. Do not nest these within the parent component or another subcomponent. The class name should do all the work necessary.
75+
Like components, these should always live at the root level of a file. Avoid nesting these within the parent component or another sub-component.
7476

75-
* Prefixed by the parent component and two underscores `c-component-name__`.
76-
* Live below the parent component in the root of the file. Not nested.
77-
* Are declared in the order they appear.
78-
* Subcomponents do not have to be direct children of the component in the markup. They can be any descendent.
77+
* Prefixed by the parent component and two underscores `c-[component-name]__[sub-component-name]`
78+
* Lives below the parent component in the root of the file, un-nested
79+
* Subcomponents do not have to be direct children of the component in the markup
7980

8081
```scss
8182
// Good!
@@ -84,20 +85,29 @@ Like components these should always live at the root level of a file. Do not nes
8485

8586
// Bad!
8687
//
87-
// Note how .c-blog-post__title is nested inside it's parent class
88+
// Note how .c-blog-post__title is nested inside it's parent class? It should
89+
// not be nested, instead it should live at the root level of the file
8890
.c-blog-post {
8991
.c-blog-post__title {
9092
}
9193
}
94+
95+
// Bad!
96+
.c-blog-post__title__emote {
97+
}
98+
99+
// Good!
100+
.c-blog-post__emote {
101+
}
92102
```
93103

94104
### Modifiers
95105

96-
These are used to modify components or subcomponents. They are always chained to a specific component and are declared in the component or subcomponent that they affect.
106+
Modifiers, as their name suggests, modify components or sub-components. They are always chained to the component or sub-component they belong to.
97107

98108
* Prefixed with the namespace of the affected element and two dashes (`c--`, `t--`)
99109
* Contained to the scope of a single component
100-
* Always declared as a chained selector to a component or subcomponent.
110+
* Always declared as a chained selector to a component or sub-component.
101111
* Never declared as a stand-alone rule.
102112

103113
```scss
@@ -109,6 +119,13 @@ These are used to modify components or subcomponents. They are always chained to
109119
}
110120
}
111121

122+
// Also Good!
123+
//
124+
// Use your discretion and decide for yourself whether this option, or the above
125+
// option makes most sense. See below for more some common scenarios.
126+
.c-blog-post.c--featured {
127+
}
128+
112129
// Bad!
113130
//
114131
// Note how .c--featured is a selector all by itself? That's bad! It
@@ -117,7 +134,7 @@ These are used to modify components or subcomponents. They are always chained to
117134
}
118135
```
119136

120-
### Component modifiers that affect subcomponents
137+
### Component modifiers that affect sub-components
121138

122139
Sometimes a component modifier will affect its sub-components. There are several methods you can use to accomplish this. As much as possible, stick to one method in your project.
123140

@@ -264,41 +281,99 @@ An exception is the use of ARIA roles for styling state. Where an ARIA role maps
264281

265282
You'll have probably noticed by now that our class names have a variety of prefixes. If not, I will describe their usages now:
266283

267-
Prefix | Purpose | Scaffold Directory |
284+
Prefix | Purpose | Location |
268285
------ | ------- | ------------------ |
269-
`.c-` | Classes that start with `.c-` are one of the three possible Component classes: `Component Class` (typically the class that defines the component itself), `Sub-Component Class`, `Modifier Class`. [See above](#component-oriented-naming) | */src/scss/components* |
270-
`.t-` | Classes that start with `.t-` are Template specific classes. These class names are declared as the `template` in the corresponding [view](https://mobify.atlassian.net/wiki/display/PLAT/Views). Example template classes include: `.t-pdp`, `.t-home`, `.t-category`. | */src/scss/templates*
271-
`.x-` | Classes that start with `x-` are considered global states or document states. That means these classes should only be applied to the `html` or `body` element. Example states include `x-ios`, `x-portrait`, `x-retina`, `x-header-is-sticky`, etc. | */src/scss/globals/*
272-
`.m-` | **Deprecated** This class prefix is currently reserved for Mobify Modules. However, eventually we intend to deprecate this prefix entirely. At that time, our Mobify Modules will instead be prefixed by their module name. | */src/scss/components/vendor*
286+
`.c-` | Component classes: this includes the root component (typically the class that defines the component itself), sub-component class, and the modifier class. [See above](#component-oriented-naming) | Project's component directory |
287+
`.t-` | Template classes: These class names are declared as the `template` in the corresponding [view](https://mobify.atlassian.net/wiki/display/PLAT/Views). Example template classes include: `.t-pdp`, `.t-home`, `.t-category`. | Project's template directory |
288+
`.u-` | Utility classes: these are meant as one-off, strongly opinionated, high specificity overrides for very narrowly defined styles. | Project's `/styles/utilities` directory |
289+
`.x-` | Classes that start with `x-` are considered global states or document states. That means these classes should only be applied to the `html` or `body` element. Example states include `x-ios`, `x-portrait`, `x-retina`, `x-header-is-sticky`, etc. | *varies* |
290+
`.m-` (*) | Desktop embedded mobile markup classes: these are classes that we will use if we author Markup that is intended for clients to embed onto their desktop pages, but is for mobile content. | *n/a* |
273291
`.js-` | Javascript classes are used exclusively by scripts and should never have CSS styles applied to them. Repeat: **Do NOT** style Javascript classes. | *n/a*
274292

293+
> \* The `m-` class prefix has an old, deprecated use: Mobify Modules. However, Mobify Modules have been replaced with third part plugins, and are treated as third party libraries with their own conventions.
275294
276-
## Us versus Them (aka There's an x-ception to every rule)
277295

278-
It's important to remember that we don't write our own markup. We write a bastardized version of existing markup. In many cases, we're simply adding wrappers or class names to markup that already exists. Rarely, we'll completely re-template something.
296+
## Components That Style Components
279297

280-
Knowing that, how do we make the decision to use our class names or their class names in our styling and how does that affect the way we write our CSS? If we're using their class names, we obviously can't follow the CEM/BEM syntax laid out above. We've laid out some situational advice below on when to use their class names and when to use ours. We also talk about ways to adjust the code style laid out above when using their class names.
298+
Sometimes there are situations when a component makes use of other components, and in so doing needs to style them for within its context. Let's take a simple example of a button and icon component being tightly coupled in this manner:
281299

282-
### When to use our selector naming scheme
300+
> **Note:** the examples in this section will use React JSX syntax for sake of brevity.
283301
284-
* Whenever you're writing your own markup in a template.
285-
* Whenever you're remixing or adding markup through the konf.
286-
* Whenever you're adding classes to existing markup.
287-
* Whenever you find yourself using @extend.
302+
```jsx
303+
<button className="c-button">
304+
<Icon name={icon} />
305+
{children}
306+
</button>
307+
```
308+
309+
In situations like this it is tempting to just style the icon's class inside of the button. However, this practice is poor and creates tight coupling between the Button and Icon components that shouldn't exist. As a rule of thumb, a component should only know about what it's responsible for; it should be unaware of anything external to itself. Continuing with this example, the Icon is an external component, therefore the Button component should be completely unaware there there is even such thing as icon classes, like `c-icon`.
310+
311+
The solution to this challenge is to instead give the external component a new class that our new component can know about, like `c-button__icon`. By doing it in this way the external Icon component is, for all intents and purposes, being treated as a sub-component of the Button component. This method also has the benefit of being free of any (tight) coupling between the components. Both components can change, be added or removed, without really effecting the other in an unpredictable way.
312+
313+
So, to summarize...
314+
315+
```jsx
316+
/* Bad! */
317+
<button className="c-button">
318+
<Icon name={icon} />
319+
{children}
320+
</button>
321+
```
322+
323+
```scss
324+
// Bad!
325+
.c-button .c-icon {
326+
// ...
327+
}
328+
```
329+
330+
### Good Practice
331+
332+
```jsx
333+
/* Good! */
334+
<button className="c-button">
335+
<Icon className="c-button__icon" name={icon} />
336+
{children}
337+
</button>
338+
```
339+
340+
```scss
341+
// Good!
342+
.c-button__icon {
343+
// ...
344+
}
345+
```
346+
347+
348+
## Parsing vs. Decorating
349+
350+
It's important to understand that we have a few different ways of authoring our CSS, and the way we do this is depends a lot on how we convert the desktop markup for mobile. Ideally, we parse the desktop markup and take full control of the final HTML. However, this isn't always possible, and sometimes we just output the desktop markup as is: untouched, or perhaps partially wrapped in order to control the appearance entirely through CSS.
351+
352+
If you find yourself wondering "should I be adding a new class, or should I use the classes from desktop?" consider the following: If we're using their class names, we obviously can't follow our CSM syntax. But that said, sometimes we just have no choice; perhaps there are engineering requirements that force us to retain the markup structure. Under such circumstances, we must stick to the desktop classes.
353+
354+
Below is laid out some situational advice that should clarify when to use desktop classes and when to author our own. We also talk about ways to adjust the code style when using their class names.
355+
356+
### When to use our class naming convention
357+
358+
* When writing your own markup in a template
359+
* When decorating (adding, moving, or wrapping) markup in a View, Parser, Decorator or UI-Script
360+
* When adding custom classes to existing markup
361+
* When you find yourself using @extend
288362

289363
### When to use their existing selectors
290364

291-
* Whenever possible — when you're not required to do any of the things above. It's faster and easier to use their markup than it is to add our own.
292-
* When their markup allows for it. For example, if they don't use classes or they don't use them with any consistency, it doesn't make sense to use their selectors.
293-
* When their markup isn't easily changed. AJAXed content or content added after a page is loaded is an example of this.
365+
* When it's fastest, easiest or most efficient to use their markup than it is to add our own.
366+
* When their markup is too inconsistent, or makes parsing too difficult.
367+
* When mobile functionality is tightly coupled to desktop's markup structure.
368+
* When intercepting AJAXed content or content added after a page is too costly, unperformant, or inefficent.
294369

295370
### How to use their existing selectors in our components
296371

297-
This is a list of rules to use when you're using their selectors within our modules section.
372+
This is a list of rules to use when you're mixing desktop selectors with our selectors.
298373

299-
> Remember, it's okay to mix our selector naming scheme with their selector naming scheme. If you have to add a class to a subcomponent, use our subcomponent naming scheme and place it in the standard spot in the file.
374+
> Remember, it's okay to mix our class naming convention with the desktop selectors. If you have to add a class to a sub-component, use our sub-component naming scheme and place it in the standard spot in the file.
300375
301-
Always wrap the module with our naming scheme
376+
Always component classes should always be structured with our naming conventions.
302377

303378
```scss
304379
// Do
@@ -315,7 +390,7 @@ Always wrap the module with our naming scheme
315390
}
316391
```
317392

318-
Subcomponents can be directly inside their parent component, but adding your own classes should be your FIRST approach so as to avoid nesting.
393+
Desktop classes can be added inside their parent component, but adding our own classes should be your FIRST approach so as to avoid nesting.
319394

320395
Constantly evaluate your nesting in situation like this.
321396

@@ -341,7 +416,7 @@ Constantly evaluate your nesting in situation like this.
341416
}
342417

343418

344-
// Don't
419+
// Bad!
345420
.c-blog-post {
346421
.content {
347422
.image {
@@ -350,7 +425,7 @@ Constantly evaluate your nesting in situation like this.
350425
}
351426
```
352427

353-
Use their modifiers the same way you would use our modifiers. Chain it to the component or subcomponent it directly affects.
428+
Use their modifiers the same way you would use our modifiers. Chain it to the component or sub-component it directly affects.
354429

355430
```scss
356431
// Okay
@@ -379,6 +454,4 @@ Use their modifiers the same way you would use our modifiers. Chain it to the co
379454
}
380455
```
381456

382-
> If they use their modifiers in weird or unexpected ways, consider using the konf or templating to add our modifier classes instead.
383-
384457
Continue on to [Block Comment Documentation Guide →](../localization-and-theming-best-practices/readme.md)

0 commit comments

Comments
 (0)