3

How can you do this with jQuery, in an elegant way?

Apply z attribute (e.g.: red background) to every children of a div parent
while their position is above a given top-offset y.

I've tried in different ways, but I'm not happy with any of them...
I know there must be a short and elegant way to do it...

dolma33
  • 4,133
  • 6
  • 28
  • 48
  • Is the top position relative to the document, or the viewable portion of the document, or to the parent div? – user113716 Nov 16 '10 at 15:22
  • let's say is relative to the document, that will be simpler (in the reality, it's relative to the position of a parent's sibling) – dolma33 Nov 16 '10 at 15:27
  • So when the page scrolls, it doesn't change which elements are affected. That sound right? – user113716 Nov 16 '10 at 15:28

3 Answers3

7

Since you're saying you've tried a few ways, and you're just looking for something more elegant, I'll assume you have the offset part worked out, and I'll just go with offset myself. Modify that part as needed. For elegance, you could create a custom selector checking top offset:

$.expr[':'].above = function(obj, index, meta, stack) { 
    return $(obj).offset().top < meta[3];
}

You could then query it as such:

$('#myParentDiv').find('div:above(100)').css('background-color', 'red');

Of course this could just as well have been expressed as

$('#myParentDiv div:above(100)').css('background-color', 'red');

or, as pointed out in comments

var y = 100;
$('#myParentDiv div:above('+y+')').css('background-color', 'red');
David Hedlund
  • 128,221
  • 31
  • 203
  • 222
  • 1
    +1, I would not have thought of writing my own pseudo-selector. Cool! – Matt Ball Nov 16 '10 at 15:38
  • Fantastic! This is pure elegance! And what if I want to give to the selector a variable as argument (e.g., `var y = 100;` ... `....find('div:above(y)')...` )? – dolma33 Nov 16 '10 at 20:51
  • @dolma: that will not work, because `y` is just a character in a string. You would need to do this: `...find('div:above(' + y + ')')...` – Matt Ball Nov 16 '10 at 20:54
  • @DavidHedlund Amazing answer, can you explain to me what is the meaning of meta[3]? I am trying get the near by div around my div (like Minesweeper) – Michel Ayres Apr 18 '12 at 01:59
  • 1
    @Michel: `meta`, here, contains all the information about the pseudo selector used. in `div:above(30)` it would be an array that looks like `[":above(30)","above","","30"]`. Hence, `meta[0]` is the entire pseudo-selector being evaluated, `meta[1]` is the name of the selector only, `meta[2]` is whether double or single quotes are wrapping the value; in our case neither. `meta[3]` which is all I'm interested in, is the input parameter, which will be `"30"`. If we built a pseudo selector that said `:between(30,50)` then `meta[3]` would be `"30,50"` and we'd have to parse the string from there. – David Hedlund Apr 18 '12 at 06:33
  • @DavidHedlund Really appreciate your attention to my comment, I'm gonna try out in my little Minesweeper. Thanks =) – Michel Ayres Apr 18 '12 at 14:16
5

Something like this should get the job done:

var y = 250,
    RED = '#F00';

$('#parent > *').css('background-color', function (i, v)
{
    if ($(this).offset().top < y)
    {
        return RED;
    }
    return v;
});

The selector '#parent > *' will select all immediate children (not all descendants) of the element with id parent. I assume that's what you're looking for, since you said "apply... to every children of a div parent."

Demo: http://jsfiddle.net/mattball/87QFU/1/

Matt Ball
  • 354,903
  • 100
  • 647
  • 710
  • +1 but if you already have a jQuery object for parent you can also use parent.children() for first-level children or parent.find('*') for the entire subtree. – Jason S Nov 16 '10 at 15:31
  • Since OP is asking for the position *above* a given offset, you probably want to compare `< y` since the Y at top is 0. – David Hedlund Nov 16 '10 at 15:32
  • @Jason: you're right, but I'm not sure I see you're getting at. Selector optimization? That's not what this question is about. – Matt Ball Nov 16 '10 at 15:35
  • I really like it, but I think it still could be more efficient: in this way, I'm *testing every children*; but if the elements are _e.g._ `

    ` or `

  • `, it _could be logic_ to assume that if I have a children below `y`, the other childrens after this one will be below `y`too, so we could economize on the next tests.
  • – dolma33 Nov 16 '10 at 15:58
  • @dolma: that kind of optimization is totally up to you. For a generic implementation, however, you can't necessarily assume that. For example, you might be using a stylesheet with this rule `#parent > *:last-child { position: fixed; top: 0; }` - in which case, your optimization does not work correctly. – Matt Ball Nov 16 '10 at 16:05
  • @dolma: In general, don't worry about optimization until performance is actually a problem. – Matt Ball Nov 16 '10 at 16:10
  • @Matt: I know, I know... I'm obsessed with optimization, and this could be a problem for me, because sometimes I really can't do simple things in 5 minutes, and I find myself losing days on them... BTW, when do you think that performance becomes a real problem, in this case? Maybe when only 10 over 500 elements are above the `y`? Or with something bigger, like only 10 over 4000? Or never? – dolma33 Nov 16 '10 at 16:38
  • 2
    @dolma: in this specific case, performance is a problem when you/your boss/your client (basically, whoever you're developing for) notices that things are taking too long. Remember, when you're using jQuery, you're already taking a performance hit, but the point isn't performance - it's that **developer time is worth more than CPU time**. Let me say this again, because it **is** that imporant. **Developer time is worth more than CPU time.** jQuery saves **you** - the developer - time by allowing you to write DOM code that works across all browsers, so you can write code that is actually more... – Matt Ball Nov 16 '10 at 16:40
  • ...valuable **to the end user**, rather than spend 3 days trying to figure out why _!@#$%ing IE won't $&*(%ing obey you_. – Matt Ball Nov 16 '10 at 16:45
  • Thank you so much Matt... I'll keep it in mind everytime I'll find myself stuck while fighting for performance and perfection! – dolma33 Nov 16 '10 at 20:53