October 8, 2013

Using .on() and targeting elements with a specific ID

Brandon Durham’s Question:

I understand you can use .on() to attach a single click event to an element and then specify which child elements receive the click. So, for example:

$(this.el).on("click", "span", function () {
    alert("Bloop!");
});

I need to be a bit more specific and target selectors with a particular attribute, like this:

$(this.el).on("click", "span[data-placeholder]", function () {
    alert("Bloop!");
});

That doesn’t seem to work, though. As soon as I add the attribute it stops working. No errors, just doesn’t seem to find the elements.

Is that the expected behavior? Is there a way around it?

CLARITY

$(this.el) is just a div that contains a number of elements, some of which are <span data-placeholder="First Name"></span> tags. There could be dozens of those <span> tags and I didn’t want that many event listeners, so I thought I’d use .on() to add the click to the parent container.

You can choose to filter your spans

$('span', this.el).filter(function() {
     return $(this).hasAttr('data-placeholder');
}).on('click', function() {
   //This is for all the spans having data-placeholder
   //...
});

Or if the placeholder is set via data api:

$(this.el).filter(function() {
     return $(this).data('placeholder') != 'undefined';
}).on('click', function() {
   //This is for all the spans having data-placeholder
   //...
});

This functions above select those elements specifically, if event delegation on the OP is needed, then you can do the following:

$('span', this.el).on('click', 'span', function() {
     if($(this).data('placeholder') != 'undefined') {
         alert('bloop');
     }
});
September 18, 2012

Select recursive :last-child. Possible?

Question by Lasse Dahl Ebert

In CSS, is it possible to recursively select all :last-child from body?

Given this markup:

<body>
  <div id="_1">
    <div id="_2"></div>
  </div>
  <div id="_3">
    <div id="_4">
      <div id="_5"></div>
      <div id="_6"></div>
    </div>
  </div>
</body>

I am looking for div no. 3, 4 and 6

Another way to put it is this:

body > :last-child,
body > :last-child > :last-child,
body > :last-child > :last-child > :last-child,
body > :last-child > :last-child > :last-child > :last-child {
  /* My stuff here */
}

But obviously this is not a good approach.

Answer by BoltClock

No, unfortunately that’s just about the only way to do it without modifying the HTML.

There has been at least one request for recursive versions of the :first-child and :last-child pseudo-classes, but it doesn’t seem to have gained much favor. Notice it suggests nesting and repeating the pseudo-classes in the same way as in your question:

Currently, AFAIK, we can only match children up to some exact nesting level known in advance (3 in the example below):

.container > :first-child,
.container > :first-child > :first-child,
.container > :first-child > :first-child > :first-child {}

We cannot use just :first-child context selector since it would also select first children of blocks that are not first children themselves.

So we need a sort of recursive selector that matches not just first of last child, but recursively matches all first-most and last-most elements regardless of their nesting level.

Answer by Starx

No need to chain all the way. It would be simply like this

div:last-child {
   /* Your GREAT css */
}

Demo

Update: On that case, give the div2 a typical class and use :not() to push out of the selection

div:last-child:not(.nolist) {
    border: 1px solid red;
}

Demo

August 12, 2012

CSS selector for first element of visual (block reflow) row

Question by Kevin L.

Is there a CSS selector for the first element of every visual row of block items?
That is, imagine having 20 block elements such that they flow across multiple lines to fit in their parent container; can I select the leftmost item of each row?

It’s doable in JavaScript by looking at the top position of all of the elements, but is it possible in plain CSS?

Answer by Starx

Yes, Its possible through CSS but only if you can fix the elements in every row.

Since you haven’t provided your case, here is an example.

Suppose, your elements are stacked up in a ul and li pattern and are three lists in a row, then you can use the following css snippet.

li:first-child, li:nth-child(3n+1) {
    background: red;
}

Demo

March 27, 2012

CSS to match the last match of a selector?

Question by Walkerneo

I have a structure like:

<div id="holder">
    <div id="first"></div>
    <div class="box">I'm the first</div>
    <div class="box">Nothing special</div>
    <div class="box">Nothing special</div>
    <div class="box">Nothing special</div>
    <div class="box">Nothing special</div>
    <div class="box">Nothing special</div>
    <div class="box">Make this background orange!!!</div>
    <div id="last"></div>
</div>​

I need the last .box element to have an orange background.

.box:last-child{} won’t work because it isn’t the last child. Apart from wrapping only the .box‘s in an element, is there any way to do this? This problem does represent what I’m trying to do, but I’d also like to know if there is a way to match the last matched element of a selector.

http://jsfiddle.net/walkerneo/KUa8B/1/

Extra notes:

  • No javascript
  • No giving the last element an extra class

Answer by BoltClock

Sorry, aside from abusing sibling combinators or :nth-last-child() in a way that depends fully on your HTML structure1, it’s currently not possible with CSS selectors alone.

This very feature looks slated to be added to Selectors 4 as :nth-last-match(), though, which in your case would be used like this:

:nth-last-match(1 of .box) {
    background: orange;
}

But I don’t know if the syntax is going to change or when vendors will start implementing it, so let’s just leave that as a hypothetical-theoretical-maybe kind of thing for now.


1 Something like this, given that your last .box is also the second last child:

.box:nth-last-child(2) {
    background: orange;
}

Answer by Starx

You can give nth-last-of-type() for a workaround

#holder > .box:nth-last-of-type(2) {
    background:orange;
}

Demo

However, here is also another way of getting this done

<div id="holder">
    <div id="first"></div>
    <div class="boxes">
        <div class="box">I'm the first</div>
        <div class="box">Nothing special</div>
        <div class="box">Nothing special</div>
        <div class="box">Nothing special</div>
        <div class="box">Nothing special</div>
        <div class="box">Nothing special</div>
        <div class="box">Make this background orange!!!</div>
    </div>
    <div id="last"></div>
</div>

Then, you can use

.boxes .box:last-child {
    background:orange;
}

Demo

March 7, 2012

input[type='text'] CSS selector does not apply to default-type text inputs?

Question by Yarin

The default input type is ‘text’. I’ve always assumed then that css declarations targeting input[type='text'] would affect those inputs even if the type was not explicitly declared on the control. However, just noticed that my default-type text inputs don’t get the styles. Why is this the case?

CSS:

input[type='text']
{
background:red;
}

HTML:

<input name='t1' type='text'/> /* Is Red */
<input name='t1'/> /* Is Not Red */

http://jsfiddle.net/LhnNM/

Answer by Mr Lister

The CSS uses only the data in the DOM tree, which has little to do with how the renderer decides what to do with elements with missing attributes.

So either let the CSS reflect the HTML

input:not([type]), input[type="text"]
{
background:red;
}

or make the HTML explicit.

<input name='t1' type='text'/> /* Is Not Red */

If it didn’t do that, you’d never be able to distinguish between

element { ...properties... }

and

element[attr] { ...properties... }

because all attributes would always be defined on all elements. (For example, table always has a border attribute, with 0 for a default.)

Answer by Starx

Because, it is not supposed to do that.

input[type=text] { } is an attribute selector, and will only select those element, with the matching attribute.

August 21, 2010

CSS Selector for Absence of Tag

Question by Ethan Turkeltaub

Given this HTML:

<div class="entry">
    <a class="meta">Aug. 20, 2010</a>
    <div class="content">
        <h2><a href="#">Hello.</a></h2>
        <p>...</p>
    </div>
</div>
<div class="entry">
    <a class="meta">Aug. 20, 2010</a>
    <div class="content">
        <p>...</p>
    </div>
</div>

And this CSS:

.entry{
    width: 760px;
}

.entry .meta{
    float: left
    width: 160px;
}

.entry .content{
    float: right;
    width: 600px;
}

Is there a selector to add a margin-top: 25px; to .entry .meta in the absence of the <h2> tag? Or will I need to resort to JavaScript for this?

Answer by Starx

Try this

.content > h2+p { margin:1px; }
.content > p { margin-top:25px; }

See Demo

...

Please fill the form - I will response as fast as I can!