How to get nth-child selector to skip hidden divs
When the user clicks on a button, I hide few blocks by
display:none
,
and the problem occurs. Thenth-child
selector also counts hidden
elements.Is there way to ignore those specific blocks, so that again every row
has different style?
The problem is that the nth-child()
selector looks at all siblings under the same parent regardless of styling. It doesn't matter that you've applied display: none
because CSS doesn't remove the element from the DOM, and therefore it's still a sibling.
From the spec:
6.6.5.2.
:nth-child()
pseudo-classThe
:nth-child(an+b)
pseudo-class notation represents an
element that has an+b-1 siblings before it in the document
tree, for any positive integer or zero value of n, and has a parent
element. (emphasis mine)
In order for the nth-child
rules you've declared to work after a user clicks to hide divs, you need to remove the hidden divs from the DOM, so they no longer exist as siblings.
In your question you request a CSS-only solution. But in your comments you say that the HTML is open for changes. You also use a bit of jQuery to hide elements.
With one small line of code added to your jQuery the problem can be solved:
$('.hidden').remove();
The .remove()
method takes elements (and its descendants) out of the DOM. In this case it removes all elements with a class hidden
.
CORRECTION
The problem with remove()
is that elements taken from the DOM with this method can't be restored, and this breaks the toggle function.
Fortunately, jQuery offers an alternative: detach()
.
The
.detach()
method is the same as.remove()
, except that
.detach()
keeps all jQuery data associated with the removed
elements. This method is useful when removed elements are to be
reinserted into the DOM at a later time.
So if we replace the original code...
$('.hide-others').click(function () {
$('.css--all-photo').toggleClass('hidden');
})
...with this code...
var divs;
$('.photos-board-item').each(function(i){
$(this).data('initial-index', i);
});
$('.hide-others').on('click', function () {
if(divs) {
$(divs).appendTo('.row').each(function(){
var oldIndex = $(this).data('initial-index');
$('.photos-board-item').eq(oldIndex).before(this);
});
divs = null;
} else {
divs = $('.css--all-photo').detach();
}
});
... the grid works as intended. (code credit: @JosephMarikle)
DEMO
Now, regardless of which divs or how many are hidden, they can be toggled on and off without disrupting the visual design because the nth-child
selector is counting only "visible" siblings. No changes to the CSS. No changes to the HTML.
Select odd even child excluding the hidden child
Pseudo-selectors don't stack, so your :not
doesn't affect the :nth-child
(nor would it affect :nth-of-type
etc.
If you can resort to jQuery, you can use the :visible
pseudo-selector there, although that's not a part of the CSS spec.
If you're generating the HTML and can change that, you can apply odd/even with logic at run-time, eg in PHP:
foreach ($divs AS $i => $div) {
echo '<div class="box ' . ($i % 2 ? 'even' : 'odd') . '">x</div>';
}
Even trying to do something tricky like
.box[class='box']:nth-of-type(even)
doesn't work, because the psuedo-selector doesn't even stack onto the attribute selector.
I'm not sure there's any way to do this purely with CSS - I can't think of any right now.
Filter :nth-child ignoring where css display is none
Okay managed to get it working by returning the css property before calling the :nth-child
function makeheight(){
var $sections = $('.section-link');
$sections.filter(function() {
return $(this).css('display') == 'block';
}, ':nth-child(3n-2)').each(function () {
var $this = $(this),
$els = $this.nextAll(':lt(2)').addBack();
var sectionheight = new Array();
$els.each(function () {
var value = $(this).find('.section-title').height();
sectionheight.push(value);
});
var newsectionheight = Math.max.apply(Math, sectionheight);
$els.find('.section-title').height(newsectionheight);
});
}
CSS nth-chid selector without hidden chilld node
You can do something like this:
Since you have
hide
element as well so this is the place where you have to use~
(negate) forodd
andeven
The code is pretty straight forward to understand let me know if you need explaination.
.whois { background: green; color: white;}
.whois:nth-child(even) { background: black; color: white;}
.whois.hide { display: none;}
.whois.hide~.whois:nth-child(odd) { background: black; color: white;}
.whois.hide~.whois:nth-child(even) { background: green; color: white;}
<table> <tr class="whois"> <td>row 1</td> </tr> <tr class="whois"> <td>row 2</td> </tr> <tr class="whois hide"> <td>row 3</td> </tr> <tr class="whois"> <td>row 4</td> </tr> <tr class="whois"> <td>row 5</td> </tr></table>
How to apply nth-child styling to a filtered set of divs?
You can try a combination of visible
and odd/even
pseudo-selector to change your css:
$('.card:visible:even').css({ 'background': 'pink'});
$('.card:visible:odd').css({ 'background': 'white'});
$(document).on("keyup", ".my_input", function() { var input_val = $(this).val(); var input_length = input_val.length; // minimum 2 chars for search if (input_length > 2) { filter_cards(input_val); } else if (input_length <= 2) { $(".card").show(); // remove matched text styling // see: https://stackoverflow.com/a/4232971 $('span.matched_text').contents().unwrap(); } $('.card:visible:even').css({ 'background': 'pink','marginRight':'20px'}); $('.card:visible:odd').css({ 'background': 'white','marginRight':0});});
// filter functionfunction filter_cards(input_val) {
// iterate over each card $(".card").each(function() {
var match_counter = 0;
// instance of card var $card = $(this);
var text = $card.text();
var exists_in_string = text.toLowerCase().indexOf(input_val.toLowerCase()) !== -1;
if (exists_in_string === false) { $card.html(text); } else if (exists_in_string === true) { match_counter += 1; var reg = new RegExp(input_val, 'i'); $card.html(text.replace(reg, '<span class="matched_text">$&</span>')); }
if (match_counter > 0) { $card.show(); } else { $card.hide(); } });}
* { box-sizing: border-box;}
.my_input { width: 100%; font-size: 48px; margin-bottom: 20px;}
.my_cards { display: flex; flex-wrap: wrap;}
.card { width: calc(50% - 10px); font-size: 38px; border: 1px solid #000; margin-bottom: 30px; overflow:hidden;}
/* add margin on child divs 1,3,5,7 etc */
.card:nth-child(2n+1) { margin-right: 20px; background: pink;}
.matched_text { background: green; color: white;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><input class="my_input" placeholder="search for hello, min 2 chars...">
<div class="my_cards">
<div class="card" data-initial_index="0"> 01 - apples and hello </div>
<div class="card" data-initial_index="1"> 02 - oranges and hello </div>
<div class="card" data-initial_index="2"> 03 - bananas </div>
<div class="card" data-initial_index="3"> 04 - passionfruits and hello </div>
<div class="card" data-initial_index="4"> 05 - mangos and hello </div>
<div class="card" data-initial_index="5"> 06 - limes and hello </div>
</div>
Related Topics
Pure JavaScript Method to Wrap Content in a Div
Execute Function After Complete Page Load
How to Detect a Mobile Device With JavaScript
How to Detect "Shift+Enter" and Generate a New Line in Textarea
How to Clear the Content of a Div Using JavaScript
Html5 Canvas Camera/Viewport - How to Actually Do It
Css Transition Doesn't Start/Callback Isn't Called
Add/Remove Class With Jquery Based on Vertical Scroll
Detect Change in Orientation Using JavaScript
How to Select Multiple Files With ≪Input Type="File"≫
How to Fix Blurry Text in My Html5 Canvas
Passing Form Data to Another HTML Page
Submit Form and Stay on Same Page
Adding Additional Data to Select Options Using Jquery
How to Create a Sticky Navigation Bar That Becomes Fixed to the Top After Scrolling