├── LICENSE.md └── README.md /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Dropbox, Inc 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dropbox (S)CSS Style Guide 2 | 3 | > “Every line of code should appear to be written by a single person, no matter the number of contributors.” —@mdo 4 | 5 | ## General 6 | ### Don’ts 7 | 8 | - Avoid using HTML tags in CSS selectors 9 | - E.g. Prefer `.o-modal {}` over `div.o-modal {}` 10 | - Always prefer using a class over HTML tags (with some exceptions like CSS resets) 11 | - Don't use ids in selectors 12 | - `#header` is overly specific compared to, for example `.header` and is much harder to override 13 | - Read more about the headaches associated with IDs in CSS [here](http://csswizardry.com/2011/09/when-using-ids-can-be-a-pain-in-the-class/). 14 | - Don’t nest more than 3 levels deep 15 | - Nesting selectors increases specificity, meaning that overriding any CSS set therein needs to be targeted with an even more specific selector. This quickly becomes a significant maintenance issue. 16 | - Avoid using nesting for anything other than pseudo selectors and state selectors. 17 | - E.g. nesting `:hover`, `:focus`, `::before`, etc. is OK, but nesting selectors inside selectors should be avoided. 18 | - Don't `!important` 19 | - Ever. 20 | - If you must, leave a comment, and prioritise resolving specificity issues before resorting to `!important`. 21 | - `!important` greatly increases the power of a CSS declaration, making it extremely tough to override in the future. It’s only possible to override with another `!important` declaration later in the cascade. 22 | - Don’t use `margin-top`. 23 | - Vertical margins [collapse](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Mastering_margin_collapsing). Always prefer `padding-top` or`margin-bottom` on preceding elements 24 | - Avoid shorthand properties (unless you really need them) 25 | - It can be tempting to use, for instance, `background: #fff` instead of `background-color: #fff`, but doing so overrides other values encapsulated by the shorthand property. (In this case, `background-image` and its associative properties are set to “none.” 26 | - This applies to all properties with a shorthand: border, margin, padding, font, etc. 27 | 28 | ### Spacing 29 | 30 | - Four spaces for indenting code 31 | - Put spaces after `:` in property declarations 32 | - E.g. `color: red;` instead of `color:red;` 33 | - Put spaces before `{` in rule declarations 34 | - E.g. `.o-modal {` instead of `.o-modal{` 35 | - Write your CSS one line per property 36 | - Add a line break after `}` closing rule declarations 37 | - When grouping selectors, keep individual selectors on a single line 38 | - Place closing braces `}` on a new line 39 | - Add a new line at the end of .scss files 40 | - Trim excess whitespace 41 | 42 | ### Formatting 43 | 44 | - All selectors are lower case, hyphen separated aka “spinal case” eg. `.my-class-name` 45 | - Always prefer Sass’s double-slash `//` commenting, even for block comments 46 | - Avoid specifying units for zero values, e.g. `margin: 0;` instead of `margin: 0px;` 47 | - Always add a semicolon to the end of a property/value declaration 48 | - Use leading zeros for decimal values `opacity: 0.4;` instead of `opacity: .4;` 49 | - Put spaces before and after child selector `div > span` instead of `div>span` 50 | 51 | ---------- 52 | 53 | ## Sass Specifics 54 | ### Internal order of a .scss file 55 | 56 | 1. Imports 57 | 2. Variables 58 | 3. Base Styles 59 | 4. Experiment Styles 60 | 61 | Example: 62 | 63 | ```scss 64 | //------------------------------ 65 | // Modal 66 | //------------------------------ 67 | 68 | @import "../constants"; 69 | @import "../helpers"; 70 | 71 | $DBmodal-namespace: "c-modal" !default; 72 | $DBmodal-padding: 32px; 73 | 74 | $DBmodal-background: #fff !default; 75 | $DBmodal-background-alt: color(gray, x-light) !default; 76 | 77 | .o-modal { ... } 78 | 79 | // Many lines later... 80 | 81 | // EXPERIMENT: experiment-rule-name 82 | .o-modal--experiment { ... } 83 | // END EXPERIMENT: experiment-rule-name 84 | ``` 85 | 86 | ### Variables 87 | 88 | - Define all variables at the top of the file after the imports 89 | - Namespace local variables with the filename (SASS has no doc level scope) 90 | - eg `business_contact.scss` →`$business_contact_font_size: 14px;` 91 | - Local variables should be `$snake_lowercase` 92 | - Global constants should be `$SNAKE_ALL_CAPS` 93 | 94 | ### Color 95 | 96 | - Use the defined color constants via the color function 97 | - Lowercase all hex values `#fffff` 98 | - Limit alpha values to a maximum of two decimal places. Always use a leading zero. 99 | 100 | Example: 101 | 102 | ```scss 103 | // Bad 104 | .c-link { 105 | color: #007ee5; 106 | border-color: #FFF; 107 | background-color: rgba(#FFF, .0625); 108 | } 109 | 110 | // Good 111 | .c-link { 112 | color: color(blue); 113 | border-color: #ffffff; 114 | background-color: rgba(#ffffff, 0.1); 115 | } 116 | ``` 117 | 118 | ### Experiments 119 | 120 | Wrap experiment styles with comments: 121 | 122 | ```scss 123 | // EXPERIMENT: experiment-rule-name 124 | .stuff { ... } 125 | // END EXPERIMENT: experiment-rule-name 126 | ``` 127 | 128 | ---------- 129 | 130 | ## Rule Ordering 131 | 132 | Properties and nested declarations should appear in the following order, with line breaks between groups: 133 | 134 | 1. Any `@` rules 135 | 2. Layout and box-model properties 136 | - margin, padding, box-sizing, overflow, position, display, width/height, etc. 137 | 3. Typographic properties 138 | - E.g. font-*, line-height, letter-spacing, text-*, etc. 139 | 4. Stylistic properties 140 | - color, background-*, animation, border, etc. 141 | 5. UI properties 142 | - appearance, cursor, user-select, pointer-events, etc. 143 | 6. Pseudo-elements 144 | - ::after, ::before, ::selection, etc. 145 | 7. Pseudo-selectors 146 | - :hover, :focus, :active, etc. 147 | 8. Modifier classes 148 | 9. Nested elements 149 | 150 | Here’s a comprehensive example: 151 | 152 | ```scss 153 | .c-btn { 154 | @extend %link--plain; 155 | 156 | display: inline-block; 157 | padding: 6px 12px; 158 | 159 | text-align: center; 160 | font-weight: 600; 161 | 162 | background-color: color(blue); 163 | border-radius: 3px; 164 | color: white; 165 | 166 | &::before { 167 | content: ''; 168 | } 169 | 170 | &:focus, &:hover { 171 | box-shadow: 0 0 0 1px color(blue, .3); 172 | } 173 | 174 | &--big { 175 | padding: 12px 24px; 176 | } 177 | 178 | > .c-icon { 179 | margin-right: 6px; 180 | } 181 | } 182 | ``` 183 | 184 | ---------- 185 | 186 | ## Nesting 187 | 188 | - As a general rule of thumb, avoid nesting selectors more than 3 levels deep 189 | - Prefer using nesting as a convenience to extend the parent selector over targeting nested elements. For example: 190 | ```scss 191 | .block { 192 | padding: 24px; 193 | 194 | &--mini { 195 | padding: 12px; 196 | } 197 | } 198 | ``` 199 | 200 | Nesting can be really easily avoided by smart class naming (with the help of BEM) and avoiding bare tag selectors. 201 | 202 | ---------- 203 | 204 | ## BEM 205 | 206 | Block: Unique, meaningful names for a logical unit of style. Avoid excessive shorthand. 207 | - Good: `.alert-box` or `.recents-intro` or `.button` 208 | - Bad: `.feature` or `.content` or `.btn` 209 | 210 | Element: styles that only apply to children of a block. Elements can also be blocks themselves. Class name is a concatenation of the block name, two underscores and the element name. Examples: 211 | - `.alert-box__close` 212 | - `.expanding-section__section` 213 | 214 | Modifier: override or extend the base styles of a block or element with modifier styles. Class name is a concatenation of the block (or element) name, two hyphens and the modifier name. Examples: 215 | - `.alert-box--success` 216 | - `.expanding-section--expanded` 217 | 218 | ### BEM Best practices 219 | 220 | Don't `@extend` block modifiers with the block base. 221 | - Good: `
` 222 | - Bad: `
` 223 | 224 | Don't create elements inside elements. If you find yourself needing this, consider converting your element into a block. 225 | - Bad: `.alert-box__close__button` 226 | 227 | Choose your modifiers wisely. These two rules have very different meaning: 228 | 229 | ```scss 230 | .block--modifier .block__element { color: red; } 231 | .block__element--modifier { color: red; } 232 | ``` 233 | 234 | ---------- 235 | 236 | ## Selector Naming 237 | 238 | - Try to use [BEM-based](http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/) naming for your class selectors 239 | - When using modifier classes, always require the base/unmodified class is present 240 | - Use Sass’s nesting to manage BEM selectors like so: 241 | ```scss 242 | .block { 243 | &--modifier { // compiles to .block--modifier 244 | text-align: center; 245 | } 246 | 247 | &__element { // compiles to .block__element 248 | color: red; 249 | 250 | &--modifier { // compiles to .block__element--modifier 251 | color: blue; 252 | } 253 | } 254 | } 255 | ``` 256 | 257 | ---------- 258 | 259 | ## Namespaced Classes 260 | 261 | There are a few reserved namespaces for classes to provide common and globally-available abstractions. 262 | 263 | - `.o-` for CSS objects. Objects are usually common design patterns (like the Flag object). Modifying these classes could have severe knock-on effects. 264 | - `.c-` for CSS components. Components are designed pieces of UI—think buttons, inputs, modals, and banners. 265 | - `.u-` for helpers and utilities. Utility classes are usually single-purpose and have high priority. Things like floating elements, trimming margins, etc. 266 | - `.is-, .has-` for stateful classes, a la [SMACSS](https://smacss.com/book/type-state). Use these classes for temporary, optional, or short-lived states and styles. 267 | - `._` for hacks. Classes with a hack namespace should be used when you need to force a style with `!important` or increasing specificity, should be temporary, and should not be bound onto. 268 | - `.t-` for theme classes. Pages with unique styles or overrides for any objects or components should make use of theme classes. 269 | 270 | ---------- 271 | 272 | ## Separation of Concerns (One Thing Well™) 273 | 274 | You should always try to spot common code—padding, font sizes, layout patterns—and abstract them to reusable, namespaced classes that can be chained to elements and have a single responsibility. Doing so helps prevent overrides and duplicated rules, and encourages a separation of concerns. 275 | 276 | ```scss 277 | // Bad code 278 | // HTML: 279 | // 280 | .modal { 281 | padding: 32px; 282 | background-color: color(gray, x-light); 283 | 284 | &.compact { 285 | padding: 24px; 286 | } 287 | } 288 | 289 | // Good code 290 | // HTML: 291 | //
...
292 | //
...
293 | 294 | // components/_modal.scss 295 | .c-modal { 296 | background-color: color(gray, x-light); 297 | } 298 | 299 | // helpers/_layout.scss 300 | .u-l-island { 301 | padding: 32px; 302 | } 303 | 304 | .u-l-isle { 305 | padding: 24px; 306 | } 307 | ``` 308 | 309 | ---------- 310 | 311 | ## Media Queries 312 | 313 | Media queries should be within the CSS selector as per SMACSS 314 | 315 | ```scss 316 | .selector { 317 | float: left; 318 | 319 | @media only screen and (max-width: 767px) { 320 | float: none; 321 | } 322 | } 323 | ``` 324 | 325 | Create variables for frequently used breakpoints 326 | 327 | ```scss 328 | $SCREEN_SM_MAX: "max-width: 767px"; 329 | 330 | .selector { 331 | float: left; 332 | 333 | @media only screen and ($SCREEN_SM_MAX) { 334 | float: none; 335 | } 336 | } 337 | ``` 338 | --------------------------------------------------------------------------------