I fetch data from Google's AdWords website which has multiple elements with the same id
.
Could you please explain why the following 3 queries doesn't result with the same answer (2)?
Live Demo
HTML:
<div> <span id="a">1</span> <span id="a">2</span> <span>3</span> </div>
JS:
$(function() { var w = $("div"); console.log($("#a").length); // 1 - Why? console.log($("body #a").length); // 2 console.log($("#a", w).length); // 2 });
Answer. As HTML and CSS are designed to be very fault tolerant, most browsers will in fact apply the specified styles to all elements given the same id. However, this is considered bad practice as it defies the W3C spec. Applying the same id to multiple elements is invalid HTML and should be avoided.
The HTML id attribute is used to specify a unique id for an HTML element. You cannot have more than one element with the same id in an HTML document.
As per the W3c spec, id attributes "must be unique within a document". That's the whole point of a unique identifier, and is why you don't have DOM methods to get multiple elements with the same ID (since the latter doesn't make any sense).
Classes are not uniqueYou can use the same class on multiple elements.
Having 2 elements with the same ID is not valid html according to the W3C specification.
When your CSS selector only has an ID selector (and is not used on a specific context), jQuery uses the native document.getElementById
method, which returns only the first element with that ID.
However, in the other two instances, jQuery relies on the Sizzle selector engine (or querySelectorAll
, if available), which apparently selects both elements. Results may vary on a per browser basis.
However, you should never have two elements on the same page with the same ID. If you need it for your CSS, use a class instead.
If you absolutely must select by duplicate ID, use an attribute selector:
$('[id="a"]');
Take a look at the fiddle: http://jsfiddle.net/P2j3f/2/
Note: if possible, you should qualify that selector with a tag selector, like this:
$('span[id="a"]');
There should only be one element with a given id. If you're stuck with that situation, see the 2nd half of my answer for options.
How a browser behaves when you have multiple elements with the same id (illegal HTML) is not defined by specification. You could test all the browsers and find out how they behave, but it's unwise to use this configuration or rely on any particular behavior.
Use classes if you want multiple objects to have the same identifier.
<div> <span class="a">1</span> <span class="a">2</span> <span>3</span> </div> $(function() { var w = $("div"); console.log($(".a").length); // 2 console.log($("body .a").length); // 2 console.log($(".a", w).length); // 2 });
If you want to reliably look at elements with IDs that are the same because you can't fix the document, then you will have to do your own iteration as you cannot rely on any of the built in DOM functions.
You could do so like this:
function findMultiID(id) { var results = []; var children = $("div").get(0).children; for (var i = 0; i < children.length; i++) { if (children[i].id == id) { results.push(children[i]); } } return(results); }
Or, using jQuery:
$("div *").filter(function() {return(this.id == "a");});
jQuery working example: http://jsfiddle.net/jfriend00/XY2tX/.
As to Why you get different results, that would have to do with the internal implementation of whatever piece of code was carrying out the actual selector operation. In jQuery, you could study the code to find out what any given version was doing, but since this is illegal HTML, there is no guarantee that it will stay the same over time. From what I've seen in jQuery, it first checks to see if the selector is a simple id like #a
and if so, just used document.getElementById("a")
. If the selector is more complex than that and querySelectorAll()
exists, jQuery will often pass the selector off to the built in browser function which will have an implementation specific to that browser. If querySelectorAll()
does not exist, then it will use the Sizzle selector engine to manually find the selector which will have it's own implementation. So, you can have at least three different implementations all in the same browser family depending upon the exact selector and how new the browser is. Then, individual browsers will all have their own querySelectorAll()
implementations. If you want to reliably deal with this situation, you will probably have to use your own iteration code as I've illustrated above.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With