[ jump directly to the list ]

While the sentiment of youmightnotneedjquery is great, developers should be aware that ditching libraries, like jQuery, can easily require large amounts of research on their end to avoid bugs (even in modern browsers). The snippets provided by youmightnotneedjquery are a starting point but hardly scratch the surface of being a solid robust replacement to jQuery.

The great thing about an established library, like jQuery, is it’s hammered on by
lots of talented people, transparently improved, and refined by the community.

Concerned over file size? When it comes to page load time, count of HTTP requests (and placement) matter far more than total JS size. And heck, jQuery 1.9.x and 2.x allow custom builds, so you can minimize what of jQuery you end up shipping.


This line from
youmightnotneedjquery is worth repeating…

 “At the very least, make sure you know what jQuery is doing for you, and what it's not.”

~ John-David Dalton, Paul Irish

Feb 6, 2014

Document history:

  • 2014 Jan 30: Rick Waldron (TC39) compiled a list of all the browser bug workarounds in jQuery’s core source.
  • 2014 Feb 2: Boris Zbarsky (Firefox engineer) looked through and annotated the items.
  • 2014 Feb 6: This cleanup and comment from John-David Dalton (Microsoft) & Paul Irish (Chrome)
  • 2015 Jan 8: Paul Irish added a note for how to investigate current workarounds in modern jQuery source
  • 2015 April 20: Paul Irish edited the intro and pasted in all new workarounds. John Resig updated the workaround count.

List of browser-specific workarounds that jQuery addresses

Update April 2015:

You can now grep the jQuery source for their browser workarounds (noted by “// Support:”) :

curl -L https://code.jquery.com/jquery-git2.js | grep -A 5 -n Support:

or:

curl -L https://code.jquery.com/jquery-git2.js | grep -n Support: | wc -l

Currently 104 documented workarounds in jQuery 2.x.

Workarounds as of April 2015

// line 40:
// Support: Firefox 18+
// Can't be in strict mode, several libs including ASP.NET trace
// the stack via arguments.caller.callee and Firefox dies if
// you try to trace through "use strict" call chains. (#13335)
//
var arr = [];


// line 77:
        
// Support: Android<4.1
        
// Make sure we trim BOM and NBSP
        rtrim
= /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,

        
// Matches dashed string for camelizing
        rmsPrefix
= /^-ms-/,


// line 298:
                
// Support: Android<4.0 (functionish RegExp)
                
return typeof obj === "object" || typeof obj === "function" ?
                        class2type
[ toString.call(obj) ] || "object" :
                        
typeof obj;
        
},



// line 313:
        
// Support: IE9-11+
        
// Microsoft forgot to hump their vendor prefix (#9572)
        camelCase
: function( string ) {
                
return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
        
},



// line 345:
        
// Support: Android<4.1
        trim
: function( text ) {
                
return text == null ?
                        
"" :
                        
( text + "" ).replace( rtrim, "" );
        
},


// line 374:
        
// Support: Android<4.1, PhantomJS<2
        
// push.apply(_, arraylike) throws on ancient WebKit
        merge
: function( first, second ) {
                
var len = +second.length,
                        j
= 0,
                        i
= first.length;


// line 647:
                
// Support: Firefox<24
                
// Workaround erroneous numeric interpretation of +"0x"
                
return high !== high || escapedWhitespace ?
                        escaped
:
                        high
< 0 ?
                                
// BMP codepoint


// line 672:
        
// Support: Android<4.0
        
// Detect silently failing push.apply
        arr
[ preferredDoc.childNodes.length ].nodeType;
} catch ( e ) {
        push
= { apply: arr.length ?



// line 683:
                
// Support: IE<9
                
// Otherwise append directly
                
function( target, els ) {
                        
var j = target.length,
                                i
= 0;
                        
// Can't trust NodeList.length


// line 732:
                                
// Support: IE, Opera, Webkit
                                
// TODO: identify versions
                                
// getElementById can match elements by name instead of ID
                                
if ( elem.id === m ) {
                                        results
.push( elem );
                                        
return results;


// line 746:
                        
// Support: IE, Opera, Webkit
                        
// TODO: identify versions
                        
// getElementById can match elements by name instead of ID
                        
if ( newContext && (elem = newContext.getElementById( m )) &&
                                contains
( context, elem ) &&
                                elem
.id === m ) {


// line 783:
        
// Support: IE <=8
        
// Exclude object elements
        
} else if ( context.nodeName.toLowerCase() !== "object" ) {

                
// Capture the context ID, setting it first if necessary
                
if ( (nid = context.getAttribute( "id" )) ) {


// line 1008:
        
// Support: IE 9 - 11
        
// Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
        
// Limit the fix to IE with document.documentMode and IE >=9 with document.defaultView
        
if ( document.documentMode && (parent = document.defaultView) && parent.top !== parent ) {
                
// Support: IE 11
                
if ( parent.addEventListener ) {
                        parent
.addEventListener( "unload", unloadHandler, false );

                
// Support: IE 9 - 10 only
                
} else if ( parent.attachEvent ) {
                        parent
.attachEvent( "onunload", unloadHandler );
                
}
        
}



// line 1025:
        
// Support: IE<8
        
// Verify that getAttribute really returns attributes and not properties
        
// (excepting IE8 booleans)
        support
.attributes = assert(function( div ) {
                div
.className = "i";
                
return !div.getAttribute("className");


// line 1042:
        
// Support: IE<9
        support
.getElementsByClassName = rnative.test( document.getElementsByClassName );

        
// Support: IE<10
        
// Check if getElementById returns elements by name
        
// The broken getElementById methods don't pick up programatically-set names,
        
// so use a roundabout getElementsByName test
        support
.getById = assert(function( div ) {
                docElem
.appendChild( div ).id = expando;


// line 1069:
                
// Support: IE6/7
                
// getElementById is not reliable as a find shortcut
                
delete Expr.find["ID"];

                Expr
.filter["ID"] =  function( id ) {
                        
var attrId = id.replace( runescape, funescape );


// line 1150:
                        
// Support: IE8, Opera 11-12.16
                        
// Nothing should be selected when empty strings follow ^= or $= or *=
                        
// The test attribute must be unknown in Opera but "safe" for WinRT
                        
// http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
                        
if ( div.querySelectorAll("[msallowcapture^='']").length ) {
                                rbuggyQSA
.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );


// line 1158:
                        
// Support: IE8
                        
// Boolean attributes and "value" are not treated correctly
                        
if ( !div.querySelectorAll("[selected]").length ) {
                                rbuggyQSA
.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
                        
}



// line 1164:
                        
// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
                        
if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
                                rbuggyQSA
.push("~=");
                        
}

                        
// Webkit/Opera - :checked should return selected option elements


// line 1176:
                        
// Support: Safari 8+, iOS 8+
                        
// https://bugs.webkit.org/show_bug.cgi?id=136851
                        
// In-page `selector#id sibing-combinator selector` fails
                        
if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) {
                                rbuggyQSA
.push(".#.+[+~]");
                        
}


// line 1185:
                        
// Support: Windows 8 Native Apps
                        
// The type and name attributes are restricted during .innerHTML assignment
                        
var input = document.createElement("input");
                        
input.setAttribute( "type", "hidden" );
                        div
.appendChild( input ).setAttribute( "name", "D" );



// line 1191:
                        
// Support: IE8
                        
// Enforce case-sensitivity of name attribute
                        
if ( div.querySelectorAll("[name=d]").length ) {
                                rbuggyQSA
.push( "name" + whitespace + "*[*^$|!~]?=" );
                        
}



// line 1687:
                                
// Support: IE <9 only
                                
// Defend against cloned attroperties (jQuery gh-1709)
                                uniqueCache
= outerCache[ node.uniqueID ] ||
                                        
(outerCache[ node.uniqueID ] = {});

                                cache
= uniqueCache[ type ] || [];


// line 1716:
                                        
// Support: IE <9 only
                                        
// Defend against cloned attroperties (jQuery gh-1709)
                
                        uniqueCache = outerCache[ node.uniqueID ] ||
                                                
(outerCache[ node.uniqueID ] = {});

                                        cache
= uniqueCache[ type ] || [];


// line 1742:
                                        
// Support: IE <9 only
                                        
// Defend against cloned attroperties (jQuery gh-1709)
                                        uniqueCache
= outerCache[ node.uniqueID ] ||
                                                
(outerCache[ node.uniqueID ] = {});

                                        uniqueCache
[ type ] = [ dirruns, diff ];


// line 1953:
                
// Support: IE<8
                
// New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
                
( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
},

                
// Position-in-collection


// line 2131:
                        
// Support: IE <9 only
                        
// Defend against cloned attroperties (jQuery gh-1709)
                        uniqueCache
= outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});

                        
if ( (oldCache = uniqueCache[ dir ]) &&
                                oldCache
[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {


// line 2371:
        
// Support: IE<9, Safari
        
// Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
        
for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
                
if ( byElement && elem ) {
                        j
= 0;
                        
if ( !context && elem.ownerDocument !== document ) {


// line 2576:
// Support: Chrome 14-35+
// Always assume duplicates if they aren't passed to the comparison function
support
.detectDuplicates = !!hasDuplicate;

// Initialize against the default document
setDocument
();


// line 2583:
// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
// Detached nodes confoundingly follow *each other*
support
.sortDetached = assert(function( div1 ) {
        
// Should return 1, but returns 4 (following)
        
return div1.compareDocumentPosition( document.createElement("div") ) & 1;
});


// line 2590:
// Support: IE<8
// Prevent attribute/property "interpolation"
// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
if ( !assert(function( div ) {
        div
.innerHTML = "<a href='#'></a>";
        
return div.firstChild.getAttribute("href") === "#" ;


// line 2604:
// Support: IE<9
// Use defaultValue in place of getAttribute("value")
if ( !support.attributes || !assert(function( div ) {
        div
.innerHTML = "<input/>";
        div
.firstChild.setAttribute( "value", "" );
        
return div.firstChild.getAttribute( "value" ) === "";


// line 2618:
// Support: IE<9
// Use getAttributeNode to fetch booleans when getAttribute lies
if ( !assert(function( div ) {
        
return div.getAttribute("disabled") == null;
}) ) {
        addHandle
( booleans, function( elem, name, isXML ) {


// line 3331:
                
// Support: Promises/A+ section 2.3.3.3.3
                
// https://promisesaplus.com/#point-59
                
// Ignore double-resolution attempts
                
if ( depth < maxDepth ) {
                        
return;
                
}


// line 3340:
                
// Support: Promises/A+ section 2.3.1
                
// https://promisesaplus.com/#point-48
                
if ( returned === deferred.promise() ) {
                        
throw new TypeError( "Thenable self-resolution" );
                
}



// line 3346:
                
// Support: Promises/A+ sections 2.3.3.1, 3.5
                
// https://promisesaplus.com/#point-54
                
// https://promisesaplus.com/#point-75
                
// Retrieve `then` only once
                then
= returned &&



// line 3352:
                        
// Support: Promises/A+ section 2.3.4
                        
// https://promisesaplus.com/#point-64
                        
// Only check objects and functions for thenability
                        
( typeof returned === "object" ||
                                
typeof returned === "function" ) &&
                        returned
.then;


// line 3408:
                                
// Support: Promises/A+ section 2.3.3.3.4.1
                                
// https://promisesaplus.com/#point-61
                                
// Ignore post-resolution exceptions
                                
if ( depth + 1 >= maxDepth ) {
                                        
// Only substitue handlers pass on context
                                        
// and multiple values (non-spec behavior)


// line 3425:
                        
// Support: Promises/A+ section 2.3.3.3.1
                        
// https://promisesaplus.com/#point-57
                        
// Re-resolve promises immediately to dodge false rejection from
                        
// subsequent errors
                        
if ( depth ) {
                                process
();


// line 4015:
                
// Support: IE11+
                
// The attrs elements can be null (#14894)
                
if ( attrs[ i ] ) {
                        name
= attrs[ i ].name;
                        
if ( name.indexOf( "data-" ) === 0 ) {
                                name
= jQuery.camelCase( name.slice(5) );


// line 4315:
        
// Support: Android 4.0-4.3
        
// Check state lost if the name is set (#11217)
        
// Support: Windows Web Apps (WWA)
        
// `name` and `type` must use .setAttribute for WWA (#14901)
        
input.setAttribute( "type", "radio" );
        
input.setAttribute( "checked", "checked" );
        
input.setAttribute( "name", "t" );



// line 4325:
        
// Support: Android<4.2
        
// Older WebKit doesn't clone checked state correctly in fragments
        support
.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;

        
// Support: IE<=11+
        
// Make sure textarea (and checkbox) defaultValue is properly cloned
        div
.innerHTML = "<textarea>x</textarea>";
        support
.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
})();



// line 4868:
                
// Support: Safari 6.0+
                
// Target should not be a text node (#504, #13143)
                
if ( event.target.nodeType === 3 ) {
                        event
.target = event.target.parentNode;
                
}



// line 4919:
                                
// Support: Firefox 20+
                                
// Firefox doesn't alert if the returnValue field is not set.
                                
if ( event.result !== undefined && event.originalEvent ) {
                                        event
.originalEvent.returnValue = event.result;
                                
}
                        
}


// line 4973:
                                
// Support: Android<4.0
                                src
.returnValue === false ?
                        returnTrue
:
                        returnFalse
;

        
// Event type


// line 5038:
// Support: Safari<7.0
// Safari doesn't support mouseenter/mouseleave at all.
//
// Support: Chrome 34+
// Mouseenter doesn't perform while left mouse button is pressed
// (and initiated outside the observed element)
// https://code.google.com/p/chromium/issues/detail?id=333868
jQuery
.each({
        mouseenter
: "mouseover",


// line 5073:
// Support: Firefox, Chrome, Safari
// Create "bubbling" focus and blur events
if ( !support.focusinBubbles ) {
        jQuery
.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {

                
// Attach a single capturing handler on the document while someone wants focusin/focusout


// line 5229:
                
// Support: IE9
                option
: [ 1, "<select multiple='multiple'>", "</select>" ],

                thead
: [ 1, "<table>", "</table>" ],

                
// Some of the following wrappers are not fully defined, because


// line 5238:
                
// Support: Android 2.3
                
// Android browser doesn't auto-insert colgroup
                col
: [ 2, "<table><colgroup>", "</colgroup></table>" ],

                
// Auto-insert "tbody" element
                tr
: [ 2, "<table>", "</table>" ],


// line 5251:
// Support: IE9
wrapMap
.optgroup = wrapMap.option;

wrapMap
.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
wrapMap
.th = wrapMap.td;



// line 5331:
        
// Support: IE9-11+
        
// Use typeof to avoid zero-argument method invocation on host objects (#15151)
        
var ret = typeof context.getElementsByTagName !== "undefined" ?
                        context
.getElementsByTagName( tag || "*" ) :
                        
typeof context.querySelectorAll !== "undefined" ?
                                context
.querySelectorAll( tag || "*" ) :


// line 5415:
                                        
// Support: Android<4.1, PhantomJS<2
                                        
// push.apply(_, arraylike) throws on ancient WebKit
                                        jQuery
.merge( nodes, elem.nodeType ? [ elem ] : elem );

                                
// Convert non-html into a text node
                                
} else if ( !rhtml.test( elem ) ) {


// line 5438:
                                        
// Support: Android<4.1, PhantomJS<2
                                        
// push.apply(_, arraylike) throws on ancient WebKit
                                        jQuery
.merge( nodes, tmp.childNodes );

                                        
// Remember the top-level container
                                        tmp
= fragment.firstChild;


// line 5716:
                                                        
// Support: Android<4.1, PhantomJS<2
                                                        
// push.apply(_, arraylike) throws on ancient WebKit
                                                        jQuery
.merge( scripts, getAll( node, "script" ) );
                                                
}
                                        
}



// line 5774:
                        
// Support: Android<4.1, PhantomJS<2
                        
// .get() because push.apply(_, arraylike) throws on ancient WebKit
                        push
.apply( ret, elems.get() );
                
}

                
return this.pushStack( ret );


// line 5787:
                
// Support: Firefox
                
// We have to pre-define these values for FF (#10227)
                HTML
: "block",
                BODY
: "block"
        
};



// line 5832:
                        
// Support: IE
                        doc
.write();
                        doc
.close();

                        display
= actualDisplay( nodeName, doc );
                        iframe
.detach();


// line 5851:
                
// Support: IE<=11+, Firefox<=30+ (#15098, #14150)
                
// IE throws on elements created in popups
                
// FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
                
if ( elem.ownerDocument.defaultView.opener ) {
                        
return elem.ownerDocument.defaultView.getComputedStyle( elem, null );
                
}


// line 5895:
        
// Support: IE9-11+
        
// Style of cloned element affects source element cloned (#8908)
        div
.style.backgroundClip = "content-box";
        div
.cloneNode( true ).style.backgroundClip = "";
        support
.clearCloneStyle = div.style.backgroundClip === "content-box";



// line 5909:
                        
// Support: Android 2.3
                        
// Vendor-prefix box-sizing
                        
"-webkit-box-sizing:border-box;box-sizing:border-box;" +
                        
"display:block;position:absolute;" +
                        
"margin:0;margin-top:1%;margin-right:50%;" +
                        
"border:1px;padding:1px;" +


// line 5942:
                        
// Support: Android 4.0-4.3
                        
// We're checking for boxSizingReliableVal here instead of pixelMarginRightVal
                        
// since that compresses better and they're computed together anyway.
                        
if ( boxSizingReliableVal == null ) {
                                computeStyleTests
();
                        
}


// line 5952:
                        
// Support: Android 2.3
                        
// Check if div with explicit width and no margin-right incorrectly
                        
// gets computed margin-right based on width of container. (#3333)
                        
// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
                        
// This support function is only executed once so no memoizing is needed.
                        
var ret,


// line 5962:
                                
// Support: Android 2.3
                                
// Vendor-prefix box-sizing
                                
"-webkit-box-sizing:content-box;box-sizing:content-box;" +
                                
"display:block;margin:0;border:0;padding:0";
                        marginDiv
.style.marginRight = marginDiv.style.width = "0";
                        div
.style.width = "1px";


// line 5987:
        
// Support: IE9
        
// getPropertyValue is only needed for .css('filter') (#12537)
        
if ( computed ) {
                ret
= computed.getPropertyValue( name ) || computed[ name ];
        
}



// line 6023:
                
// Support: IE9-11+
                
// IE returns zIndex value as an integer.
                ret
+ "" :
                ret
;
}



// line 6315:
                        
// Support: IE9-11+
                        
// background-* props affect original clone's values
                        
if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
                                style
[ name ] = "inherit";
                        
}



// line 6407:
// Support: Android 2.3
jQuery
.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
        
function( elem, computed ) {
                
if ( computed ) {
                        
return swap( elem, { "display": "inline-block" },
                                curCSS
, [ elem, "marginRight" ] );


// line 6576:
// Support: IE9
// Panic based approach to setting things on disconnected nodes
Tween
.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
        set
: function( tween ) {
                
if ( tween.elem.nodeType && tween.elem.parentNode ) {
                        tween
.elem[ tween.prop ] = tween.now;


// line 6852:
                                
// Support: Android 2.3
                                
// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)
                                temp
= remaining / animation.duration || 0,
                                percent
= 1 - temp,
                                
index = 0,
                                
length = animation.tweens.length;


// line 7235:
        
// Support: Android<4.4
        
// Default value for a checkbox should be "on"
        support
.checkOn = input.value !== "";

        
// Support: IE<=11+
        
// Must access selectedIndex to make default options select
        support
.optSelected = opt.selected;

        
// Support: Android<=2.3
        
// Options inside disabled selects are incorrectly marked as disabled
        select
.disabled = true;
        support
.optDisabled = !opt.disabled;

        
// Support: IE<=11+
        
// An input loses its value after becoming a radio
        
input = document.createElement( "input" );
        
input.value = "t";
        
input.type = "radio";
        support
.radioValue = input.value === "t";


// line 7712:
                                
// Support: IE<11
                                
// option.value not trimmed (#14858)
                                
return jQuery.trim( elem.value );
                        
}
                
},
                select
: {


// line 7848:
// Support: Android 2.3
// Workaround failure to string-cast null input
jQuery
.parseJSON = function( data ) {
        
return JSON.parse( data + "" );
};



// line 7862:
        
// Support: IE9
        
try {
                xml
= ( new window.DOMParser() ).parseFromString( data, "text/xml" );
        
} catch ( e ) {
                xml
= undefined;
        
}


// line 8371:
                        
// Support: IE8-11+
                        
// IE throws exception if url is malformed, e.g. http://example.com:80x/
                        
try {
                                urlAnchor
.href = s.url;
                                
// Support: IE8-11+
                                
// Anchor's host property isn't correctly set when s.url is relative
                                urlAnchor
.href = urlAnchor.href;
                                s
.crossDomain = originAnchor.protocol + "//" + originAnchor.host !==
                                        urlAnchor
.protocol + "//" + urlAnchor.host;
                        
} catch ( e ) {


// line 8883:
                
// Support: IE9
                
// #1450: sometimes IE returns 1223 when it should be 204
                
1223: 204
        
},
        xhrSupported
= jQuery.ajaxSettings.xhr();



// line 8889:
// Support: IE9
// Open requests must be manually aborted on unload (#5280)
// See https://support.microsoft.com/kb/2856746 for more info
if ( window.attachEvent ) {
        window
.attachEvent( "onunload", function() {
                
for ( var key in xhrCallbacks ) {


// line 8967:
                                        
// Support: IE9
                                        
// Accessing binary-data responseText throws an exception
                                        
// (#11426)
                                        
typeof xhr.responseText === "string" ? {
                                                text
: xhr.responseText
                                        
} : undefined,


// line 9478:
// Support: Safari<7+, Chrome<37+
// Add the top/left cssHooks using jQuery.fn.position
// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
// Blink bug: https://code.google.com/p/chromium/issues/detail?id=229280
// getComputedStyle returns percent when specified for top/left/bottom/right;
// rather than make the css module depend on the offset module, just check for it here

Workarounds from Feb 2014

  • L40 -- Firefox 18+
  • L255 -- IE < 9
  • L282 -- Firefox <20
  • L312 --  Android < 4, iOS < 6 / old Chrome/Safari issue
  • L692 -- Firefox

  • L3483 -- WebKit issue, fixed in recent WebKit?
  • Android 2.3 Support
  • L3484 -- Same as L3483
  • L3520 -- WebKit issue, fixed in recent WebKit?
  • Android 2.3 Support
  • Android 2.3 Support
  • L3980 -- WebKit issue, fixed in recent WebKit?
  • Android 2.3 Support
  • L3985 -- IE >=9 issue
  • L4399 -- Firefox making the mistake of following the DOM2 Events spec
  • Android 2.3 Support
  • In addition to API surface, jQuery 2.x must provide the exact same semantics as jQuery 1.x, which means we’re forced to carry the burden of some ancient issues such as node wrapping requirements. These are the most frustrating, but thankfully minimal.
  • L4955 and L4975 -- IE >=9 issue
  • L5027 -- WebKit Qt port issue
  • L5050 -- WebKit Qt port issue
  • L5058 -- WebKit issue
  • L5303 -- WebKit issue
  • L5338 -- WebKit Qt port issue
  • L5395 -- WebKit Qt port issue
  • L5421 -- Optimization using Firefox-only experimental API
  • L5448 -- WebKit and Firefox issue
  • I wrote this several years ago and honestly don’t remember what the issue I encountered was—will reconfirm ASAP. RW
  • L5451 -- IE issue of some sort?  Not clear
  • L5481 -- IE9 issue
  • L5493 -- iOS issue
  • Needs reconfirmation
  • Android 2.3 Support
  • L5563 -- Same Firefox/Old WebKit issue as L5545
  • Android 2.3 Support
  • Android 2.3 Support
  • L5654 -- Vendor prefixes
  • Yeah, that part needs to die, but will take a few years.  :(
  • Everyone is guilty.
  • L5907 -- WebKit issue (Chrome/Safari)
  • Needs reconfirmation
  • Android 2.3 Support
  • L6156 -- IE < 11 issue
  • L6322 -- IE 9-10 issue
  • L6831 -- Android/OldWebKit issue
  • Android 2.3 Support
  • L6836 -- IE issue (all versions)
  • L6840 -- WebKit issue
  • L6845 -- IE issue (all versions)
  • L6942 -- IE< 10 issue
  • L7049 -- IE issue (old?)
  • L7084 -- classList cannot be used
  • Android 2.3 support
  • Android 2.3 Support
  • L7439 -- IE < 10 issue
  • L7489 -- IE< 9 issue
  • L7495 -- IE fallback for L7489r
  • L8332 -- Opera < 12.15 (Presto) issue
  • L8457 -- IE < 10 issue
  • L8462 -- IE < 10 issue
  • L8533 -- IE9 issue
  • L8801 -- IE issue (same origin policy?)
  • L8998 -- WebKit issue
  • L9028 -- Mobile Safari issue

Sizzle Issues

  • L709 -- Android WebKit bug (possibly fixed?)
  • Android 2.3 Support
  • Sizzle Specific
  • Sizzle Specific
  • L763 --  IE < 8/Opera/WebKit bugs
  • Sizzle Specific
  • Sizzle Specific
  • L886 -- IE6  memory leak fix
  • Sizzle Specific
  • L917 -- IE-specific API used for optimization
  • Sizzle Specific
  • L997 -- IE < 9 issue?
  • Sizzle Specific
  • Sizzle Specific
  • Sizzle Specific
  • L1029 -- IE11 removed attachEvent but old IE doesn't have addEventListener
  • Sizzle Specific
  • Sizzle Specific
  • L1064 -- Safari < 4 issue
  • Sizzle Specific
  • L1067 -- Opera < 10  issue
  • Sizzle Specific
  • Sizzle Specific
  • Sizzle Specific
  • L1149 -- IE9/Opera11.5 issue
  • Sizzle Specific
  • L1153 -- IE < 10 qSA issue
  • Sizzle Specific
  • L1164 -- IE setup for line L1176
  • Sizzle Specific
  • L1170 -- IE 8 / Opera 10-12 qSA issue
  • Sizzle Specific
  • Sizzle Specific
  • L1182 -- WebKit/Opera qSA issue
  • Sizzle Specific
  • Sizzle Specific
  • L1191 -- Windows 8 Native Apps issue
  • Sizzle Specific
  • Sizzle Specific
  • L1204 -- IE8/Firefox 3.5 qSA issue
  • Sizzle Specific
  • L1209 -- Opera < 12 qSA issue
  • Sizzle Specific
  • L1215 -- Lack of unprefixed matches()/matchesSelector() in UAs?
  • Sizzle Specific
  • L1222 -- IE 9 issue and Firefox (old?) issue
  • Sizzle Specific
  • Sizzle Specific
  • L1389 -- IE < 10 workaround for (L1286)
  • Sizzle Specific
  • Sizzle Specific
  • Sizzle Specific
  • L2316 -- IE < 9 issue, Safari issue
  • Sizzle Specific
  • L2498 -- Chrome issue, fixed in Chrome 14?
  • Sizzle Specific
  • L2505 -- WebKit issue, fixed in Chrome 27
  • Sizzle Specific
  • Sizzle Specific
  • Sizzle Specific
  • Sizzle Specific

Special Notations:

Android 2.3 Support.

Many Webkit issues may be fixed in the latest version however we're obligated to maintain support in jQuery 2.x for the code required to fix those issues as far back as 2.3 due to mobile market share.

Sizzle Specific.

Some issues that appear to be in the "jQuery source" are actually the Sizzle source that is added to the list of files concatenated together when jQuery is built. Sizzle must work the same way in all browsers as far back as IE6, but can also be omitted via a custom build, for modern (ie. qSA without bug fixes) browser support.