You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Aug 8, 2023. It is now read-only.
*[Us versus Them](#us-versus-them-aka-theres-an-x-ception-to-every-rule)
15
16
*[When to use our selector naming scheme](#when-to-use-our-selector-naming-scheme)
@@ -20,14 +21,15 @@
20
21
## Basic Conventions
21
22
22
23
* 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)
24
26
25
27
26
28
## CSM
27
29
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.
29
31
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.
31
33
32
34
```html
33
35
<divclass="c-blog">
@@ -43,23 +45,23 @@ Our convention (which we call CSM or Component, Sub-Component, Modifier) uses [B
43
45
44
46
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.
45
47
46
-
`.c-blog` This is a component. It describes a highlevel 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.
47
49
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.
49
51
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.
51
53
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.
53
55
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.
55
57
56
58
### Components
57
59
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.
59
61
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
63
65
64
66
```scss
65
67
.c-blog-post {
@@ -68,14 +70,13 @@ The highest level of a module — it should describe an independent module that
68
70
69
71
### Sub-components
70
72
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.
72
74
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.
74
76
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
79
80
80
81
```scss
81
82
// Good!
@@ -84,20 +85,29 @@ Like components these should always live at the root level of a file. Do not nes
84
85
85
86
// Bad!
86
87
//
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
88
90
.c-blog-post {
89
91
.c-blog-post__title {
90
92
}
91
93
}
94
+
95
+
// Bad!
96
+
.c-blog-post__title__emote {
97
+
}
98
+
99
+
// Good!
100
+
.c-blog-post__emote {
101
+
}
92
102
```
93
103
94
104
### Modifiers
95
105
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.
97
107
98
108
* Prefixed with the namespace of the affected element and two dashes (`c--`, `t--`)
99
109
* 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.
101
111
* Never declared as a stand-alone rule.
102
112
103
113
```scss
@@ -109,6 +119,13 @@ These are used to modify components or subcomponents. They are always chained to
109
119
}
110
120
}
111
121
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
+
112
129
// Bad!
113
130
//
114
131
// 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
117
134
}
118
135
```
119
136
120
-
### Component modifiers that affect subcomponents
137
+
### Component modifiers that affect sub-components
121
138
122
139
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.
123
140
@@ -264,41 +281,99 @@ An exception is the use of ARIA roles for styling state. Where an ARIA role maps
264
281
265
282
You'll have probably noticed by now that our class names have a variety of prefixes. If not, I will describe their usages now:
266
283
267
-
Prefix | Purpose | Scaffold Directory |
284
+
Prefix | Purpose | Location |
268
285
------ | ------- | ------------------ |
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* |
273
291
`.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*
274
292
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.
275
294
276
-
## Us versus Them (aka There's an x-ception to every rule)
277
295
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
279
297
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:
281
299
282
-
### When to use our selector naming scheme
300
+
> **Note:** the examples in this section will use React JSX syntax for sake of brevity.
283
301
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
288
362
289
363
### When to use their existing selectors
290
364
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.
294
369
295
370
### How to use their existing selectors in our components
296
371
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.
298
373
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.
300
375
301
-
Always wrap the module with our naming scheme
376
+
Always component classes should always be structured with our naming conventions.
302
377
303
378
```scss
304
379
// Do
@@ -315,7 +390,7 @@ Always wrap the module with our naming scheme
315
390
}
316
391
```
317
392
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.
319
394
320
395
Constantly evaluate your nesting in situation like this.
321
396
@@ -341,7 +416,7 @@ Constantly evaluate your nesting in situation like this.
341
416
}
342
417
343
418
344
-
//Don't
419
+
//Bad!
345
420
.c-blog-post {
346
421
.content {
347
422
.image {
@@ -350,7 +425,7 @@ Constantly evaluate your nesting in situation like this.
350
425
}
351
426
```
352
427
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.
354
429
355
430
```scss
356
431
// Okay
@@ -379,6 +454,4 @@ Use their modifiers the same way you would use our modifiers. Chain it to the co
379
454
}
380
455
```
381
456
382
-
> If they use their modifiers in weird or unexpected ways, consider using the konf or templating to add our modifier classes instead.
383
-
384
457
Continue on to [Block Comment Documentation Guide →](../localization-and-theming-best-practices/readme.md)
0 commit comments