forked from taitems/Front-End-Development-Guidelines
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
1368 lines (840 loc) · 42.5 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html>
<head>
<title>Front End Development Guidelines</title>
<link href="http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css" rel="stylesheet" type="text/css" />
<link href="includes/styles.css" rel="stylesheet" type="text/css" />
<script src="http://code.jquery.com/jquery-1.5.2.min.js" type="text/javascript"></script>
<script src="includes/jquery.scrollTo-min.js" type="text/javascript"></script>
<script src="includes/interact.js" type="text/javascript"></script>
<script src="includes/respond.min.js" type="text/javascript"></script>
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js" type="text/javascript"></script>
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js" type="text/javascript"></script>
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCss.js" type="text/javascript"></script>
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js" type="text/javascript"></script>
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shAutoloader.js" type="text/javascript"></script>
</head>
<body>
<div id="toc">
<div class="wrapper">
<h1>Contents</h1>
</div>
</div>
<div id="mainContainer">
<h1>Accessibility</h1>
<div class="entry">
<h2>What's Up, DOCTYPE?</h2>
<p>
The absence of a DOCTYPE is a crime punishable by death. You may have relied on the following DOCTYPE in the past, but it's important to know that this is now being superceded by a leaner and meaner snippet.
</p>
<script type="syntaxhighlighter" class="brush: xml; toolbar: false; gutter: false;"><![CDATA[
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
]]></script>
<p>
Ideally, the HTML5 DOCTYPE should be used. It's supported in all modern browsers, and throws IE6 and IE7 into standards mode. <a href="http://ejohn.org/blog/html5-doctype/" target="_blank">Source</a>.
</p>
<script type="syntaxhighlighter" class="brush: xml; toolbar: false; gutter: false;"><![CDATA[
<!DOCTYPE html>
]]></script>
</div>
<div class="entry">
<h2>Write Valid Semantic Markup</h2>
<p>
Writing websites with clean, semantic HTML is something we wish we could always do. Sometimes we find ourselves limited by the way pages were setup by our predecessors, or sometimes we're coding a HTML email. The validity of the HTML should never be compromised, even if to solve a browser specific bug.
</p>
<p>
Headings should be heirarchically created from <code><h1></code> onwards, paragraphs should always be in <code><p></code> tags and so on and so forth. If you write semantic HTML, the resultant page will be cleaner, lighter and easily parsed by search engine spiders. This is one of the simplest SEO fixes you can undertake.
</p>
<h3>Which do you think looks cleaner, this?:</h3>
<script type="syntaxhighlighter" class="brush: xml; toolbar: false; gutter: false;"><![CDATA[
<span class="sectionHeading">A Heading</span>
<br /> <br />
Lorem ipsum dolor sit amet. ...
<br /> <br />
]]></script>
<h3>Or this?</h3>
<script type="syntaxhighlighter" class="brush: xml; toolbar: false; gutter: false;"><![CDATA[
<h1>A Heading</h1>
<p>
Lorem ipsum dolor sit amet. ...
</p>
]]></script>
</div>
<div class="entry">
<h2>Use Microformats</h2>
<p>
Microformats are a way of making contact information machine readable. hCard classes (not vCard) are used to define the type of content contained within elements. These are then extracted or highlighted by the browser.
</p>
<script type="syntaxhighlighter" class="brush: xml; toolbar: false; gutter: false;"><![CDATA[
<span class="tel">
<span class="type">home</span>:
<span class="value">+1.415.555.1212</span>
</span>
]]></script>
<p>
If you were to navigate to a page that uses this, you would notice that a program like Skype will easily detect what numbers on the page are phone numbers. Mobile Safari does something similar on iOS devices.
</p>
<p>
For more information: <a href="http://microformats.org/wiki/hcard" target="_blank">http://microformats.org/wiki/hcard</a>
</p>
</div>
<div class="entry">
<h2>Images Need ‘Alt’ Text</h2>
<p>
The <code><img></code> tag requires <code>alt</code> text to both validate and meet accessibility guidelines. The text in the <code>alt</code> attribute should be descriptive of what the image shows, or is trying to achieve, unless of the course the image is not critical.
</p>
<p>
If the image is of a list bullet or other trivial icons, it is recommended to simply leave the <code>alt</code> attribute empty, but still present. A screenreader will then ignore it, as opposed to having to read out "bullet" 20 times.
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
<img src="dog.gif" alt="Fido and I at the park!" />
<!-- good, descriptive -->
<img src="bullet.gif" alt="bullet" />
<!-- bad, as silly as it seems -->
<img src="bullet.gif" alt="" />
<!-- good -->
]]></script>
</div>
<div class="entry">
<h2>Use Tables for Tabular Data Only</h2>
<p>
Tables should only ever be used for the presentation of tabular data. The only exception is when composing HTML email, in which a table is almost the only thing supported by soul crushing email clients.
</p>
<p>
For accessibility, table headers should always be presented using <code><th></code> elements. In .NET datagrids, this can be enabled by setting <code>showAccessibleHeader</code> to true.
Remember to also set <code>cellpadding</code>, <code>cellspacing</code> and <code>border</code> values to <code>0</code> as these are more consistently controlled by CSS.
</p>
<script type="syntaxhighlighter" class="brush: xml; toolbar: false; gutter: false;"><![CDATA[
<table cellpadding="0" cellspacing="0" border="0">
<thead>
<tr>
<th>
Cell Header
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
Cell Item
</td>
</tr>
</tbody>
</table>
]]></script>
</div>
<div class="entry">
<h2>Use jQuery & jQuery UI Widgets</h2>
<p>
jQuery and jQuery UI are constructed to look and behave as close to identical as possible on different browsers.
jQuery UI is designed to be WAI WCAG 2.0 and WAI ARI compliant, so using the framework removes any uncertainty about plugins or scripts running on your site.
</p>
</div>
<h1>JavaScript</h1>
<div class="entry">
<h2>Whitespacing & Formatting</h2>
<p>
Any discussion about formatting, whitespacing and the placement of braces is going to be hotly debated. I guess the simplest rule is that, unless you're willing to completely format a whole document, <strong>respect and maintain the formatting of an existing document</strong>.
That means: see same-line braces throughout a JS file, continue to write code with same-line braces. Your code should fail the code review process if it doesn't maintain consistency with the rest of the document.
</p>
<p>
Consistent formatting makes code more readable, and also means the code can be easily modified with find and replace commands. The coding habits we have picked up are thankfully very similar to what jQuery officially encourages. There are a few minor discrepencies, but again, these are personal issues or things that we think cannot be maintained.
<a href="http://docs.jquery.com/JQuery_Core_Style_Guidelines" target="_blank">Further Reading</a>
</p>
<h3>Character Spacing</h3>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
// Bad
if(blah==="foo"){
foo("bar");
}
// Good :)
if (blah === "foo") {
foo("bar");
}
]]></script>
<h3>Same Line Braces</h3>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
// Bad
if (foo)
{
bar();
}
// Good :)
if (foo) {
bar();
}
]]></script>
<h3>Always Using Parenthesis</h3>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
// Bad
if (foo)
bar();
// Good :)
if (foo) {
bar();
}
]]></script>
<h3>String Handling</h3>
<p>
<strong>Strings should always use double quotes</strong>. Some people are very fond of their C style strings (single quotes), but this leads to conflicting styles within a script.
C style string handling dictates that empty and single character strings should be wrapped in single quotations, while phrases and words should be wrapped in double quotations.
</p>
</div>
<div class="entry">
<h2>Commenting</h2>
<p>
Javascript code requires regular commenting in order to make it easily understandable. The general rule of thumb for javascript is to use single line comments where possible to
quickly and concisely describe what a particular line or block of code is meant to do. If you need to be a little more descriptive eg, describing what a function is meant to do,
then the long comment syntax is better.
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
var zeroAsAString = "0";
// Checks if zeroString is 0 and then runs function doHeapsOfStuff()
if (zeroAsAString === 0) {
doHeapsOfStuff(param1, param2)
}
/*
Initiated When: zeroAsAString === 0
Parameters: param1, param2
*/
function doHeapsOfStuff() {
}
]]></script>
</div>
<div class="entry">
<h2>Always Use === Comparison</h2>
<p>
The use of the == equality operator allows for frustrating bugs to slip through almost undetected. It allows for weak typing that is best explained by <a href="http://bonsaiden.github.com/JavaScript-Garden/#types.equality" target="_blank">Javascript Garden</a>.
The use of the strict equality operator === does not run type coercion and therefore strictly evaluates the difference between two objects. Again, consult <a href="http://bonsaiden.github.com/JavaScript-Garden/#types.equality" target="_blank">Javascript Garden</a> for more information
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
var zeroAsAString = "0";
if (zeroAsAString == 0) {
// gets in here lolwut
}
if (zeroAsAString === 0) {
// never gets in here
}
]]></script>
<h3>The Exception</h3>
<p>
Double equals comparison is allowed when comparing to null, because it will detect both null or undefined properties. If you don't fully understand this, I still suggest you use triple equals.
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
var foo = null;
// foo is null, but bar is undefined as it has not been declared
if (foo == null && bar == null) {
// still got in here
}
]]></script>
</div>
<div class="entry">
<h2>Always Specify the Second ‘radix’ Parameter When Using .parseInt()</h2>
<p>
When parsing a string to an integer, it is considered good practice to specify the second 'radix' parameter - which determines to what base the string should be converted to. It is, by default, octal/binary - so you will run into some problems.
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
alert( parseInt("08") ); // alerts: 2
]]></script>
<p>
It is suggested you always send a value of <code>10</code>, as base 10 is generally what we'll be using.
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
alert( parseInt("08", 10) ); // alerts: 8
]]></script>
</div>
<div class="entry">
<h2>Avoid Comparing to true and false</h2>
<p>
Direct comparison to the values of true and false is unnecessary. Sometimes it might be good for clarity, but it's just extra code.
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
if (foo === true) {
// good that they're using triple equals, bad as it's ambiguous
}
if (foo) {
// yay!
}
if (!bar) {
// the opposite
}
]]></script>
</div>
<div class="entry">
<h2>Avoid Polluting the Global Namespace</h2>
<p>
An over-reliance on global variables is something all of us, myself especially, are guilty of. Arguments as to why globals are bad are fairly straight forward: the chance of script and variable conflicts is increased,
and both the source file and the namespace itself become littered with countless ambiguously named variables.
</p>
<p>
<a href="http://yuiblog.com/" target="_blank">Douglas Crockford</a> believes that the quality of a JavaScript application can be assessed by the number of global variables it uses; the less the better. Given that not everything can be a local
(but let's be honest, that one you're thinking about right now, it can, don't be lazy) you need to find a way of structuring your variables to prevent clashes and minimise the bloat.
The easiest way is to employ a single variable or a minimal amount of modules on which the variables are set. Crockford mentions that <abbr>YUI</abbr> uses a single global, <code>YAHOO</code>.
He discusses this in more detail in his blog post <a href="http://yuiblog.com/blog/2006/06/01/global-domination/" target="_blank">"Global Domination"</a>.
</p>
<p>
Considering that, in the case of small web apps, globals are generally used to store application-wide settings: it's generally better to namespace your project or settings as objects.
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
// polluted global name space
var settingA = true;
var settingB = false;
var settingC = "test";
// a settings namespace
var settings = {
settingA: true,
settingB: false,
settingC: "test"
}
]]></script>
<p>
But if we're avoiding globals to reduce the chance of conflicts, isn't standardising the namespaces to be the same going to increase chance of one app's settings overwriting anothers? Well, it would make sense.
It is instead suggested that you namespace your globals to your own specific app name, or reassign your namespace much in the same way that jQuery uses <code>$.noConflict()</code> mode.
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
var myAppName = {
settings: {
settingA: true
}
}
//accessed as
myAppName.settings.settingA; // true
]]></script>
</div>
<div class="entry">
<h2>Camel Case Variables</h2>
<p>
Shouldn't have to explain this one:
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
var MOUSE_TIMEOUT = 30; // bad
var mouseTimeout = 30; // good :)
]]></script>
</div>
<div class="entry">
<h2>Readable Milliseconds</h2>
<p>
A handy way of writing milliseconds in a readable format.
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
// is this 3, 30 or 300 seconds?
var timeout = 30000;
// an extra calculation, but easier to read and modify
var timeout = 30 * 1000;
]]></script>
</div>
<div class="entry">
<h2>Loop Performance - Cache Array Length</h2>
<p>
Looping is arguably the most important part of JavaScript performance to get right. Shave a millisecond or two off inside of a loop, potentially gain seconds overall. One such way is to cache the length of an array so it doesnt have to be calculated every time the loop is iterated through.
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
var toLoop = ["1000 items"];
for (var i = 0; i < toLoop.length; i++) {
// BAD - the length has to be evaluated 1000 times
}
for (var i = 0, len = toLoop.length; i < len; i++) {
// GOOD - the length is only looked up once and then cached
}
]]></script>
<h3>The Exception</h3>
<p>
If you're looping through an array to find an remove a particular item, this will alter the array length. Any time you change the array length by either adding or removing items from inside the loop, you will get yourself into trouble. Consider either re-setting the length or avoid caching it for this particular situation
</p>
</div>
<div class="entry">
<h2>Loop Performance - Use ‘break;’ & ‘continue;’</h2>
<p>
The ability to step over and out of loops is really useful in avoiding costly loop cycles.
</p>
<p>
If you're looking for something inside of a loop, what do you do once you find it? Say the condition you're looking for is matched halfway through a 1000 item loop.
Do you execute whatever you intend to do, and allow the loop to continue to iterate over the remaining 500 items, knowing that there's no chance it will hit an if statement? Nope! You break out of your loop, literally!
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
var bigArray = ["1000 items"];
for (var i = 0, len = bigArray.length; i < len; i++) {
if (i === 500) {
break;
}
console.log(i); // will only log out 0 - 499
}
]]></script>
<p>
Another problem is skipping over a particular iteration and then continuing on with the loop. While things like odds and evens are better managed by replacing <code>i++</code> with <code>i + 2</code>,
some conditions need to be specifically listened for, to then trigger the skip. Anything that prevent's running through an entire iteration is pretty handy.
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
var bigArray = ["1000 items"];
for (var i = 0, len = bigArray.length; i < len; i++) {
if (condition) {
continue;
}
doCostlyStuff();
}
]]></script>
</div>
<div class="entry">
<h2>Don't Send Too Many Function Parameters</h2>
<p>
This is a pretty bad idea, more for readability than anything:
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
function greet(name, language, age, gender, hairColour, eyeColour) {
alert(name);
}
]]></script>
<p>
It's a much better idea to construct an object before-hand or to pass the object inline
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
function greet(user) {
alert(user.name);
}
greet({
name: "Bob",
gender: "male"
});
]]></script>
</div>
<div class="entry">
<h2>Remap ‘this’ to ‘self’</h2>
<p>
When writing object-oriented (OO) JavaScript, the scope of <code>this</code> must be understood. Regardless of what design pattern you choose to structure your pseudo-classes, a reference to <code>this</code> is generally the
easiest way to refer back to an instance. The moment you begin integrating jQuery helper methods with your pseudo-classes is the moment you notice the changing scope of <code>this</code>.
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
Bob.findFriend("Barry");
Person.prototype.findFriend = function(toFind) {
// this = Bob
$(this.friends).each(function() {
// this = Bob.friends[i]
if (this.name === toFind) {
// this = Barry
return this;
}
});
}
]]></script>
<p>
In the above example, <code>this</code> has changed from a reference to <code>Bob</code>, to his friend <code>Barry</code>. It's important to understand what happened to the value of <code>this</code> over time.
Inside of the prototyped function, <code>this</code> refers to the instance of the pseudo-class (in this case <code>Bob</code>).
Once we step inside the <code>$.each()</code> loop, <code>this</code> is then re-mapped to be item <code>i</code> in the parsed array.
</p>
<p>
It's not incredibly difficult to understand how the scope of <code>this</code> changes. <!--Learning how to correctly use <code>call()</code> and <code>apply()</code> is, on the other hand, a much more complicated manner for my puney designer brain.
While some people would suggest this as a better way of managing those sticky situations,--> I believe the solution is to remap the value of <code>this</code> to <code>self</code>.
This opinion is re-inforced by the jQuery source code, which frequently remaps <code>this</code> throughout its functions.
</p>
<p>
In the following example I will better utilise the parameters made available with the <code>$.each()</code> helper, as well as re-mapping the value of <code>this</code>.
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
Bob.findFriend("Barry");
Person.prototype.findFriend = function(toFind) {
// the only time "this" is used
var self = this;
$(self.friends).each(function(i,item) {
if (item.name === toFind) {
return item;
}
});
}
]]></script>
</div>
<div class="entry">
<h2>CanIHaz Boolean?</h2>
<p>
Booleans should be named with the prefixes of <code>is</code>, <code>can</code> or <code>has</code>.
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
isEditing = true;
obj.canEdit = true;
user.hasPermission = true;
]]></script>
</div>
<div class="entry">
<h2>Feature Sniff, Don't Browser Sniff</h2>
<p>
Does the client's browser support geolocation? Does the client's browser support web workers? HTML5 video? HTML5 audio? The answer used to be:
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
if ($.browser.msie) {
// no it doesnt
}
]]></script>
<p>
But things are rapidly changing. The latest version of IE is almost a modern browser, but as usual it's making front end development a pain. Earlier versions of IE were generally as equally sucky as their predecessors,
so it enabled lazy JavaScript developers to simply detect <code>if (ie)</code> and execute some proprietary Microsoft slops syntax. Now IE9 has done away with these functions, but that old <code>if (ie)</code> chestnut is throwing a spanner in the works.
</p>
<p>
So what if you could detect support for individual features without sniffing the (unreliable and cloakable) user-agent?
</p>
<p>
If you answered <em>"that would be ghetto"</em>, then you are correct.
</p>
<p>
In steps <a href="http://www.modernizr.com" target="_blank">Modernizr</a>, a JavaScript library developed in part by industry dream-boat Paul Irish.
With wide adoption, tiny file-size and plenty of <a href="http://www.modernizr.com/docs/#s1" target="_blank">documentation</a>: implementing it is a no-brainer.
It creates a <code>Modernizr</code> object that contains the results of it's detection tests, so checking feature support is as simple as the following:
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
// old way of detecting canvas support
if (!!document.createElement('canvas').getContext) { ... }
// with Modernizr
if (Modernizr.canvas) { ... }
]]></script>
</div>
<h1>jQuery Specific</h1>
<div class="entry">
<h2>Chain Like a Sick Bitch</h2>
<p>
One of the best parts of jQuery is it's function chaining. You've probably used it a bit, maybe a few simple calls... but have you ever traversed the DOM like a sick bitch? Take some time to familiarise yourself with the <a href="http://api.jquery.com/end/" target="_blank">.end()</a> function. It is critical for when you begin stepping up and down the DOM tree from your original selector.
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
$(".quote")
.hide()
.find("a").text("Click here").bind("click",doStuff).end()
.parent().removeClass().addClass("testimonial").draggable().end()
.fadeIn("slow");
]]></script>
<p>
In the example above, the <a href="http://api.jquery.com/end/" target="_blank">.end()</a> function is used once we have finished doing things with a particular DOM object and want to traverse
back up the DOM to the original object we called. We then load back up and dive back into the DOM.
</p>
</div>
<div class="entry">
<h2>‘.stop()’ Collaborate & Listen</h2>
<p>
Binding jQuery animations to mouse events is a key part of modern web-based user interaction. It's also something that you see done poorly on even the most famous of web sites.
<a href="http://www.learningjquery.com/2009/01/quick-tip-prevent-animation-queue-buildup" target="_blank">This article</a> provides a straight forward example of built up animations and demonstrates how visually jarring they can be.
Thankfully it's easily fixed with a single function prefix or a parameter added to <code>$.animate</code> calls.
</p>
<p>
When using <code>$.animate</code>, <code>queue: false</code> can be added to the parameters to prevent chaining. Animation shortcuts such as <code>$.fadeIn</code> or <code>$.slideDown</code> do not take <code>queue</code> settings.
Instead you have to pre-empt these animations with the <code>$.stop</code> method of pausing currently executing animations. Certain scenarios require the animation to stop dead in it's tracks, or to jump to the end of the transition.
It is recommended you familiarise yourself with the <a href="http://api.jquery.com/stop/" target="_blank">documentation</a> of the parameters <code>clearQueue</code> and <code>jumpToEnd</code>, because god knows I can't help you there.
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
$("selector").stop(true,true).fadeOut();
$("selector").animate({
property: value
}, {
duration: 1000,
queue: false
}
]]></script>
<p>
Tangentially, I find it odd that what I can only assume is an American authored library uses such a profoundly British word as <code>queue</code>.
</p>
</div>
<div class="entry">
<h2>Optimise Your Selectors</h2>
<p>
jQuery is pretty chill. It can do pretty much everything but make you coffee, and I hear that's in the roadmap for 2.0. One thing you have to be careful about is abusing the power that is the <a href="http://sizzlejs.com/" target="_blank">sizzleJS</a> selector engine.
There are two strategies to overcome this: <em>caching the selectors results</em> and <em>using efficient selectors</em>.
</p>
<h3>Caching Selector Results</h3>
<p>
Do a costly DOM query every time you want to change something, or store a reference to the element? Pretty clear choice.
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
// before
$(".quote a").bind("click", doStuff); // DOM query eww
// now
$(".quote a").addClass("quoteLink"); // DOM query eww
// later
$(".quote a").fadeIn("slow"); // DOM query eww
]]></script>
<p>
Ignoring chaining, this is better:
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
// before
var $quoteLinks = $(".quote a"); // the only DOM query
$quoteLinks.bind("click", doStuff);
// now
$quoteLinks.addClass("quoteLink");
// later
$quoteLinks.fadeIn("slow");
]]></script>
<br />
<h3>Using Efficient Selectors</h3>
<p>
So jQuery/sizzleJS can use CSS3 selectors like a boss, but what's the real cost? Behind the scenes the browser is hopefully using <code>document.querySelector()</code>, but there's also a fair chance it will be breaking down your selector string and querying the DOM manually.
</p>
<script type="syntaxhighlighter" class="brush: js; toolbar: false; gutter: false;"><![CDATA[
// an ID search is the quickest possible query, then it just takes a list of the childNodes and matches the class
$("#quoteList").children(".quotes");
// looks for the "foo" class only in the pre-defined bar element
$(".foo",bar);
]]></script>
</div>
<div class="entry">
<h2>A ‘for’ Loop is Always Quicker Than a ‘each()’ Loop</h2>
<p>
No matter what happens in the next few years of browser development, a native <code>for</code> loop will always be quicker than a jQuery <code>$.each()</code> loop.
When you think of what jQuery really is (a library wrapped around native JS functions) you begin to realise that the native underlying JavaScript is always going to be quicker. It's a tradeoff of run speed versus authoring speed.
</p>
<p>
It is vital that a native <code>for</code> loop is always used for performance critical functions that could fire potentially hundreds of times per second. Examples include:
<ul>
<li>Mouse movement</li>
<li>Timer intervals</li>
<li>Loops within loops</li>
</ul>
</p>
</div>
<h1>CSS</h1>
<div class="entry">
<h2>Whitespacing</h2>
<p>
Whitespacing of CSS can be difficult as we chop and change between single and multi line CSS arguments. I'm not going to get into that.
</p>
<h3>Proper Spacing</h3>
<script type="syntaxhighlighter" class="brush: css; toolbar: false; gutter: false;"><![CDATA[
/* BAD */
.selector {display:none;background:#ff0000;color:#000000;}
/* GOOD - SINGLE LINE */
.selector { display: none; background: #ff0000; color: #000000; }
/* GOOD - MULTI-LINE */
.selector {
display: none;
background: #ff0000;
color: #000000;
}
]]></script>
<h3>Same Line Braces</h3>
<script type="syntaxhighlighter" class="brush: css; toolbar: false; gutter: false;"><![CDATA[
.selector {
display: none;
background: #ff0000;
color: #000000;
}
]]></script>
<h3>Indenting Child Elements</h3>
<p>
Purely optional, and personally only employed when in a document with single line declarations.
</p>
<script type="syntaxhighlighter" class="brush: css; toolbar: false; gutter: false;"><![CDATA[
.selector { display: none; background: #ff0000; color: #000000; }
.selector a { text-decoration: none; }
.selector span { font-weight: bold; }
]]></script>
<h3>Grouping & Indenting Vendor Prefixes</h3>
<script type="syntaxhighlighter" class="brush: css; toolbar: false; gutter: false;"><![CDATA[
.selector {
background: #FFF; border: 1px solid #000; color: #EAEAEA;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
]]></script>
</div>