├── images ├── layouts.png ├── component-example.png ├── component-nesting.png ├── component-elements.png └── component-modifiers.png ├── sketch └── illustrations.sketch ├── History.md └── Readme.md /images/layouts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/rscss/master/images/layouts.png -------------------------------------------------------------------------------- /images/component-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/rscss/master/images/component-example.png -------------------------------------------------------------------------------- /images/component-nesting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/rscss/master/images/component-nesting.png -------------------------------------------------------------------------------- /sketch/illustrations.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/rscss/master/sketch/illustrations.sketch -------------------------------------------------------------------------------- /images/component-elements.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/rscss/master/images/component-elements.png -------------------------------------------------------------------------------- /images/component-modifiers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/rscss/master/images/component-modifiers.png -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | ## v1.1.0 - 2015-02-10 2 | 3 | Child selectors are now the preferred convention for styling elements. (#2) 4 | 5 | ## v1.0.0 - 2015-01-30 6 | 7 | Initial version. 8 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | RSCSS 2 | ===== 3 | 4 | **Reasonable Standard* for CSS Stylesheet Structure.** 5 | 6 | :construction: This document is a work in progress. See the [changelog](History.md) for summaries of revisions. 7 | 8 | (`*`: or **S** can also stand for "suggestions") 9 | 10 |
11 | 12 | Problem 13 | ------- 14 | 15 | Any CSS greater than 1000 lines will get unwieldy. You'll eventually run into these common pitfalls: 16 | 17 | * "What does this class mean?" 18 | * "Is this class still being used?" 19 | * "If I make a new class `green`, will there be a clash?" 20 | 21 |
22 | 23 | Structure 24 | --------- 25 | 26 | ### Think in components 27 | 28 | ![](images/component-example.png) 29 | 30 | Think of each piece of your UI is an individual "component." Components will be named with **at least two words**, separated by a dash. Examples of a component: 31 | 32 | * A like button (`.like-button`) 33 | * A search form (`.search-form`) 34 | * A news article card (`.article-card`) 35 | 36 | ### Elements 37 | 38 | ![](images/component-elements.png) 39 | 40 | **Naming:** Each component may have elements. They should have classes that are only **one word**. 41 | 42 | ```scss 43 | .search-form { 44 | > .field { /* ... */ } 45 | > .action { /* ... */ } 46 | } 47 | ``` 48 | 49 | **Selectors:** Prefer to use the `>` child selector whenever possible. This prevents bleeding through nested components, and performs better than descendant selectors. 50 | 51 | ```scss 52 | .article-card { 53 | .title { /* okay */ } 54 | > .author { /* ✓ better */ } 55 | } 56 | ``` 57 | 58 | **On multiple words:** For those that need two or more words, concatenate them without dashes or underscores. 59 | 60 | ```scss 61 | .profile-box { 62 | > .firstname { /* ... */ } 63 | > .lastname { /* ... */ } 64 | > .avatar { /* ... */ } 65 | } 66 | ``` 67 | 68 | **Avoid tag selectors:** use classnames whenever possible. Tag selectors are fine, but they may come at a small performance penalty and may not be as descriptive. 69 | 70 | ```scss 71 | .article-card { 72 | > h3 { /* ... */ } 73 | > .name { /* ✓ better */ } 74 | } 75 | ``` 76 | 77 | ### Variants 78 | 79 | ![](images/component-modifiers.png) 80 | 81 | Components may have variants. Their classes will be prefixed by a dash (`-`). 82 | 83 | ```scss 84 | .like-button { 85 | &.-wide { /* ... */ } 86 | &.-short { /* ... */ } 87 | &.-disabled { /* ... */ } 88 | } 89 | ``` 90 | 91 | Elements may also have variants. 92 | 93 | ```scss 94 | .shopping-card { 95 | > .title { /* ... */ } 96 | > .title.-small { /* ... */ } 97 | } 98 | ``` 99 | 100 | Why a dash? Because: 101 | 102 | * it prevents ambiguity with elements 103 | * a CSS class can only start with a letter, `_` or `-` 104 | * dashes are easier to type than underscores 105 | * it kind of resembles switches in UNIX commands (`gcc -O2 -Wall -emit-last`) 106 | 107 | ### Nested components 108 | 109 | ![](images/component-nesting.png) 110 | 111 | Sometimes it's necessary to nest components. 112 | 113 | ```html 114 |
115 |
116 | ... 117 |
118 |

...

119 |

...

120 |
121 | ``` 122 | 123 | ### Simplifying nested components 124 | 125 | Sometimes, when nesting components, your markup can get dirty: 126 | 127 | ```html 128 |
129 | 130 | 131 |
132 | ``` 133 | 134 | You can simplify this by using your CSS preprocessor's `@extend` mechanism: 135 | 136 | ```html 137 |
138 | 139 | 140 |
141 | ``` 142 | 143 | ```scss 144 | // sass 145 | .search-form { 146 | > .submit { 147 | @extend .search-button; 148 | @extend .search-button.-red; 149 | @extend .search-button.-large; 150 | } 151 | } 152 | ``` 153 | 154 | ### Layout 155 | 156 | ![](images/layouts.png) 157 | 158 | **Avoid positioning properties:** Components should be made in a way that they're reusable in different contexts. Avoid putting these properties in components: 159 | 160 | * Positioning (`position`, `top`, `left`, `right`, `bottom`) 161 | * Floats (`float`, `clear`) 162 | * Margins (`margin`) 163 | * Dimensions (`width`, `height`) * 164 | 165 | **Fixed dimensions:** Exception to these would be elements that have fixed width/heights, such as avatars and logos. 166 | 167 | **Define positioning in parents:** If you need to define these, try to define them in whatever context whey will be in. In this example below, notice that the widths and floats are applied on the *list* component, not the component itself. 168 | 169 | ```css 170 | .article-list { 171 | & { 172 | @include clearfix; 173 | } 174 | 175 | > .article-card { 176 | width: 33.3%; 177 | float: left; 178 | } 179 | } 180 | 181 | .article-card { 182 | & { /* ... */ } 183 | > .image { /* ... */ } 184 | > .title { /* ... */ } 185 | > .category { /* ... */ } 186 | } 187 | ``` 188 | 189 |
190 | 191 | CSS structure 192 | ------------- 193 | 194 | ### One component per file 195 | 196 | ```scss 197 | /* css/components/search-form.scss */ 198 | .search-form { 199 | > .button { /* ... */ } 200 | > .field { /* ... */ } 201 | > .label { /* ... */ } 202 | 203 | // variants 204 | &.-small { /* ... */ } 205 | &.-wide { /* ... */ } 206 | } 207 | ``` 208 | 209 | In sass-rails and stylus, this makes including all of them easy: 210 | 211 | ```scss 212 | @import 'components/*'; 213 | ``` 214 | 215 | ### Avoid over-nesting 216 | 217 | Use no more than 1 level of nesting. It's easy to get lost with too much nesting. 218 | 219 | ```scss 220 | /* bad */ 221 | .image-frame { 222 | > .description { 223 | /* ... */ 224 | 225 | > .icon { 226 | /* ... */ 227 | } 228 | } 229 | } 230 | ``` 231 | 232 | Consider instead: 233 | 234 | ```scss 235 | .image-frame { 236 | > .description { /* ... */ } 237 | > .description > .icon { /* ... */ } 238 | } 239 | ``` 240 | 241 |
242 | 243 | Pitfalls 244 | -------- 245 | 246 | ### Bleeding through nested components 247 | 248 | Be careful about nested components where the nested component has an element of the same name. 249 | 250 | ```html 251 |
252 |
253 | 254 | 255 | 4 256 |
257 | 258 |

Article title

259 |

3 votes

260 |
261 | ``` 262 | 263 | ```scss 264 | .article-link { 265 | > .title { /* ... */ } 266 | > .count { /* ... (!!!) */ } 267 | } 268 | 269 | .vote-button { 270 | > .up { /* ... */ } 271 | > .down { /* ... */ } 272 | > .count { /* ... */ } 273 | } 274 | ``` 275 | 276 | In this case, if `.article-link > .count` did not have the `>` (child) selector, it will also apply to the `.vote-button .count` element. This is one of the reasons why child selectors are preferred. 277 | 278 |
279 | 280 | But... 281 | ------ 282 | 283 | Some people may have apprehensions to these convention, such as: 284 | 285 | ### But dashes suck 286 | 287 | You're free to omit it and just use regular words, but keep the rest of the ideas in place (components, elements, variants). 288 | 289 | ### But I can't think of 2 words 290 | 291 | Some components will only need one word to express their purpose, such as `alert`. In these cases, consider that using some suffixes will make it clearer that it's a block-level element: 292 | 293 | * `.alert-box` 294 | * `.alert-card` 295 | * `.alert-block` 296 | 297 | Or for inlines: 298 | 299 | * `.link-button` 300 | * `.link-span` 301 | 302 |
303 | 304 | Other solutions 305 | --------------- 306 | 307 | ### BEM 308 | 309 | [BEM] in nice, but some may be irked at its unconventional syntax. RSCSS pretty much follows BEM conventions, only with a different syntax. 310 | 311 | ```html 312 | 313 | 317 | ``` 318 | 319 | ```html 320 | 321 | 325 | ``` 326 | 327 | ### Terminologies 328 | 329 | The same concepts exist in similar ways in other CSS structuring ideologies. 330 | 331 | | RSCSS | BEM | SMACSS | 332 | | --- | --- | --- | 333 | | Component | Block | Module | 334 | | Element | Element | ? | 335 | | Layout | ? | Layout | 336 | | Variant | Modifier | Theme & State | 337 | 338 |
339 | 340 | Summary 341 | ------- 342 | 343 | * Think in **components**, named with 2 words (`.screenshot-image`) 344 | * Components have **elements**, named with 1 word (`.blog-post .title`) 345 | * Name **variants** with a dash prefix (`.shop-banner.-with-icon`) 346 | * Components can nest 347 | * Remember you can extend to make things simple 348 | 349 | [Smacss]: https://smacss.com/ 350 | [BEM]: http://bem.info/ 351 | 352 | [1]: https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Writing_efficient_CSS#Avoid_the_descendant_selector.21 353 | --------------------------------------------------------------------------------