codingrose
codingrose

Reputation: 15699

pseudo class nth-of-type not applicable on specific class

On the first time my HTML,CSS looks perfect, but as shown in fiddle, when clicking on button, I want to hide/show some .show elements. When I hide them, CSS is broken. I dont know what I am missing.

HTML:

<div>
    <span class="show">box</span>
    <span class="show">box</span>
    <span class="show">box</span>
    <span class="show">box</span>
    <span class="show">box</span>
    <span class="show">box</span>
    <span class="show">box</span>
    <span class="show">box</span>
</div>
<input type="button" id="button" value="click" />

CSS:

div .show:nth-of-type(-n+4) {
    margin-top:0;
}
div .show:nth-of-type(4n) {
    margin-right:0;
}

JS:

$("#button").click(function () {
    $("span:eq(0),span:eq(2)").toggle().toggleClass("show");
});

Jsfiddle here.

Any help would be appreciated.

Thanks for your time.

Upvotes: 3

Views: 130

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074455

The :nth-of-type will not count only the .show elements, it will count all spans. So when you hide some of them, even though they're hidden, they still count.

If you're going to show and hide the spans, nth-of-type probably isn't what you need.

I'm not a CSS wizard. Two options come to me:

  1. Don't hide the elements, detach them, and then reattach them later. Then they aren't in the parent anymore and :nth-of-type will keep working. See the example below.

  2. (And I don't like this, but...) Don't use :nth-of-type, use classes you assign via JavaScript whenever you show/hide spans (basically running through the visible ones and giving them classes to do what you need.)

Here's an example of doing the detach/reattach thing: Fiddle

// Get the spans
var $spans = $("#container span");

// Assign them indexes
$spans.each(function(index) {
    this.setAttribute("data-index", index);
});

// Attach/detach on a toggle
var detached;

$("#button").click(function () {
    if (detached) {
        reattach(detached);
        detached = undefined;
    }
    else {
        detached = detach();
    }
});

function detach() {
    var rnd1, rnd2;

    // Pick two at random
    rnd1 = Math.floor(Math.random() * $spans.length);
    do {
        rnd2 = Math.floor(Math.random() * $spans.length);
    }
    while (rnd2 === rnd1);

    // Detach them
    return $("#container span:eq(" + rnd1 + "),span:eq(" + rnd2 + ")").detach();
}

function reattach(spans) {
    spans.each(function() {
        var $span = $(this),
            index = +$span.attr("data-index");
        if (index === 0) {
            $span.prependTo("#container");
        }
        else {
            $span.insertAfter($spans[index - 1]);
        }
    });
}

Note that it's important that the div containing the spans not have an empty text node as its first child (your fiddle does, I've removed it in mine). That's because when we put the spans back, since we always do them in order, if we're reattaching the first one we have to use prependTo rather than insertAfter, and the text node messes things up.

Upvotes: 6

Related Questions