Mahn
Mahn

Reputation: 16603

HTML DOMs, ids vs no ids?

Provided you have a container div with hundreds of very simple children elements such as the following:

<div id="stuffContainer" class="item-container">
    <div class="single-item"></div>
    <div class="single-item"></div>
    <div class="single-item"></div>
    <div class="single-item"></div>
    <div class="single-item"></div>
    <div class="single-item"></div>
    [...]
</div>

Would including an unique id for each single element harm (client) performance in any (meaningful) way, be it rendering, javascript or memory wise?

Why I'm asking: I may need from time to time to reference specific items, and I'm trying to figure out whether I should precalculate in advance which items I will need to select, giving ids to them and leaving the rest out, or just assigning ids to all of them, which would make the process more straight forward but I wonder if this may be an overkill somehow.

Bonus points (if I could actually give them) if someone can talk about how this is handled by modern browsers and why it would/would not make a difference in terms of how browsers render and manage the DOM.

Upvotes: 5

Views: 341

Answers (5)

BoltClock
BoltClock

Reputation: 724592

At the very most, I'm guessing that the basic few things a browser would do is assign the ID as a property to each element when building the DOM structure, as well as store the IDs in a hash table to facilitate things like #id selectors, document.getElementById() and idref lookups later. I don't think this is going to cause even a slight dent in observed performance or memory usage, as hash tables and the DOM are designed to be very well-optimized.

That said, if IDs aren't needed on your elements at all, then there quite simply is no point in assigning them IDs; you're going to end up with a whole lot of markup bloat instead. As Dan Davies Brackett mentions, that will obviously cause a slowdown since it depends on the client connection.

If you can afford to reference these elements using CSS selectors, you can always use :nth-child() to look up specific children. If you need to support older browsers, there's always a CSS2 solution. See these questions:

Upvotes: 3

Erik  Reppen
Erik Reppen

Reputation: 4645

The original Q isn't very specific about contents/purpose and there should be variation, depending, IMO. I definitely disagree with the current accepted answer on one point. Looping through and attaching new IDs to a ton of HTML that's already rendered could cause massive amounts of reflow calculation which could get ugly depending on what 'stuffContainer' represents.

Build With IDs First From Server or Inject as Single Block on Client-Side if You Must

As a general rule, avoid hitting the DOM with changes repeatedly if you can avoid it. IDs built beforehand on the server is pretty negligible as far as the browser loading the page, IMO. Sure, it's a larger, and consequently slower hash-table but if we're talking hundreds and not tens of thousands I seriously doubt you're going to notice.

A more efficient client-side approach in the case of something like a select list built from data would be to build as a string first, with IDs and all, and then assign to innerHTML of a container or if like some of my js chat colleagues, you have a bizarre hang-up about innerHTML in every possible use-case even though it's in the spec now, at the very least build and append to a document fragment first. and then append that to your container.

Data-Attributes or Classes Over IDs

IMO, the smell-factor isn't so much about performance but rather HTML bloat and creating an ID dependency where none is needed, thereby blocking something else that might find a custom ID on one of your single-item divs useful. IDs are definitely the ideal way to narrow down an element look-up in JavaScript but in cases of containers with contents you'll get more flexibility out of ID'd containers than ID'ing every child item. The performance gain of one-stepping vs. two-stepping isn't worth the flexibility cost of applying generic IDs to elements.

As an alternative you can use classes with unique values or the data attribute, e.g. 'data-itemId="0"'. For smaller sets of HTML like a custom select list where IDs are connected to some server-side indexing system for ease of updating data I would tend to favor this highly visible approach as it makes it easier to understand the architecture, but it adds a lot of needless attributes to track in scenarios where hundreds to thousands of items might be involved.

Or Ideally (in most cases), Event Delegation

Most ideally, IMO, you avoid additional attributes altogether in cases where you only care about the child single-item element you're clicking and not what it's 'ID' is or the order those single-item containers will remain static and you can safely assume the positions are the effective IDs. Or another scenario where this might work with a non-static single-item set is if you've got single-item data in an array of objects that gets shuffled and then used to build and replace HTML on user-initiated sorts that will always tie order of the HTML to other data-tracking dependencies.

The non-Jquery approach (untested):

var myContainer = document.getElementById('stuffContainer');
//ignore following indent goof

    myContainer.addEventListener('click', function(e){
        var
            singleItem,
            elementOriginallyClicked = singleItem = e.target,
            stuffContainer = this;

        //anything clicked inside myContainer will trigger a click event on myContainer
        //the original element clicked is e.target
        //google 'event bubbling javascript' or 'event delegation javascript' for more info

        //climb parentNodes until we get to a single-item node
        //unless it's already single-item that was originally clicked
        while( !singleItem.className.match(/[=\s'"]single-item[\s'"]/g) ){
            singleItem = singleItem.parentNode;
        }

        //You now have a reference to the element you care about

        //If you want the index:

        //Get the singleItem's parent's childNodes collection and convert to array
        //then use indexOf (MDN has normalizer for IE<=8) to get the index of the single-item

        var childArray = Array.prototype.slice.apply(stuffContainer.childNodes,[0]),
        thisIndex = childArray.indexOf(singleItem);

        doSomethingWithIndex(thisIndex);
        //or 
        //doSomethingWithDOMObject(singleItem);

    } );

Or simple JQuery delegation style (also, untested):

$('#someContainer').on('click','.single-item', function(){
    var $_singleItem = $(this), //jq handles the bubble to the interesting node for you
    thisIndex = $_singleItem.index(); //also getting index relative to parent

    doSomethingWithIndex(thisIndex);
    //or
    //doSomethingWithJQObject($_thisItem);
} );

Upvotes: 2

dash
dash

Reputation: 21

Using id's on everything would be a bit overkill in this case. I understand where you are coming from, but if you use a language like jQuery, selecting the children would be easy considering the structure. Here is an example of how you might know which one of the div's was clicked:

$('.single-item').click(function()
{
    var yourClickedDiv = $(this);
    // execute the rest of your code here
});

This is just a small example, but as you can see, you are able to access each div for whatever you need to do. This will keep the html file less cluttered from excessive id tags, along with keeping your file size a little bit smaller (not to mention save you the headache from generating every unique id).

Upvotes: 0

Dan Davies Brackett
Dan Davies Brackett

Reputation: 10081

As BoltClock implies, the answer to most performance questions is 'measure it!'. That said, you missed one potential axis for measurement: download size. Adding ID attributes to more elements than is necessary will add to your byte weight, not least because the elements are required to be unique (which means they won't zip as well as non-unique attributes might).

Upvotes: 2

jeff
jeff

Reputation: 8348

There are no significant performance degradations from using id attributes, even when used hundreds of times. Although it would be slightly faster to hand-pick the elements you need to uniquely identify, in my opinion the performance improvement would not justify the extra time required to do so.

That being said, I'm not sure id attributes are even required in this case. If you were to use jQuery, you could select the fourth element, for example, using the following code:

$('.single-item').eq(3);

Upvotes: 1

Related Questions