├── .github └── PULL_REQUEST_TEMPLATE.md ├── CONTRIBUTING.md ├── LICENSE └── README.md /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | 3 | Proposed changes: 4 | 5 | * .. 6 | * .. 7 | 8 | Resolves # . 9 | 10 | ## Checklist 11 | 12 | * [ ] The changes only affect or contain one style guide rule or section. 13 | * [ ] The changes are in [style guide format](/CONTRIBUTING.md#format). 14 | * [ ] The new style guide section has an entry in the [Table of Contents](/README.md#table-of-contents) (only if changes introduce new section). 15 | * [ ] The changes can be merged into the target branch without conflicts. 16 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | For new additions or changes to the guide, create a branch and submit a Pull Request. 4 | Only add/change 1 style guide rule per Pull Request. 5 | The Pull Request serves as a place to discuss and refine the additions/changes. 6 | 7 | ## Format 8 | 9 | Use [Github Flavoured Markdown](https://guides.github.com/features/mastering-markdown/#GitHub-flavored-markdown). 10 | 11 | Each rule should have the following format: 12 | 13 | ```markdown 14 | ## Rule name 15 | Short summary of the rule to provide context. 16 | 17 | ### Why? 18 | * list 19 | * of 20 | * benefits 21 | 22 | ### How? 23 | Instructions with code examples. 24 | ``` 25 | 26 | 27 | ### Rule name 28 | 29 | Use short and descriptive rule names as 2nd level heading: 30 | 31 | ```markdown 32 | ## Avoid `.ready()` 33 | ``` 34 | 35 | ### Summary 36 | 37 | Put a short summary directly after the rule name to provide context. When referencing jQuery API methods, link them to jQuery's docs: 38 | 39 | ```markdown 40 | jQuery's [`.ready()`](https://api.jquery.com/ready/) ensures your script is not executed before the DOM is ready. [...] 41 | ``` 42 | 43 | ### The *Why?* 44 | 45 | Describe why the rule exists. What purpose does it serve? Bullet lists are often most effective: 46 | 47 | ```markdown 48 | ### Why? 49 | 50 | * Using `.ready()` means scripts have been loaded too early. Therefore defer loading instead. 51 | * Script loading blocks page rendering. Therefore script loading should be defered. 52 | ``` 53 | 54 | ### The *How?* 55 | 56 | Describe how (and how not) to apply the rule: 57 | 58 | ```markdown 59 | ### How? 60 | 61 | Defer script loading by placing scripts just before the closing `` tag or using the [`defer` attribute](https://developer.mozilla.org/en/docs/Web/HTML/Element/script#attr-defer): 62 | ``` 63 | 64 | ### Code snippets 65 | 66 | When using code snippets: 67 | * use ```html for highlighted markup examples. 68 | * use ```javascript for highlighted script examples. 69 | * use `` and `/* recommended */` or `` and `/* avoid */` at the start of the snippet to indicate if it's a good or bad practice. 70 | 71 | For example: 72 | 73 | ```html 74 | 75 | 76 | ... 77 | 78 | 79 | 80 | ``` 81 | 82 | ```html 83 | 84 | 85 | ... 86 | 87 | 88 | 89 | 90 | ``` 91 | 92 | ### Back to Table of Contents 93 | 94 | Add a [↑ back to Table of Contents](README.md#table-of-contents) link at the end of each rule, so the reader can easily navigate back: 95 | 96 | ```markdown 97 | [↑ back to Table of Contents](#table-of-contents) 98 | ``` 99 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | # CC0 1.0 Universal 2 | 3 | ## Statement of Purpose 4 | 5 | The laws of most jurisdictions throughout the world automatically confer 6 | exclusive Copyright and Related Rights (defined below) upon the creator and 7 | subsequent owner(s) (each and all, an "owner") of an original work of 8 | authorship and/or a database (each, a "Work"). 9 | 10 | Certain owners wish to permanently relinquish those rights to a Work for the 11 | purpose of contributing to a commons of creative, cultural and scientific 12 | works ("Commons") that the public can reliably and without fear of later 13 | claims of infringement build upon, modify, incorporate in other works, reuse 14 | and redistribute as freely as possible in any form whatsoever and for any 15 | purposes, including without limitation commercial purposes. These owners may 16 | contribute to the Commons to promote the ideal of a free culture and the 17 | further production of creative, cultural and scientific works, or to gain 18 | reputation or greater distribution for their Work in part through the use and 19 | efforts of others. 20 | 21 | For these and/or other purposes and motivations, and without any expectation 22 | of additional consideration or compensation, the person associating CC0 with a 23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright 24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work 25 | and publicly distribute the Work under its terms, with knowledge of his or her 26 | Copyright and Related Rights in the Work and the meaning and intended legal 27 | effect of CC0 on those rights. 28 | 29 | **1. Copyright and Related Rights.** A Work made available under CC0 may be 30 | protected by copyright and related or neighboring rights ("Copyright and 31 | Related Rights"). Copyright and Related Rights include, but are not limited 32 | to, the following: 33 | 34 | i. the right to reproduce, adapt, distribute, perform, display, communicate, 35 | and translate a Work; 36 | 37 | ii. moral rights retained by the original author(s) and/or performer(s); 38 | 39 | iii. publicity and privacy rights pertaining to a person's image or likeness 40 | depicted in a Work; 41 | 42 | iv. rights protecting against unfair competition in regards to a Work, 43 | subject to the limitations in paragraph 4(a), below; 44 | 45 | v. rights protecting the extraction, dissemination, use and reuse of data in 46 | a Work; 47 | 48 | vi. database rights (such as those arising under Directive 96/9/EC of the 49 | European Parliament and of the Council of 11 March 1996 on the legal 50 | protection of databases, and under any national implementation thereof, 51 | including any amended or successor version of such directive); and 52 | 53 | vii. other similar, equivalent or corresponding rights throughout the world 54 | based on applicable law or treaty, and any national implementations thereof. 55 | 56 | **2. Waiver.** To the greatest extent permitted by, but not in contravention of, 57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright 59 | and Related Rights and associated claims and causes of action, whether now 60 | known or unknown (including existing as well as future claims and causes of 61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 62 | duration provided by applicable law or treaty (including future time 63 | extensions), (iii) in any current or future medium and for any number of 64 | copies, and (iv) for any purpose whatsoever, including without limitation 65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes 66 | the Waiver for the benefit of each member of the public at large and to the 67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver 68 | shall not be subject to revocation, rescission, cancellation, termination, or 69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work 70 | by the public as contemplated by Affirmer's express Statement of Purpose. 71 | 72 | **3. Public License Fallback.** Should any part of the Waiver for any reason be 73 | judged legally invalid or ineffective under applicable law, then the Waiver 74 | shall be preserved to the maximum extent permitted taking into account 75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver 76 | is so judged Affirmer hereby grants to each affected person a royalty-free, 77 | non transferable, non sublicensable, non exclusive, irrevocable and 78 | unconditional license to exercise Affirmer's Copyright and Related Rights in 79 | the Work (i) in all territories worldwide, (ii) for the maximum duration 80 | provided by applicable law or treaty (including future time extensions), (iii) 81 | in any current or future medium and for any number of copies, and (iv) for any 82 | purpose whatsoever, including without limitation commercial, advertising or 83 | promotional purposes (the "License"). The License shall be deemed effective as 84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the 85 | License for any reason be judged legally invalid or ineffective under 86 | applicable law, such partial invalidity or ineffectiveness shall not 87 | invalidate the remainder of the License, and in such case Affirmer hereby 88 | affirms that he or she will not (i) exercise any of his or her remaining 89 | Copyright and Related Rights in the Work or (ii) assert any associated claims 90 | and causes of action with respect to the Work, in either case contrary to 91 | Affirmer's express Statement of Purpose. 92 | 93 | **4. Limitations and Disclaimers.** 94 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 95 | surrendered, licensed or otherwise affected by this document. 96 | 97 | b. Affirmer offers the Work as-is and makes no representations or warranties 98 | of any kind concerning the Work, express, implied, statutory or otherwise, 99 | including without limitation warranties of title, merchantability, fitness 100 | for a particular purpose, non infringement, or the absence of latent or 101 | other defects, accuracy, or the present or absence of errors, whether or not 102 | discoverable, all to the greatest extent permissible under applicable law. 103 | 104 | c. Affirmer disclaims responsibility for clearing rights of other persons 105 | that may apply to the Work or any use thereof, including without limitation 106 | any person's Copyright and Related Rights in the Work. Further, Affirmer 107 | disclaims responsibility for obtaining any necessary consents, permissions 108 | or other rights required for any use of the Work. 109 | 110 | d. Affirmer understands and acknowledges that Creative Commons is not a 111 | party to this document and has no duty or obligation with respect to this 112 | CC0 or use of the Work. 113 | 114 | For more information, please see 115 | 116 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jQuery Style Guide 2 | 3 | > Opinionated *jQuery Style Guide* for teams by [De Voorhoede](https://twitter.com/devoorhoede). 4 | 5 | [![style guide jquery](https://img.shields.io/badge/style%20guide-jquery-5ed9c7.svg)](https://github.com/voorhoede/jquery-style-guide) 6 | 7 | ## Purpose 8 | 9 | This guide aims to improve the way your team uses [jQuery](http://jquery.com/). It helps you write code which is 10 | 11 | * close to modern web technologies and best practices. 12 | * easy to understand for developers / team members. 13 | * easy to reuse (in other projects). 14 | * more performant. 15 | * avoids overuse of jQuery and needless vendor locking. 16 | 17 | 18 | ## Table of Contents 19 | 20 | * [About jQuery](#about-jquery) 21 | * [Consider native browser features](#consider-native-browser-features) 22 | * [Consider lightweight alternative](#consider-lightweight-alternative) 23 | * [Avoid `.ready()`](#avoid-ready) 24 | * [Assign `jQuery` to `$`](#assign-jquery-to-) 25 | * [Cache jQuery lookups](#cache-jquery-lookups) 26 | * [Optimise selectors for performance](#optimise-selectors-for-performance) 27 | * [Use `.first()` for single element](#use-first-for-single-element) 28 | * [Use `.on()` for event binding](#use-on-for-event-binding) 29 | * [Use event delegation](#use-event-delegation) 30 | * [Avoid `.show()`, `.hide()` and `.toggle()`](#avoid-show-hide-and-toggle) 31 | * [Avoid using `.css()`](#avoid-using-css) 32 | * [Prefer CSS animations over `.animate()`](#prefer-css-animations-over-animate) 33 | * [Prefer native array methods](#prefer-native-array-methods) 34 | * [Prefer promises over callbacks](#prefer-promises-over-callbacks) 35 | * [Lint your script files](#lint-your-script-files) 36 | * [Create a smaller build](#create-a-smaller-build) 37 | 38 | 39 | ## About jQuery 40 | 41 | [jQuery](http://jquery.com/) is a utility library for easy DOM access & manipulation, event handling, Ajax and more. By using jQuery you can write consise and expressive code which works across modern and legacy browsers. jQuery has extensive tests, detailed documentation, a large active community and an ecosystem of plugins. 42 | 43 | 44 | ## Consider native browser features 45 | 46 | Since the release of jQuery many of its features now have a native browser equivalent. For example adding a class to an element can now be achieved via `element.classList.add(className)` instead of `$(element).addClass(className)`. Depending on the needs of your project you may be able to use only native browser features. 47 | 48 | ### Why? 49 | 50 | * Native browser features are following the spec, making them future proof. 51 | * Native browser features are closer to the metal, making them faster than jQuery. 52 | * Developers who already know JavaScript don't need to learn the specifics of jQuery. 53 | 54 | ### How? 55 | 56 | * Only apply Javascript after feature detection. Use a server-side rendered page as a basis. Enhance parts of a page only if the browser natively supports the required technology. 57 | * Consult [platform.html5.org](https://platform.html5.org/) for overview of native browser technologies and [Can I use](http://caniuse.com/) and [Kangax tables](http://kangax.github.io/compat-table/es5/) for browser compatibility. 58 | * Consult [you might not need jQuery](http://youmightnotneedjquery.com/) for native alternatives to jQuery features. 59 | 60 | [↑ back to Table of Contents](#table-of-contents) 61 | 62 | 63 | ## Consider lightweight alternative 64 | 65 | jQuery is the swiss army knife for DOM and event handling and much more. While jQuery offers a wide range of features, you might not need most of them in your project. Simply because you have little functionality or only modern browsers to support. In that case consider a lightweight alternative. 66 | 67 | ### Why? 68 | 69 | * Lightweight alternatives have a smaller file size and can therefore be downloaded faster. 70 | * Lightweight alternatives have less wrapper functionality which typically makes them faster. 71 | * Some lightweight alternatives support only newer browsers and can therefore stay closer to native browser methods. This typically makes them more performant and easier to understand. 72 | * Some lightweight alternatives mimic the jQuery API. Which means if you know jQuery, you know the alternative. 73 | 74 | ### How? 75 | 76 | * Use a lightweight alternative like [Cash](https://github.com/kenwheeler/cash), [Dominus](https://github.com/bevacqua/dominus#readme), [Shoestring](https://github.com/filamentgroup/shoestring#readme) or [Zepto](https://github.com/madrobby/zepto#readme). 77 | * [Create a jQuery custom build](#create-a-jquery-custom-build) to only include the features you need. 78 | 79 | [↑ back to Table of Contents](#table-of-contents) 80 | 81 | 82 | ## Avoid `.ready()` 83 | 84 | jQuery's [`.ready()`](https://api.jquery.com/ready/) ensures your script is not executed before the DOM is ready. This is important because we typically want to access the DOM in our script. However, since the script can't be executed before the DOM is ready, a better practice is to defer script execution. 85 | 86 | ### Why? 87 | 88 | * Using `.ready()` means scripts have been loaded too early. Therefore defer loading instead. 89 | * Script loading blocks page rendering. Therefore script loading should be defered. 90 | 91 | ### How? 92 | 93 | Avoid loading scripts too early and waiting for the DOM to be ready using `.ready()`. 94 | Defer script loading by placing scripts just before the closing `` tag or using the [`defer` attribute](https://developer.mozilla.org/en/docs/Web/HTML/Element/script#attr-defer): 95 | 96 | ```html 97 | 98 | 99 | ... 100 | 101 | 102 | 103 | ``` 104 | 105 | ```html 106 | 107 | 108 | ... 109 | 110 | 111 | 112 | ``` 113 | 114 | Note: Be aware [using `defer` in IE <= 9 can cause issues](https://github.com/h5bp/lazyweb-requests/issues/42). So consider your browser scope before using this setup. 115 | 116 | ```html 117 | 118 | 119 | ... 120 | 121 | 122 | 123 | 124 | ``` 125 | 126 | [↑ back to Table of Contents](#table-of-contents) 127 | 128 | 129 | ## Assign `jQuery` to `$` 130 | 131 | ### Why? 132 | 133 | * Assigning `jQuery` to `$` is a common practice, which developers are familiair to. 134 | * Assigning `jQuery` to `$` within a scope, avoids unexpected conflict with other scripts using `$`. 135 | * The jQuery documentation and other resources typically use `$`. 136 | 137 | ### How? 138 | 139 | Explicitly assign `jQuery` to `$` within a scope. When using a module loader (like CommonJS) assign it directly to a variable named `$`. Otherwise use an [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) (immediately-invoked function expression): 140 | 141 | ```javascript 142 | /* recommended when using module loader, like CommonJS: */ 143 | const $ = require('jquery'); 144 | // use jQuery as $ 145 | ``` 146 | 147 | ```javascript 148 | /* recommended: use an IIFE */ 149 | (function($){ 150 | // use jQuery as $ 151 | }(jQuery)); 152 | ``` 153 | 154 | [↑ back to Table of Contents](#table-of-contents) 155 | 156 | ## Cache jQuery lookups 157 | 158 | Every call to `$(element}` asks jQuery to rescan for the matching element, wrap it in a jQuery object, and create a new instance of something you already have in memory. This is something avoidable if you already did it once. 159 | 160 | ### Why? 161 | * It avoids querying the DOM for the element everytime want to use it, which greatly improves performance. 162 | * You can use descriptive variable names which convey more meaning. 163 | 164 | ```javascript 165 | /* avoid: repeating jQuery lookups */ 166 | $('button').addClass('is-active'); 167 | $('button').on('click', function(event) {}); 168 | 169 | /* recommended: cache jQuery lookup in variable */ 170 | var $button = $('button'); 171 | $button.addClass('is-active'); 172 | $button.on('click', function(event) {}); 173 | ``` 174 | 175 | [↑ back to Table of Contents](#table-of-contents) 176 | 177 | 178 | ## Optimise selectors for performance 179 | 180 | ### Why? 181 | * Always try to create a selector that is exactly specific enough for your case. Make sure you don't depend on a specific HTML structure. 182 | * Creating good selectors makes your HTML more flexible. 183 | * Querying on a specific element is faster than the whole document. This is really easy with module based development. 184 | 185 | ### How? 186 | 187 | ``` javascript 188 | /* avoid: overly specific */ 189 | var $amount = $('[data-table] [data-table-amount]'); 190 | var $percentage = $('[data-table] [data-table-percentage]'); 191 | 192 | /* recommended: using `.find()` which is highly optimised on the parent element */ 193 | var $table = $('[data-table'); 194 | var $amount = $table.find('[data-table-amount]'); 195 | var $percentage = $table.find('[data-table-percentage]'); 196 | ``` 197 | 198 | [↑ back to Table of Contents](#table-of-contents) 199 | 200 | 201 | ## Use `.first()` for single element 202 | 203 | jQuery always returns a collection when using `$(selector)`, while sometimes you are only interested in / only expect one element. In vanilla JS you would use `.querySelector(selector)` instead of `.querySelectorAll(selector)`. 204 | 205 | ### Why? 206 | To make it clear for other developers of you intention of just using one element 207 | 208 | ### How? 209 | 210 | ```javascript 211 | /* collection of buttons (akin querySelectorAll) */ 212 | $buttons = $form.find('button'); 213 | 214 | /* versus just a single button (akin querySelector) */ 215 | $submitButton = $form.find('[type="submit"]').first(); 216 | ``` 217 | 218 | Naturally variable names should also reflect this. So plural for collections (`$buttons`), singular for a individual element (`$button`). 219 | 220 | [↑ back to Table of Contents](#table-of-contents) 221 | 222 | 223 | ## Use [.on()](http://api.jquery.com/on/) for event binding 224 | 225 | Methods like [`.click()`](http://api.jquery.com/click/) or [`.change()`](http://api.jquery.com/change/) are just alias for `.on('click')` and `.on('change')`. 226 | 227 | ### Why? 228 | 229 | * `.on()` supports [event delegation](http://api.jquery.com/on/#direct-and-delegated-events) resulting in more flexibility and better performance. 230 | * It's a way to keep consistency as all your events have the same signature. 231 | * Avoiding using aliases let you trim the jQuery custom build. That way you reduce load/parse times and the file size. 232 | 233 | ### How? 234 | 235 | ``` javascript 236 | /* avoid: .click() */ 237 | $button.click(function(event) {}); 238 | 239 | /* recommended: .on() */ 240 | $button.on('click', function() {}); 241 | ``` 242 | 243 | [↑ back to Table of Contents](#table-of-contents) 244 | 245 | 246 | ## Use event delegation 247 | 248 | > When a selector is provided, the event handler is referred to as delegated. jQuery bubbles the event from the event target up to the element where the handler is attached and runs the handler for any elements along that path matching the selector. 249 | > 250 | > — [jQuery](http://api.jquery.com/on/#direct-and-delegated-events) 251 | 252 | ### Why? 253 | 254 | * Using delegated events allows for events to be processed even to elements added to the document later 255 | * Keeps the scope of the event *bubbling* shorter and thus performant. 256 | 257 | ### How? 258 | 259 | ```javascript 260 | $list = $('[todo-list]').first(); 261 | $items = $list.find('[todo-item]'); 262 | 263 | /* avoid: event listener on each item */ 264 | $items.on('click', function(event) { /* ... */ }); 265 | 266 | /* recommended: event delegation on list */ 267 | $list.on('click', '[todo-item]', function(event) { /* ... */ }); 268 | ``` 269 | 270 | [↑ back to Table of Contents](#table-of-contents) 271 | 272 | 273 | ## Avoid `.show()`, `.hide()` and `.toggle()` 274 | 275 | JQuery lets you [`.show()`](http://api.jquery.com/show/), [`.hide()`](http://api.jquery.com/hide/) and [`.toggle()`](http://api.jquery.com/toggle/) elements. jQuery toggles an inline `display: none` to achieve this. 276 | HTML5 introduces a [new global attribute named `[hidden]`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/hidden), which is styled as `display: none` by default. It's better practice to use this native standard and toggle `[hidden]` instead of using `.show()`, `.hide()` and `.toggle()`. 277 | 278 | ### Why? 279 | 280 | * Avoid `.show()`, `.hide()` and `.toggle()` as they use inline styles, which are hard to overwrite. 281 | * Prefer `[hidden]` as it semantically indicates an element is not yet, or no longer, relevant. 282 | * Styles should be managed in (external) CSS stylesheets (not inlined) for separation of concerns. 283 | 284 | ### How? 285 | 286 | Add, remove or toggle the `[hidden]` attribute instead of using `.show()`, `.hide()` or `.toggle()`. 287 | 288 | Note: If you need to support pre HTML5 browsers use CSS to style `[hidden]` correctly: 289 | ```css 290 | /* recommended: ensure hidden elements are not displayed in pre HTML5 browsers */ 291 | [hidden] { display: none !important; } 292 | ``` 293 | 294 | #### Show elements 295 | 296 | ```javascript 297 | /* avoid: `.show()` elements */ 298 | $elements.show(); 299 | 300 | /* recommended: add `[hidden]` attribute */ 301 | $elements.attr('hidden', ''); 302 | ``` 303 | 304 | #### Hide elements 305 | 306 | ```javascript 307 | /* avoid: `.hide()` elements */ 308 | $elements.hide(); 309 | 310 | /* recommended: remove `[hidden]` attribute */ 311 | $elements.removeAttr('hidden'); 312 | ``` 313 | 314 | #### Toggle elements 315 | 316 | ```javascript 317 | /* avoid: `toggle()` elements */ 318 | $elements.toggle(); 319 | ``` 320 | 321 | ```javascript 322 | /* recommended: toggle hidden attribute (with jQuery): */ 323 | // add `toggleHidden` functionality as jQuery plugin 324 | $.fn.toggleHidden = function() { 325 | return this.each(function(index, element) { 326 | var $element = $(element); 327 | if ($element.attr('hidden')) { 328 | $element.removeAttr('hidden') 329 | } else { 330 | $element.attr('hidden', ''); 331 | } 332 | }); 333 | }; 334 | 335 | // call `toggleHidden` on element: 336 | $elements.toggleHidden(); 337 | ``` 338 | 339 | ```javascript 340 | /* recommended: toggle hidden attribute (without jQuery): */ 341 | $elements.get().forEach(toggleHidden); 342 | 343 | function toggleHidden(element) { 344 | if (element.hasAttribute('hidden')) { 345 | element.removeAttribute('hidden') 346 | } else { 347 | element.setAttribute('hidden', ''); 348 | } 349 | } 350 | ``` 351 | [↑ back to Table of Contents](#table-of-contents) 352 | 353 | 354 | ## Avoid using `.css()` 355 | 356 | jQuery can get and set styling directly on an element with the [`.css()`](https://api.jquery.com/css/) method. 357 | When using `.css()` to set CSS it will set the styles inline and you will be mixing concerns (styling and logic). 358 | 359 | ### Why? 360 | * By toggling classes the same thing can be accomplished. 361 | * Separation of concerns, don't mix CSS with JavaScript. 362 | * When the `.css()` method is not used it can be omitted when creating a custom jQuery build. This reduces file size. 363 | 364 | ### How? 365 | ``` javascript 366 | /* avoid: mixing JavaScript and CSS */ 367 | $element.css('border', '1px solid green'); 368 | ``` 369 | 370 | ``` javascript 371 | /* recommended: using a class */ 372 | $element.addClass('is-active'); 373 | ``` 374 | 375 | ``` css 376 | /* CSS */ 377 | .is-active { border: 1px solid green; } 378 | ``` 379 | 380 | [↑ back to Table of Contents](#table-of-contents) 381 | 382 | 383 | ## Prefer CSS animations over `.animate()` 384 | 385 | jQuery lets you create complex animation sequences using [.animate()](http://api.jquery.com/animate/). Since the introduction of jQuery native CSS has caught up and now also provides methods to transition and animate elements. 386 | 387 | ### Why? 388 | 389 | * Defining animations in CSS separates presentation from (interaction) logic. 390 | * Native CSS transitions and animations can be hardware-accelerated (using GPU), resulting in smoother animations. 391 | 392 | ### How? 393 | 394 | For simple animations use a [CSS transition](https://developer.mozilla.org/en-US/docs/Web/CSS/transition): 395 | 396 | ```javascript 397 | /* avoid: jquery animate */ 398 | $element.animate({ left: '50px' }, 150, 'easeout'); 399 | ``` 400 | 401 | ```javascript 402 | /* recommended: css animations */ 403 | $element.addClass('is-active'); 404 | ``` 405 | 406 | ```css 407 | /* vendor prefix might be required */ 408 | .is-active { 409 | transform: translate(50px); 410 | transition: transform 150ms ease-out; 411 | } 412 | ``` 413 | 414 | For more complex animations use a [CSS keyframes animation](https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes): 415 | 416 | ```javascript 417 | /* avoid: jquery animate */ 418 | function blink() { 419 | $element 420 | .animate({ opacity: 0 }, 1000) 421 | .animate({ opacity: 1 }, 1000, blink); 422 | } 423 | blink(); 424 | ``` 425 | 426 | ```javascript 427 | /* recommended: css animations */ 428 | $element.addClass('is-blinking'); 429 | ``` 430 | 431 | ```css 432 | /* vendor prefix might be required */ 433 | .is-blinking { 434 | animation: blink 2s infinite; 435 | } 436 | 437 | @keyframes blink { 438 | 0% { opacity: 1; } 439 | 50% { opacity: 0; } 440 | 100% { opacity: 1; } 441 | } 442 | ``` 443 | 444 | [↑ back to Table of Contents](#table-of-contents) 445 | 446 | 447 | ## Prefer native Array methods 448 | 449 | ### Why? 450 | 451 | jQuery’s array methods are non-standard. They use the signature `(index, item/element)` while native uses `(item/element, index)`. 452 | 453 | ### How? 454 | 455 | Make sure you check your browser scope [supports native array methods](http://kangax.github.io/compat-table/es5/). Then use [`.get()`](http://api.jquery.com/get/) to get a native array of HTML elements. Use [native array methods](https://dev.opera.com/articles/javascript-array-extras-in-detail/), like `forEach`, `map`, `filter` and `reduce` to process the elements: 456 | 457 | ``` javascript 458 | /* avoid: jQuery array methods */ 459 | $elements.map((index, el) => /* ... */) 460 | 461 | /* recommended: use native methods */ 462 | $elements.get().map(el => /* ... */) 463 | ``` 464 | [↑ back to Table of Contents](#table-of-contents) 465 | 466 | 467 | ## Prefer promises over callbacks 468 | 469 | A Promise represents a proxy for a value not necessarily known when the promise is created. It allows you to associate handlers to an asynchronous action's eventual success value or failure reason. 470 | 471 | ### Why? 472 | 473 | Use promises instead of callbacks to keep code more readable and future proof when handling asynchronous requests. 474 | Promises can also be passed around so other modules can chain (.then) onto it, instead of complex callbacks inside callbacks (pyramid of doom) structures. 475 | 476 | ### How? 477 | 478 | ``` javascript 479 | /* avoid: callbacks */ 480 | $.ajax('example.com/articles/1/author', { 481 | success: function(response) {}, 482 | error: function(err) {} 483 | }); 484 | 485 | /* recommended: use promise */ 486 | var request = $.ajax('example.com/articles/1/author'); 487 | request.then(function(response) {}); 488 | request.catch(function(err) {}); 489 | ``` 490 | 491 | [↑ back to Table of Contents](#table-of-contents) 492 | 493 | 494 | ## Lint your script files 495 | 496 | Linters like [ESLint](http://eslint.org/) and [JSHint](http://jshint.com/) improve code consistency and help trace syntax errors. 497 | 498 | ### Why? 499 | 500 | * Linting files ensures all developers use the same code style. 501 | * Linting files helps you trace syntax errors before it's too late. 502 | 503 | ### How? 504 | 505 | Configure your linter to accept jQuery and `$` as global variable. 506 | 507 | #### ESLint 508 | 509 | ```json 510 | { 511 | "env": { 512 | "browser": true 513 | }, 514 | "globals": { 515 | "jQuery": true, 516 | "$": true 517 | } 518 | } 519 | ``` 520 | 521 | #### JSHint 522 | 523 | ```json 524 | { 525 | "jquery": true, 526 | "browser": true 527 | } 528 | ``` 529 | 530 | [↑ back to Table of Contents](#table-of-contents) 531 | 532 | 533 | ## Create a smaller build 534 | 535 | > Special builds can be created that exclude subsets of jQuery functionality. This allows for smaller custom builds when the builder is certain that those parts of jQuery are not being used. 536 | > 537 | > — [jQuery](https://github.com/jquery/jquery#modules) 538 | 539 | ### Why? 540 | 541 | * Smaller builds download quicker, are parsed quicker and require less memory. 542 | * Excluding methods best avoided restricts developers from using them (no more `$('p').css('red')`, etc). 543 | 544 | ### How? 545 | 546 | Follow the [official documention on creating a custom build](https://github.com/jquery/jquery#what-you-need-to-build-your-own-jquery) to get you setup. 547 | 548 | Then create your own custom build excluding [modules](https://github.com/jquery/jquery#modules) you don't need: 549 | 550 | grunt custom:-css,-css/showHide,-deprecated,-effects,-event/alias,-core/ready,-exports/amd 551 | 552 | This custom build is an example that reflects the guidelines presented. Following this guide saves you 17KB (6kb gzipped) on your final jQuery size. 553 | 554 | [↑ back to Table of Contents](#table-of-contents) 555 | 556 | 557 | --- 558 | 559 | ## License 560 | 561 | [![CC0](http://mirrors.creativecommons.org/presskit/buttons/88x31/svg/cc-zero.svg)](https://creativecommons.org/publicdomain/zero/1.0/) 562 | 563 | [De Voorhoede](https://twitter.com/devoorhoede) waives all rights to this work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. 564 | 565 | You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. 566 | --------------------------------------------------------------------------------