|
| 1 | +# CSS Naming Convention |
| 2 | + |
| 3 | + |
| 4 | +This is Atom's naming convention for creating UI in Atom and Atom packages. It's close to [BEM/SUIT](https://github.com/suitcss/suit/blob/master/doc/naming-conventions.md), but slightly customized for Atom's use case. |
| 5 | + |
| 6 | + |
| 7 | +## Example |
| 8 | + |
| 9 | +Below the commit box as a possible example: |
| 10 | + |
| 11 | +```html |
| 12 | +<div class='gitub-CommitBox'> |
| 13 | + <div class='gitub-CommitBox-editor'></div> |
| 14 | + <footer class='gitub-CommitBox-footer'> |
| 15 | + <button class='gitub-CommitBox-button'>Commit to sm-branch</button> |
| 16 | + <div class='gitub-CommitBox-counter is-warning'>50</div> |
| 17 | + </footer> |
| 18 | +</div> |
| 19 | +``` |
| 20 | + |
| 21 | +And when styled in Less: |
| 22 | + |
| 23 | +```less |
| 24 | +.github { |
| 25 | + &-CommitBox { |
| 26 | + |
| 27 | + &-editor {} |
| 28 | + |
| 29 | + &-footer {} |
| 30 | + |
| 31 | + &-button {} |
| 32 | + |
| 33 | + &-counter { |
| 34 | + background: red; |
| 35 | + |
| 36 | + &.is-warning { |
| 37 | + color: black; |
| 38 | + } |
| 39 | + } |
| 40 | + } |
| 41 | +} |
| 42 | +``` |
| 43 | + |
| 44 | +## Breakdown |
| 45 | + |
| 46 | +Here another example: |
| 47 | + |
| 48 | +```html |
| 49 | +<button class=' |
| 50 | + github-CommitBox-commitButton |
| 51 | + github-CommitBox-commitButton--primary |
| 52 | + is-disabled |
| 53 | +'> |
| 54 | +``` |
| 55 | + |
| 56 | +And now let's break it down into all the different parts. |
| 57 | + |
| 58 | +```html |
| 59 | +<button class=' |
| 60 | + namespace-ComponentName-childElement |
| 61 | + namespace-ComponentName-childElement--modifier |
| 62 | + is-state |
| 63 | +'> |
| 64 | +``` |
| 65 | + |
| 66 | + |
| 67 | +### Namespace |
| 68 | + |
| 69 | +`github`-CommitBox |
| 70 | + |
| 71 | +Every class starts with a namespace, in Atom's case it's the __package name__. Since packages are unique (well, at least for all the packages published on atom.io), it avoids style conflicts. Using a namespace like this makes sure that no styles __leak out__. And even more importantly that no styles __leak in__. |
| 72 | + |
| 73 | +The namespace for Atom core ([atom/atom](https://github.com/atom/atom-ui)) is `core`-ComponentName. |
| 74 | + |
| 75 | +Atom's [UI library](https://github.com/atom/atom-ui) is the only exception that doesn't use a namespace. All components start with the `ComponentName`. For example `Button`, `Checkbox`. |
| 76 | + |
| 77 | +> Note: If multiple words are needed, camelCase is used: `myPackage`-Component. |
| 78 | +
|
| 79 | + |
| 80 | +### Component |
| 81 | + |
| 82 | +github-`CommitBox` |
| 83 | + |
| 84 | +Components are building blocks of a package. They can be small or large. Components can also contain other components. It's more about seeing what belongs together. |
| 85 | + |
| 86 | +Components can also share the same elements. A pattern often found is that a new Component starts where a childElement ends. |
| 87 | + |
| 88 | +```html |
| 89 | +<ul class="github-List"> |
| 90 | + <li class="github-List-item github-Commit"> |
| 91 | + <label class="github-Commit-message"></label> |
| 92 | + <span class="github-Commit-time"></span> |
| 93 | + </li> |
| 94 | +</ul> |
| 95 | +``` |
| 96 | + |
| 97 | +In this example, `github-List-item` is responsible for the "container" and layout styles. `github-Commit` is responsible for the "content" inside. |
| 98 | + |
| 99 | +> Note: Components use PascalCase. This makes it easy to spot them in the markup. For example in `settings-List-item`, it's easy to see that the component is `List` and not `settings` or `item`. |
| 100 | +
|
| 101 | + |
| 102 | +### Child element |
| 103 | + |
| 104 | +github-CommitBox-`commitButton` |
| 105 | + |
| 106 | +Elements that are part of a component are appended to the component's class name with a single dash (`-`). |
| 107 | + |
| 108 | +> Note: If multiple words are needed, camelCase is used: github-CommitBox`-commitButton`. |
| 109 | +
|
| 110 | + |
| 111 | +### Modifier |
| 112 | + |
| 113 | +github-CommitBox-commitButton`--primary` |
| 114 | + |
| 115 | +Modifiers are used if a component is very similar to the default component but varies slightly. Like has a different color. Modifiers use a double dash `--` to distinguish them from components and child elements. |
| 116 | + |
| 117 | +> Note: If multiple words are needed, camelCase is used: github-CommitBox-commitButton`--primaryColor`. |
| 118 | +
|
| 119 | + |
| 120 | +### States |
| 121 | + |
| 122 | +github-CommitBox-commitButton `is-disabled` |
| 123 | + |
| 124 | +States are prefixed with a short verb, like `is-` or `has-`. Since these class names probably get used in many different places, it should never be styled stand-alone and always be a chained selector. |
| 125 | + |
| 126 | +```less |
| 127 | +.is-disabled { |
| 128 | + // nope |
| 129 | +} |
| 130 | +.github-CommitBox-commitButton.is-disabled { |
| 131 | + // yep |
| 132 | +} |
| 133 | +``` |
| 134 | + |
| 135 | +> Note: If multiple words are needed, camelCase is used: `has-collapsedItems`. |
| 136 | +
|
| 137 | + |
| 138 | + |
| 139 | +## More guidelines |
| 140 | + |
| 141 | +- Styling elements (like `div`) should be avoided. This makes it easier to switch elements, like from a `<button>` to `<a>`. |
| 142 | +- No utility classes. Themes and user styles can only override CSS but not change the markup. Therefore having utility classes doesn't make as much sense once you override them. |
| 143 | +- Avoid using existing CSS classes to reference elements in the DOM. That way when the markup changes, functionality and specs will less likely break. Instead use `ref` attributes (`ref="commitButton"`). |
| 144 | +- Avoid changing modifiers at runtime. If you're in need, consider turning the modifier class into a state. For example if you often want to switch a default button to a primary button, change the `github-CommitBox-commitButton--primary` modifier class into a `is-primary` state instead. Since state classes are decoupled from components, it's easier to reuse that state class even if the component changes later. |
| 145 | + |
| 146 | + |
| 147 | +## Benefits |
| 148 | + |
| 149 | +- Just by looking at a class in the DevTools you already get a lot of information about where the source can be found (what package, what component). What relationship each element has (parent/child). What class names are states and might be changed/removed. There should be less "what does this class do" moments. |
| 150 | +- Reduces specificity. Mostly there is just a single class. Two when using states. This reduces the specificity war when trying to override styles in packages and `styles.less`. |
| 151 | +- Using a single class makes it easier to change the markup later. Once a selector like `.class > div > .class` is in the wild, removing the `div` later would break the styling. |
| 152 | +- Easier to refactor/move code around because you can see what class belongs to what component. |
| 153 | + |
| 154 | + |
| 155 | +## Concerns |
| 156 | + |
| 157 | +### Class names get quite long |
| 158 | + |
| 159 | +Only in the DOM. During authoring in Less class names can be split into different parts and glued together with `&`. |
| 160 | + |
| 161 | +```less |
| 162 | +.github { |
| 163 | + &-CommitBox { |
| 164 | + // styles |
| 165 | + &-editor { |
| 166 | + // styles |
| 167 | + } |
| 168 | + } |
| 169 | +} |
| 170 | +``` |
| 171 | + |
| 172 | +will output as |
| 173 | + |
| 174 | +```less |
| 175 | +.github-CommitBox { |
| 176 | + // styles |
| 177 | +} |
| 178 | +.github-CommitBox-editor { |
| 179 | + // styles |
| 180 | +} |
| 181 | +``` |
| 182 | + |
| 183 | +Child elements might also be styled as components. Especially in smaller packages or when components should be shared inside a package. For example `github-CommitBox-commitButton` could just be `github-Button` if that button doesn't need any special styles even tough it's part of the the `CommitBox` component. |
| 184 | + |
| 185 | +### I don't like nesting selectors |
| 186 | + |
| 187 | +The whole selector can of course also be written without nesting. One benefit for not nesting selectors is that they can be easier searched for. |
| 188 | + |
| 189 | +```less |
| 190 | +.github-CommitBox { /* styles */ } |
| 191 | + |
| 192 | +.github-CommitBox-editor { /* styles */ } |
| 193 | + |
| 194 | +.github-CommitBox-footer { /* styles */ } |
| 195 | +``` |
0 commit comments