3

This is truly bizarre. If I use jQuery's .find() to find child elements that have data attributes during a scroll event, then scrolling the page will repeatedly add and remove an ID to the parents of those elements.

It's difficult to describe, but here's a reproducible test case: http://jsfiddle.net/8fouvx9p/

var groups = $(".group");

$(window).bind("scroll resize orientationchange", function() {
  showGroup();   
});
               
function showGroup() {
  $(groups).each(function() {
    var group = $(this),
        elements = $(group).find("[data-animation]");
  });
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="group">
    <div data-animation="test" class="test">Test</div>
    <p data-animation="test" class="test">Test</p>
    <span data-animation="test" class="test">Test</span>
</div>
<div class="group">
    <div data-animation="test" class="test">Test</div>
    <p data-animation="test" class="test">Test</p>
    <span data-animation="test" class="test">Test</span>
</div>
<div class="group">
    <div data-animation="test" class="test">Test</div>
    <p data-animation="test" class="test">Test</p>
    <span data-animation="test" class="test">Test</span>
</div>
<div class="group">
    <div data-animation="test" class="test">Test</div>
    <p data-animation="test" class="test">Test</p>
    <span data-animation="test" class="test">Test</span>
</div>
<div class="group">
    <div data-animation="test" class="test">Test</div>
    <p data-animation="test" class="test">Test</p>
    <span data-animation="test" class="test">Test</span>
</div>
<div class="group">
    <div data-animation="test" class="test">Test</div>
    <p data-animation="test" class="test">Test</p>
    <span data-animation="test" class="test">Test</span>
</div>
<div class="group">
    <div data-animation="test" class="test">Test</div>
    <p data-animation="test" class="test">Test</p>
    <span data-animation="test" class="test">Test</span>
</div>
<div class="group">
    <div data-animation="test" class="test">Test</div>
    <p data-animation="test" class="test">Test</p>
    <span data-animation="test" class="test">Test</span>
</div>
<div class="group">
    <div data-animation="test" class="test">Test</div>
    <p data-animation="test" class="test">Test</p>
    <span data-animation="test" class="test">Test</span>
</div>

Make sure the preview is small enough that there's space to scroll, then inspect one of the "test" elements and scroll up and down. You'll see that in Firefox, it adds and removes an ID of null to the test elements as you scroll:

null ID

In Safari, it happens less consistently – but when it does, the ID will start with sizzle.

If I change the .find("[data-animation]") to .find(".test"), it doesn't happen.

Given the sizzle ID that sometimes appears in Safari, I'm guessing this is due to an error in Sizzle (jQuery's selector engine) itself, and not something I'm doing incorrectly in my own code?

daGUY
  • 27,055
  • 29
  • 75
  • 119
  • is your function missing something? because i'm not seeing your screenshot in fire fox and `showGroup` is not actually doing anything to elements – PhilVarg Oct 07 '15 at 22:32
  • @PhilVarg, nope – if I view my fiddle in Firefox, I get the results in the screenshot. And yes, `showGroup()` doesn't even do anything other than select the elements, which is the whole mystery :-) – daGUY Oct 07 '15 at 22:35
  • this must be an issue with firefox 41. just updated from 39 and it didnt occur on 39, but did occur on 41.0.1. or like you mentioned an issue with jquery interacting with ff and safari. i see nothing in your code that would be doing this – PhilVarg Oct 07 '15 at 22:40
  • @PhilVarg, yeah, I'm on Firefox 41.0.1 as well. Interesting... – daGUY Oct 07 '15 at 22:46
  • Relevant: [jQuery's Sizzle selector engine can use querySelectorAll if it's available.](http://stackoverflow.com/a/11503822/4639281) –  Oct 07 '15 at 23:53
  • My main concern is, does the constant adding/removing of IDs negatively impact performance? If it's a bug in Sizzle itself I guess there's nothing I can do about it, but I'm just wondering. Unfortunately, for what I need to do, there isn't a good way to rewrite my code to avoid using data attributes. – daGUY Oct 08 '15 at 16:42
  • It's not a bug, you just can't directly pass a data attribute to `.find()`. But it actually works fine when you wrap it in a jQuery object : `group.find($("[data-animation]"));`. http://tinyurl.com/owygomz – Shikkediel Oct 08 '15 at 20:10
  • @Shikkediel, thanks! That works fine in my actual project too. Can you post that as an answer and I'll accept it? – daGUY Oct 08 '15 at 21:02
  • The only bug would be that the FireFox developer tools should not be displaying `id="null"`. No need to change the code. [See this](https://github.com/jquery/jquery/issues/2620) for a complete explanation. – John S Apr 07 '16 at 16:10

1 Answers1

3

It seems that the creation of those empty identifiers is something that happens on Firefox only. But all browsers I checked with appear to have something similar going on, be it less visible. With Chrome and Opera you can see an active change on the parent div, without any final effect as a result. With IE it's very subtle, nothing is really noticeable in the DOM tree but there is still a light flicker in the style window. Indicating that it is responding to the same thing as well.

When I dug around a bit these quotes from the jQuery documentation about the arguments that can be passed to the .find() method seemed to hold the best clue :

A string containing a selector expression to match elements against.

An element or a jQuery object to match elements against.

https://api.jquery.com/find/

I interpreted this as that you can't directly pass a data attribute but instead the approach would have to be to filter the elements themselves that contain it. The fix would then be quite simple. The culprite :

.find("[data-animation]");

And wrapping it in a jQuery object makes the functionality work :

.find($("[data-animation]"));

That actually solved the issue but the assumption was incorrect. Using a data attribute should qualify as a selector expression. The OP should feel free to accept another answer if that can provide a full explanation for the effect this query has on the parent. So far I have only noticed the following :

  • It is not just an issue with data but occurs with all attributes
  • Related to using classes, an element with an id does not get affected
  • Does not have anything to do with using the .each() loop at least
  • Probably the oddest... there is no such issue when using .children() instead

That last one is quite baffling since both methods are very similar. But scouring the documentation I did find a difference, only .find() has a selector context and this looks to be at the root of it.

Here is a strange example where the null id appears on body if the context is set to that :

Demo

And it disappears altogether when the second parameter is omitted...


A working example of the original code, including some other minor tweaks :

Pen

var groups = $('.group');

$(window).on('scroll resize orientationchange', showGroup);

function showGroup() {

  groups.each(function() {

    var group = $(this),
    elements = group.find($('[data-animation]'));
  });
}
Community
  • 1
  • 1
Shikkediel
  • 5,195
  • 16
  • 45
  • 77
  • My only question is, why isn't `"[data-animation]"` considered a string containing a selector expression? After all, `[data-animation]` is a valid CSS selector... – daGUY Oct 08 '15 at 21:53
  • A far better question than I realised. I've adapted the answer and will try to figure out what's going on *exactly*. – Shikkediel Oct 09 '15 at 01:44