├── .github └── PULL_REQUEST_TEMPLATE.md ├── .scss-lint.yml ├── Gemfile ├── README.md └── _example.scss /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## What? 2 | ... 3 | 4 | ## Why? 5 | ... 6 | 7 | ## Testing / Proof 8 | ... 9 | 10 | @bigcommerce/frontend 11 | -------------------------------------------------------------------------------- /.scss-lint.yml: -------------------------------------------------------------------------------- 1 | # BC configuration 2 | linters: 3 | 4 | #Cos we use maps with keywords, this produces noise 5 | ColorKeyword: 6 | enabled: false 7 | 8 | ElsePlacement: 9 | enabled: true 10 | style: new_line # or 'same_line' 11 | 12 | EmptyLineBetweenBlocks: 13 | enabled: true 14 | ignore_single_line_blocks: false 15 | 16 | Indentation: 17 | enabled: true 18 | character: space # or 'tab' 19 | width: 4 20 | 21 | LeadingZero: 22 | enabled: true 23 | style: include_zero # or 'exclude_zero' 24 | 25 | NameFormat: 26 | enabled: false 27 | convention: hyphenated_lowercase # or 'BEM', or a regex pattern 28 | 29 | SelectorDepth: 30 | enabled: true 31 | max_depth: 2 32 | 33 | NestingDepth: 34 | enabled: true 35 | max_depth: 2 36 | 37 | # For example 38 | # http://www.regexr.com/39qql 39 | SelectorFormat: 40 | enabled: true 41 | # convention: camel_case # or 'snake_case', or 'hyphenated_lowercase', or a regex pattern 42 | convention: ^[a-z][a-z0-9]*([A-Z0-9][a-z0-9]*)*((\.is-|-+)[a-z0-9][a-z0-9]*([A-Z0-9][a-z0-9]*)*)*$ 43 | 44 | StringQuotes: 45 | enabled: true 46 | style: double_quotes # or single_quotes 47 | 48 | TrailingZero: 49 | enabled: true 50 | 51 | # This is a new linting rule as of 0.30 and the per-file disablement syntax seems to failing, so turn it off 52 | QualifyingElement: 53 | enabled: false 54 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'sass', '3.4.7' 4 | gem 'scss-lint', '~> 0.31.0' 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sass Coding Guidelines 2 | 3 | Bigcommerce uses [Sass](http://sass-lang.com/) for style generation. 4 | 5 | Bigcommerce's naming conventions are heavily influenced by the SUIT CSS framework 6 | and align closely to [Medium](https://medium.com/@fat/mediums-css-is-actually-pretty-fucking-good-b8e2a6c78b06)'s 7 | thoughts on CSS. Which is to say, it relies on _structured class names_ and 8 | _meaningful hyphens_ (i.e., not using hyphens merely to separate words). This 9 | helps to work around the current limits of applying CSS to the DOM (i.e., the 10 | lack of style encapsulation), and to better communicate the relationships between 11 | classes. 12 | 13 | 14 | **Table of contents** 15 | 16 | * [General Principles](#principles) 17 | * [Specificity](#specificity) 18 | * [Performance](#performance) 19 | * [Formatting](#formatting) 20 | * [Indentation](#indentation) 21 | * [Commenting](#commenting) 22 | * [Spacing](#spacing) 23 | * [Quotes](#quotes) 24 | * [Value Declaration](#value-declaration) 25 | * [Declaration Order](#declaration-order) 26 | * [Pseudo Elements and Classes](#pseudo) 27 | * [Units](#units) 28 | * [Nesting](#nesting) 29 | * [@extend or @inlcude](#extendorinclude) 30 | * [Components](#components) 31 | * [componentName](#componentName) 32 | * [componentName--modifierName](#componentName--modifierName) 33 | * [componentName-descendantName](#componentName-descendantName) 34 | * [componentName.is-stateOfComponent](#is-stateOfComponent) 35 | * [Utilities](#utilities) 36 | * [u-utilityName](#u-utilityName) 37 | * [Variables and Mixins](#variables-and-mixins) 38 | * [Variables](#variables) 39 | * [Component / Micro app variables](#component-variables) 40 | * [Maps](#variable-maps) 41 | * [colors](#colors) 42 | * [z-index](#zindex) 43 | * [font-weight](#fontweight) 44 | * [line-height](#lineheight) 45 | * [Animations](#animations) 46 | * [Mixins](#mixins) 47 | * [Polyfills](#polyfills) 48 | * [JavaScript](#javascript) 49 | * [Folder Structure](#folders) 50 | 51 | 52 | 53 | 54 | ## General Principles 55 | Strictly adhere to the agreed-upon style guide listed below. The general 56 | principle is to develop DRY (Don't Repeat Yourself) SCSS, built around reusable 57 | components and patterns. 58 | 59 | * All code should look like a single person has typed it. 60 | * Don't try to prematurely optimize your code; keep it readable and understandable. 61 | * When building a component, always start by looking at existing patterns. 62 | * Break down complex components until they are made up of simple components. 63 | * Save your complex components as patterns so they can be easily reused. 64 | * Build your component as a mixin which outputs _optional_ css. 65 | 66 | 67 | 68 | ## Specificity 69 | 70 | On large code bases, it's preferable and a tonne more maintainable if the 71 | specificity of selectors are all as equal and as low as humanly possible. 72 | 73 | 74 | > **Do:** 75 | > Use classes in your SCSS for styling. 76 | 77 | ```css 78 | .component { 79 | ... 80 | } 81 | ``` 82 | 83 | 84 | > **Don't:** 85 | > Use ID's for styling. There is literally no point in using them. 86 | 87 | ```css 88 | #component { 89 | ... 90 | } 91 | ``` 92 | 93 | 94 | > **Do:** 95 | > Style the base elements (such as typography elements). 96 | 97 | ```css 98 | h1 { 99 | ... 100 | } 101 | ``` 102 | 103 | > **Don't:** 104 | > Reference or style descendent elements in your class selectors. 105 | 106 | ```css 107 | .component h1 { 108 | ... 109 | } 110 | ``` 111 | 112 | 113 | > **Don't:** 114 | > Use overqualified selectors in your CSS. Do not prepend a class or ID with an element. 115 | 116 | ```css 117 | div.container { 118 | ... 119 | } 120 | ``` 121 | 122 | 123 | #### Performance 124 | Overly specific selectors can also cause performance issues. Consider: 125 | 126 | ```css 127 | ul.user-list li span a:hover { 128 | color: red; 129 | } 130 | ``` 131 | 132 | Selectors are resolved right to left, exiting when it has been detected the 133 | selector does not match. This requires a lot of DOM walking and for large 134 | documents can cause a significant increase in the layout time. For further 135 | reading checkout: https://developers.google.com/speed/docs/best-practices/rendering#UseEfficientCSSSelectors 136 | 137 | If we know we want to give all `a` elements inside the `.user-list` red on 138 | hover we can simplify this style to: 139 | 140 | ```css 141 | .user-list-link:hover { 142 | color: red; 143 | } 144 | ``` 145 | 146 | 147 | 148 | ## Formatting 149 | 150 | The following are some high level page formatting style rules. 151 | 152 | * Remove all trailing white-space from your file, Sublime Text can even do this upon saving. 153 | * Tip: set your editor to show white-space. 154 | * Leave one clear line at the bottom of your file. 155 | 156 | 157 | #### Indentation 158 | 159 | * Don't mix spaces with tabs for indentation. 160 | * Use a soft-tab of 4 spaces. 161 | * Use white-space to improve readability. 162 | * Feel free to use indentation to show hierarchy. 163 | 164 | > **Do:** 165 | 166 | ```css 167 | .component { 168 | ... 169 | } 170 | 171 | .component-child { 172 | ... 173 | } 174 | 175 | .component-childSecond { 176 | ... 177 | } 178 | ``` 179 | 180 | 181 | #### Commenting 182 | * Separate your code into logical sections using standard comment blocks. 183 | * Leave one clear line under your section comments. 184 | * Leave two clear lines above comment blocks. 185 | * Annotate your code inside a comment block, leaving a reference # next to the line. 186 | 187 | > **Do:** 188 | > Comment your code 189 | > No really, comment your code 190 | 191 | ```css 192 | // ============================================================================= 193 | // FILE TITLE / SECTION TITLE 194 | // ============================================================================= 195 | 196 | 197 | // Comment Block / Sub-section 198 | // ----------------------------------------------------------------------------- 199 | // 200 | // Purpose: This will describe when this component should be used. This comment 201 | // block is 80 chars long 202 | // 203 | // 1. Mark lines of code with numbers which are explained here. 204 | // This keeps your code clean, while also allowing detailed comments. 205 | // 206 | // ----------------------------------------------------------------------------- 207 | 208 | .component { 209 | ... // 1 210 | } 211 | 212 | ``` 213 | 214 | 215 | #### Spacing 216 | 217 | * CSS rules should be comma separated but live on new lines. 218 | * Include a single space before the opening brace of a rule-set. 219 | * Include a single space after the colon of a declaration. 220 | * Include a semi-colon at the end of every declaration in a declaration block. 221 | * Include a space after each comma in comma-separated property or function values. 222 | * Place the closing brace of a rule-set on its own line. 223 | * CSS blocks should be separated by a single clear line. 224 | * Add two blank lines between sections and one between sub-sections. 225 | 226 | > **Do:** 227 | 228 | ```css 229 | .content, 230 | .content-edit { 231 | padding: 0; 232 | margin: 0; 233 | font-family: "Helvetica", sans-serif; 234 | } 235 | 236 | 237 | .newSection { 238 | ... 239 | } 240 | 241 | .newSection-edit { 242 | ... 243 | } 244 | ``` 245 | 246 | > **Don't:** 247 | 248 | ```css 249 | .content, .content-edit{ 250 | padding:0; margin:0; 251 | font-family: "Helvetica",sans-serif} 252 | .newSection { 253 | ... 254 | } 255 | .newSection-edit { 256 | ... 257 | } 258 | ``` 259 | 260 | 261 | #### Quotes 262 | 263 | > **Do:** 264 | > Always use double quotes when available. 265 | > Quote attribute values in selectors 266 | 267 | ```css 268 | input[type="checkbox"] { 269 | background-image: url("/img/you.jpg"); 270 | font-family: "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial; 271 | } 272 | ``` 273 | 274 | > **Don't:** 275 | 276 | ```css 277 | input[type=checkbox] { 278 | background-image: url(/img/you.jpg); 279 | font-family: Helvetica Neue Light, Helvetica Neue, Helvetica, Arial; 280 | } 281 | ``` 282 | 283 | 284 | #### When declaring values 285 | * Use lower-case and shorthand hex values 286 | * Use unit-less line-height values 287 | * Where allowed, avoid specifying units for zero values 288 | * Never specify the height property unless it's specifically needed (`min-height` is cool) 289 | * Never use `!important` (Utility classes are an exception but still should be 290 | avoided) 291 | * Try to only style the property you are explicitly concerned with to reduce 292 | over zealously resetting something you might want to inherit 293 | * `background-color: #333` over `background: #333` 294 | * `margin-top: 10px` over `margin: 10px 0 0` 295 | * Use shorthand if you can, be sensible 296 | 297 | > **Do:** 298 | 299 | ```css 300 | .component { 301 | background-color: #ccc; 302 | color: #aaa; 303 | left: 0; 304 | line-height: 1.25; 305 | min-height: 400px; 306 | padding: 0 20px; 307 | top: 0; 308 | } 309 | ``` 310 | 311 | > **Don't:** 312 | 313 | ```css 314 | .component { 315 | background: #ccc; 316 | color: #AAAAAA; 317 | left: 0px; 318 | line-height: 24px; 319 | height: 400px !important; //jerk #yolo FUUUUUU 320 | padding: 0px 20px 0px 20px; 321 | top: 0px; 322 | } 323 | ``` 324 | 325 | 326 | 327 | #### Declaration order 328 | There are a millions opinions and thoughts on logical ordering and grouping. 329 | Don't force someone to learn your opinion, ordering doesn't matter, consistency 330 | does. Just use the alphabet, _everyone_ knows it. 331 | * @extend 332 | * @include 333 | * Alphabetical, always. 334 | 335 | > **Do** 336 | 337 | ```css 338 | .component { 339 | @extend %a-placeholder; 340 | @include silly-links; 341 | color: #aaa; 342 | left: 0; 343 | line-height: 1.25; 344 | min-height: 400px; 345 | padding: 0 20px; 346 | top: 0; 347 | width: 150px; 348 | } 349 | ``` 350 | 351 | > **Don't:** 352 | 353 | ```css 354 | .component { 355 | min-height: 400px; 356 | left: 0; 357 | @include silly-links; 358 | top: 0; 359 | width: 150px; 360 | color: #aaa; 361 | @extend %a-placeholder; 362 | line-height: 1.25; 363 | width: 200px; 364 | padding: 0 20px; 365 | } 366 | ``` 367 | 368 | 369 | ## Pseudo Elements and Classes 370 | Pseudo elements and classes are very different things, as is the syntax used to 371 | declare them. Declare pseudo _**classes**_ with a single colon. Declare pseudo 372 | _**elements**_ with a double colon. 373 | 374 | > **Do** 375 | 376 | ```css 377 | .component:focus { 378 | ... 379 | } 380 | 381 | .component:hover { 382 | ... 383 | } 384 | 385 | .component::before { 386 | ... 387 | } 388 | 389 | .component::after { 390 | ... 391 | } 392 | ``` 393 | 394 | > **Don't** 395 | 396 | ```css 397 | .component:after { 398 | ... 399 | } 400 | ``` 401 | 402 | 403 | 404 | ## Units 405 | 406 | > **Do:** 407 | 408 | * Use `rem` units as primary unit type. This includes: 409 | * Positioning (`top`, `right`, `bottom`, `left`) 410 | * Dimensions (Such as `width`, `height`, `margin`, `padding`) 411 | * Font size 412 | * Use `px` units as primary unit type for the following properties: 413 | * Border widths (`border: 1px solid #bada55;`) 414 | * Use `%` units only if necessary, where `rem` will not suffice: 415 | * Positioning (`top`, `right`, `bottom`, `left`) 416 | * Dimensions (`width`, `height`) 417 | * Line-height should be kept unit-less. If you find you're using a line-height 418 | with a set unit type, try to think of alternative ways to achieve the same outcome. 419 | If it's a unique case which requires a specific `px` or `rem` unit, outline the 420 | reasoning with comments so that others are aware of its purpose. 421 | 422 | > **Don't:** 423 | 424 | * Avoid all use of magic numbers. Re-think the problem. (`margin-top: 37px;`) 425 | 426 | 427 | 428 | 429 | ## Nesting 430 | 431 | Nesting is handy, _sometimes_, but will quickly conflict with our 432 | [Specificty](#specificity) and [Performance](#performance) guidelines. 433 | 434 | As we follow conventions and thoughts from popular and widely accepted 435 | methodologies such as BEM, SMACSS and SUIT, the use of the Suffix can help immensely though. 436 | 437 | * Just because you can, doesn't mean you should. 438 | * [Parent Selector Suffixes](http://thesassway.com/news/sass-3-3-released#parent-selector-suffixes) 439 | are neat, but not very searchable 440 | * Watch your output, be mindful of [Specificty](#specificity) and 441 | [Performance](#performance) 442 | * Aim for a maximum depth of just 1 nested rule 443 | 444 | > **Do:** 445 | 446 | ```css 447 | .panel-body { 448 | position: relative; 449 | } 450 | 451 | .panel-sideBar { 452 | z-index: 10; 453 | } 454 | 455 | .panel-sideBar-item { 456 | cursor: pointer; 457 | } 458 | 459 | .panel-sideBar-item-label { 460 | color: #AEAEAE; 461 | 462 | &.has-smallFont { 463 | font-size: 13px; 464 | } 465 | } 466 | ``` 467 | 468 | At its worst, this produces: 469 | ```css 470 | .panel-sideBar-item-label.has-smallFont { 471 | font-size: 13px; 472 | } 473 | ``` 474 | 475 | > **Don't:** 476 | 477 | ```css 478 | .bc-tab-panel { 479 | 480 | .panel-body { 481 | position: relative; 482 | ... 483 | 484 | .panel-side-bar { 485 | z-index: 10; 486 | ... 487 | 488 | .panel-side-item { 489 | cursor: pointer; 490 | ... 491 | 492 | .panel-side-item-label { 493 | color: #AEAEAE; 494 | 495 | &.small-font { 496 | font-size: 13px; 497 | } 498 | } 499 | } 500 | } 501 | } 502 | } 503 | ``` 504 | 505 | At it's worst, this produces: 506 | ```css 507 | .bc-tab-panel .panel-body .panel-side-bar .panel-side-item .panel-side-item-label.small-font { 508 | font-size: 13px; 509 | } 510 | ``` 511 | 512 | 513 | ## @extend or @include 514 | 515 | * Excessive use of `@include` can cause unnecessary bloat to your stylesheet, but 516 | gzip should help with that. 517 | * Excessive use of `@extend` can create large selector blocks (not helpful in web inspector) 518 | and hoisting of your selector can cause override and inheritance issues. 519 | * We advise to `@include` over `@extend` generally, but use common sense. In situations where it's better to `@extend` it's safer to do so on a placeholder selector. 520 | 521 | > **Do:** 522 | > Make use of placeholder selectors to separate repeated local styles 523 | 524 | ```css 525 | %placeholderSelector { 526 | background-color: #eee; 527 | } 528 | 529 | .component1 { 530 | @extend %placeholderSelector; 531 | color: red; 532 | } 533 | 534 | .component2 { 535 | @extend %placeholderSelector; 536 | color: blue; 537 | } 538 | ``` 539 | 540 | 541 | ## Components 542 | 543 | Syntax: `[--modifierName|-descendantName]` 544 | 545 | This component syntax is mainly taken from [Suit CSS](http://suitcss.github.io/) 546 | with minor modifications. 547 | 548 | Component driven development offers several benefits when reading and writing 549 | HTML and CSS: 550 | 551 | * It helps to distinguish between the classes for the root of the component, 552 | descendant elements, and modifications. 553 | * It keeps the specificity of selectors low. 554 | * It helps to decouple presentation semantics from document semantics. 555 | 556 | You can think of components as custom elements that enclose specific semantics, 557 | styling, and behaviour. 558 | 559 | **Do not choose a class name based on its visual presentation or its content.** 560 | 561 | The primary architectural division is between components and utilities: 562 | 563 | * componentName (eg. `.dropdown` or `.buttonGroup`) 564 | * componentName--modifierName (eg. `.dropdown--dropUp` or `.button--primary`) 565 | * componentName-descendantName (eg. `.dropdown-item`) 566 | * componentName.is-stateOfComponent (eg. `.dropdown.is-active`) 567 | * u-utilityName (eg. `.u-textTruncate`) 568 | * `[-][--modifierName|-descendentName]` 569 | 570 | 571 | 572 | 573 | #### ComponentName 574 | 575 | The component's name must be written in camel case. Use class names that are as 576 | short as possible but as long as necessary. 577 | 578 | * Example: `.nav` not `.navigation` 579 | * Example: `.button` not `.btn` 580 | 581 | ```css 582 | .myComponent { /* ... */ } 583 | ``` 584 | 585 | ```html 586 |
587 | ... 588 |
589 | ``` 590 | 591 | 592 | #### componentName--modifierName 593 | 594 | A component modifier is a class that modifies the presentation of the base 595 | component in some form. Modifier names must be written in camel case and be 596 | separated from the component name by two hyphens. The class should be included 597 | in the HTML _in addition_ to the base component class. 598 | 599 | ```css 600 | /* Core button */ 601 | .button { 602 | ... 603 | } 604 | 605 | .button--primary { 606 | ... 607 | } 608 | ``` 609 | 610 | ```html 611 | 612 | ``` 613 | 614 | #### componentName-descendantName 615 | 616 | A component descendant is a class that is attached to a descendant node of a 617 | component. It's responsible for applying presentation directly to the descendant 618 | on behalf of a particular component. Descendant names must be written in camel case. 619 | 620 | ```html 621 |
622 |
623 | {$alt} 624 | ... 625 |
626 |
627 | ... 628 |
629 |
630 | ``` 631 | 632 | You might notice that `tweet-avatar`, despite being a descendant of `tweet-header` 633 | does not have the class of `tweet-header-avatar`. Why? Because it doesn't necessarily 634 | **have** to live there. It could be adjacent to `tweet-header` and function the same 635 | way. Therefore, you should **only** prepend a descendant with its parent if must 636 | live there. Strive to keep class names as short as possible, but as long as necessary. 637 | 638 | When building a component, you'll often run into the situation where you have a 639 | list, group or simply require a container for some descendants. In this case, it's 640 | much better to follow a pattern of pluralising the container and having each 641 | descendant be singular. This keeps the relationship clear between descendant levels. 642 | 643 | > **Do:** 644 | 645 | ```html 646 | 653 | ``` 654 | 655 | ```html 656 | 661 | ``` 662 | 663 | > **Don't:** 664 | > Avoid verbose descendant names 665 | 666 | ```html 667 | 674 | ``` 675 | 676 | ```html 677 | 682 | ``` 683 | 684 | 685 | #### componentName.is-stateOfComponent 686 | 687 | Use `is-stateName` for state-based modifications of components. The state name 688 | must be Camel case. **Never style these classes directly; they should always be 689 | used as an adjoining class.** 690 | 691 | JS can add/remove these classes. This means that the same state names can be used 692 | in multiple contexts, but every component must define its own styles for the state 693 | (as they are scoped to the component). 694 | 695 | ```html 696 |
697 | ... 698 |
699 | ``` 700 | 701 | ```css 702 | .tweet { 703 | ... 704 | } 705 | 706 | .tweet.is-expanded { 707 | ... 708 | } 709 | ``` 710 | 711 | 712 | ## Utilities 713 | 714 | Utility classes are low-level structural and positional traits. Utilities can 715 | be applied directly to any element; multiple utilities can be used together; 716 | and utilities can be used alongside component classes. 717 | 718 | Utility classes should be used sparingly, lean towards component level styling 719 | to make for as reusable HTML patterns as possible. 720 | 721 | 722 | 723 | #### u-utilityName 724 | 725 | Syntax: `u-` 726 | 727 | Utilities must use a camel case name, prefixed with a `u` namespace. 728 | 729 | 730 | 731 | ## Variables and Mixins 732 | 733 | Variables and Mixins should follow similar naming conventions. 734 | 735 | 736 | #### Variables 737 | 738 | Syntax: `[[--modifierName][-descendentName]-]-[--]` 739 | 740 | Variables should be named as such, things that can change over time. 741 | 742 | Variables should also follow our component naming convention to show context 743 | and be in camelCase. If the variable is a global, generic variable, the property 744 | name should be prefixed first, followed by the variant and or modifier name for 745 | clearer understanding of use. 746 | 747 | > **Do:** 748 | > Abstract your variable names 749 | 750 | ```CSS 751 | $color-brandPrimary: #aaa; 752 | $fontSize: 1rem; 753 | $fontSize--large: 2rem; 754 | $lineHeight--small: 1.2; 755 | ``` 756 | 757 | > **Don't:** 758 | > Name your variables after the color value 759 | 760 | ```css 761 | $bigcommerceBlue: #00abc9; 762 | $color-blue: #00ffee; 763 | $color-lightBlue: #eeff00; 764 | ``` 765 | 766 | 767 | #### Component / Micro App level variables 768 | 769 | Micro apps must base their local variables on the global variables primarily. 770 | You may add your own specific variables as required if no global variable is available. 771 | 772 | For portability, your component should declare it's own set of variables inside 773 | it's own settings partial, inside the settings folder. Even if at the time, your 774 | component only uses globally available variables from Bigcommerce's Library, 775 | you should reassign the global variable to a local one. 776 | If your component styles change from those global variables at all in the future, 777 | less of your SCSS will have to change, as you only change the local variable value. 778 | 779 | If your variable is scoped to your component, it should be namespaced as such following 780 | our component naming conventions. 781 | 782 | > **Do:** 783 | 784 | ```css 785 | $componentName-fontSize: fontSize("small"); 786 | $componentName-decendantName-backgroundColor: #ccc; 787 | $componentName-decendantName-marginBottom: fontSize("large"); 788 | $componentName-decendantName--active-backgroundColor: #000; 789 | ``` 790 | 791 | ```css 792 | .componentName { 793 | font-size: $componentName-fontSize; 794 | } 795 | 796 | .componentName-decendantName { 797 | background-color: $componentName-decendantName-backgroundColor; 798 | margin-bottom: $componentName-decendantName-marginBottom; 799 | } 800 | 801 | .componentName-decendantName--active { 802 | background-color: $componentName-decendantName--active-backgroundColor; 803 | } 804 | ``` 805 | 806 | 807 | #### Maps, maps are cool 808 | 809 | Variable maps with a simple getter mixin, can help simplify your variable names 810 | when calling them, and help better group variables together using their 811 | relationship. [More info](http://erskinedesign.com/blog/friendlier-colour-names-sass-maps/) 812 | 813 | > **Do:** 814 | 815 | ```scss 816 | // Setting variables and mixin 817 | // ----------------------------------------------------------------------------- 818 | 819 | $colors: ( 820 | primary: ( 821 | base: #00abc9, 822 | light: #daf1f6, 823 | dark: #12799a 824 | ), 825 | secondary: ( 826 | base: #424d55, 827 | light: #ccc, 828 | lightest: #efefef, 829 | dark: #404247 830 | ), 831 | success: ( 832 | base: #bbd33e, 833 | light: #eaf0c6 834 | ) 835 | ); 836 | 837 | @function color($color, $tone: "base") { 838 | @return map-get(map-get($colors, $color), $tone); 839 | } 840 | ``` 841 | 842 | 843 | ```scss 844 | // Usage 845 | // ----------------------------------------------------------------------------- 846 | 847 | body { 848 | color: color("secondary"); 849 | } 850 | 851 | h1, 852 | h2, 853 | h3 { 854 | color: color("secondary", "dark"); 855 | } 856 | 857 | .alert { 858 | background-color: color("primary", "light"); 859 | } 860 | 861 | .alert-close { 862 | color: color("primary"); 863 | } 864 | 865 | .alert--success { 866 | background-color: color("success", "light"); 867 | 868 | > .alert-close { 869 | color: color("success"); 870 | } 871 | } 872 | ``` 873 | 874 | **Every variable used in the core architecture must be based off the global 875 | variables.** 876 | 877 | 878 | #### Colors 879 | 880 | Please only use the globally available colors from the Bigcommerce Library. 881 | Your Micro app or component shouldn't really have a need for a *new* color. 882 | This creates consistency and sanity. 883 | 884 | Avoid using the `darken(color, %)` and `lighten(color, %)` mixins for similar reasons. 885 | 886 | Use the color maps available to you: 887 | ```css 888 | .component { 889 | background-color: color("brand", "primary"); 890 | } 891 | ``` 892 | 893 | 894 | #### z-index scale 895 | 896 | Please use the z-index scale defined in the Bigcommerce Library under global settings. 897 | 898 | `zIndex("lowest")` or `zIndex("high")` for example. 899 | 900 | 901 | 902 | #### Font Weight 903 | 904 | Bigcommerce apps share a strict set of font weights. Never declare a new font weight, 905 | only use the available font settings from the Bigcommerce Library. e.g. 906 | 907 | ```css 908 | fontWeight("light"); 909 | fontWeight("semibold"); 910 | ``` 911 | 912 | 913 | 914 | #### Line Height 915 | 916 | The Bigcommerce Library also provides a line height scale. This should be used for blocks 917 | of text. e.g. 918 | 919 | ```css 920 | lineHeight("smallest"); 921 | lineHeight("large"); 922 | ``` 923 | 924 | Alternatively, when using line height to vertically centre a single line of text, 925 | be sure to set the line height to the height of the container - 1. 926 | 927 | ```CSS 928 | .button { 929 | height: remCalc(50px); 930 | line-height: remCalc(49px); 931 | } 932 | ``` 933 | 934 | 935 | #### Animations 936 | 937 | Animation delays, durations and easing should be taken from the global framework 938 | 939 | 940 | #### Mixins 941 | 942 | Mixins follow regular camel case naming conventions and do not require namespacing. If you are creating a mixin for a utility, it will need to match the utility name (including `u` namespacing). 943 | 944 | * `@mixin buttonVariant;` 945 | * `@mixin u-textTruncate;` 946 | 947 | 948 | ## Polyfills 949 | 950 | At Bigcommerce, we try not to replicate CSS polyfills that auto-prefixer can 951 | supply in a Grunt or Gulp task. This keeps our SCSS code base lean and future proof. 952 | 953 | > **Do:** 954 | 955 | ```css 956 | .button { 957 | border-radius: 3px; 958 | } 959 | ``` 960 | 961 | > **Don't:** 962 | > Add vendor prefixes at all. 963 | 964 | ```css 965 | .button { 966 | @include border-radius(3px); 967 | } 968 | ``` 969 | ```css 970 | .button { 971 | -ms-border-radius: 3px; 972 | -o-border-radius: 3px; 973 | -webkit-border-radius: 3px; 974 | border-radius: 3px; 975 | } 976 | ``` 977 | 978 | 979 | ## JavaScript 980 | 981 | syntax: `js-` 982 | 983 | JavaScript-specific classes reduce the risk that changing the structure or theme 984 | of components will inadvertently affect any required JavaScript behaviour and 985 | complex functionality. It is not necessary to use them in every case, just 986 | think of them as a tool in your utility belt. If you are creating a class, which 987 | you don't intend to use for styling, but instead only as a selector in JavaScript, 988 | you should probably be adding the `js-` prefix. In practice this looks like this: 989 | 990 | ```html 991 | 992 | ``` 993 | 994 | **Again, JavaScript-specific classes should not, under any circumstances, be styled.** 995 | 996 | 997 | ## Folder Structure 998 | 999 | #### General principle 1000 | The Sass folder structure we're proposing, will have two slight differences 1001 | between the core framework and micro apps, however the bulk of the structure is 1002 | identical between the two. 1003 | 1004 | The idea is to have the least amount of folders as possible, but as many as we 1005 | need to define clear, structured patterns in your Sass. 1006 | 1007 | #### Core Folder Structure 1008 | 1009 | ``` 1010 | . 1011 | ├── sass 1012 | | ├── settings/ 1013 | | └── tools/ 1014 | | └── vendor/ 1015 | | └── components/ 1016 | | └── utilities/ 1017 | ``` 1018 | 1019 | 1020 | **/settings:** Contains all of your SCSS variables for your framework. Within 1021 | this folder is 1 primary file `_settings.scss`, which imports all other variable 1022 | files that have been broken into logical files such as `_colors.scss`, 1023 | `_typography.scss`, `_z-index.scss` and your chosen frameworks variables, for 1024 | example `_foundation.scss`. 1025 | 1026 | **/tools:** Contains all of your Sass mixins. Within this folder is 1 primary 1027 | file `_tools.scss`, which imports all other mixin files that have been broken into 1028 | logical files. No framework mixins should appear in this folder as they can be 1029 | consumed from their own respective `/vendor` or `/components` folder. 1030 | 1031 | **/vendor:** Contains all of your vendor files, such as normalize, bootstrap, 1032 | foundation, animate.css, etc. All readily consumable third party files belong 1033 | here, and can be imported in the framework base file as required. No file in 1034 | the /vendor folder should ever be modified. 1035 | 1036 | **/components:** Contains all of your components. This folder will make up the 1037 | vast majority of your compiled CSS. All custom components simply live inside 1038 | this folder, for example `/components/component/_component.scss`. It also contains 1039 | the consumed version of your chosen /vendor framework's components, which will be 1040 | reworked to adhere to the Naming Conventions and Style Guide. They will live 1041 | inside a subfolder of the framework's name, for example `/components/foundation/`. 1042 | 1043 | **/utilities:** Contains all CSS snippets which can be applied to your HTML for 1044 | quick prototyping, or a case by case basis where a unique, yet repeatable style 1045 | is required. Every utility found within this folder will have both a class and a 1046 | mixin. An example being, truncatedText. You can utilise it by applying the class 1047 | `.u-truncatedText` or by applying a mixin, `@include truncatedText;`. 1048 | 1049 | 1050 | #### Micro App Folder Structure 1051 | 1052 | ``` 1053 | . 1054 | ├── sass 1055 | | ├── settings/ 1056 | | └── tools/ 1057 | | └── vendor/ 1058 | | └── layouts/ 1059 | | └── components/ 1060 | | └── utilities/ 1061 | | └── shame/ 1062 | ``` 1063 | 1064 | There are only two minor differences in a micro app, when compared to the core 1065 | framework. Firstly you'll notice that the /framework folder has been replaced by 1066 | a /layouts folder, as well as the addition of the /shame folder. 1067 | 1068 | **/layouts:** Contains your micro app "layouts" and page specific styling. 1069 | Essentially creating the wrapping sections and grids for your app, where the 1070 | core framework's components will live inside. For example, a layout file could 1071 | potentially be your micro app's navigation. It is important to note that the 1072 | styling for individual navigation items and all other inner components styling 1073 | do not live in the layout file. There purpose is purely for the containing 1074 | elements that set up your app. 1075 | 1076 | **/shame:** This interestingly named folder has one goal: to remain empty. It's 1077 | purpose is the place for all of those hot fixes or quick hacks in throwing 1078 | something together. Any code which you don't feel is "complete" can also live 1079 | here. It creates clear visibility on less than perfect code, especially when it 1080 | comes to code reviews, and creates a trail for your dodgy code that if left 1081 | somewhere in your component/layout code could be forgotten about and left. 1082 | 1083 | **A note on: /components & /utilities:** Within your micro app, these folders should 1084 | only house your app's unique code. Any repeatable component or utility that could 1085 | be re-used across other micro apps should be flagged and a PR opened for adding 1086 | it into the core framework. 1087 | -------------------------------------------------------------------------------- /_example.scss: -------------------------------------------------------------------------------- 1 | // ============================================================================= 2 | // FILE TITLE 3 | // ============================================================================= 4 | 5 | 6 | // Comment Block 7 | // ----------------------------------------------------------------------------- 8 | // 9 | // Purpose: This will describe when this component should be used. This comment 10 | // block is 80 chars long 11 | // 12 | // ----------------------------------------------------------------------------- 13 | 14 | 15 | .component { 16 | @extend %component; 17 | color: #aaa; 18 | left: 0; 19 | line-height: 1.25; 20 | min-height: 40rem; 21 | padding: 0 2rem; 22 | top: 0; 23 | } 24 | 25 | .component-child { 26 | margin: 0; 27 | } 28 | 29 | .component-childSecond { 30 | padding-left: 2rem; 31 | } 32 | 33 | 34 | // Component Sub-Section (Purpose: Describes why this section exists) 35 | // ----------------------------------------------------------------------------- 36 | 37 | .componentPart { 38 | color: #333; 39 | } 40 | 41 | .componentPart--modifier { 42 | border: 0; 43 | } 44 | 45 | .componentPart-child { 46 | color: #fff; 47 | } 48 | --------------------------------------------------------------------------------