Select the last 3 child elements - css

I know you can select the last child with :last-child or a certain child with :nth-child (if you know their position/number).
What I need is to select the last 3 children without knowing how many child elements there could be.
I know there is something that's called :nth-last-child but I cant really understand how it is working.
For this:
<div id="something">
<a href="images/x.jpg" ><a/>
<a href="images/x.jpg" ><a/>
<!-- More elements here -->
<!-- ..... -->
<!-- I need to select these: -->
<a href="images/x.jpg" ><a/>
<a href="images/x.jpg" ><a/>
<a href="images/x.jpg" ><a/>
</div>
I need something like this:
#something a:last-child{
/* only now it selects the last <a> and the 2 <a>'s that come before*/
}

You can read more here about nth-last child, but this should basically do the trick of selecting the last 3 children with just CSS
#something a:nth-last-child(-n+3) {
/*declarations*/
}
fiddle demonstration from Fabrício Matté
This will only select those rows returning a positive number for out N expression (-n+3), and since we are using nth-last-child, it's counting from last to first,
so first rows from bottom gives,
f(n) = -n+3
f(1) = -1+3 = 2 <- first row from the bottom
f(2) = -2+3 = 1 <- second row from the bottom
f(3) = -3+3 = 0 <- third row from the bottom
everything else will return a negative number

This is possible with CSS3 selectors and formulas:
.something a:nth-last-child(-n+3) { ... }
You could also try using jQuery (example) or adding a specific class to the last three elements in your server-side code (it does not require JavaScript to be enabled in browsers and also works on older browsers that do not support CSS3).

The accepted answer has the correct formula, but the explanation is wrong.
So the correct CSS is (same as currently accepted answer):
#something a:nth-last-child(-n+3) {
/*declarations*/
}
But here is the correct explanation of the math:
f(n) = -n+3
f(0) = -0+3 = 3 <- 3rd row from the bottom
f(1) = -1+3 = 2 <- 2nd row from the bottom
f(2) = -2+3 = 1 <- 1st row from the bottom
f(3) = -3+3 = 0 <- nothing
f(3) = -4+3 = -1 <- nothing
etc...

Related

How can I select specific number of last child using CSS?

For example, there are total 12 elements.
I want to apply my style only on last n (1, 2, 3...) numbers of child of total 12 elements; how can I do this?
I think what you are looking for is the css pseudo-class :nth-last-child (see MDN)
Just use a negative n value and add the index from the end (represents number of elements)
.parentClass > * :nth-last-child ( -n + 3 ) {
/* CSS here for last 3 elements */
}
https://jsfiddle.net/evm0mg8j/

Add classes to adjacent elements dynamically on mouseenter

I'm creating a grid of elements and have a hover effect in place, using CSS transitions, for each element. I'd like to add secondary effects on adjacent x- and y-axis elements as well, creating a cloud effect. I imagine I'll be referencing those elements using jQuery's next() and prev() methods, or by $index and $parent.$index.
The grid area will be large enough to prevent row-wrapping (using negative margins and hidden overflow).
Here's a simplified example of my repeat:
<div class="activity-thumb-row" ng-repeat="i in getNumArray(20) track by $index">
<div class="activity-thumb"
ng-class="{'adjacent': adjacent}"
ng-repeat="j in getNumArray(30) track by $index"
ng-mouseenter="highlightActivities()">
</div>
</div>
And a function in the controller (which I realize may not be the best approach):
$scope.highlightActivities = function() {
$(this).next().adjacent = true;
$(this).prev().adjacent = true;
}
How can I target elements adjacent to the hovered element using ng-class (or something else) inside ng-repeat?
Here's a fiddle for fiddling.
For reference, here are some related discussions:
Change class on mouseover in directive
Angular js ng repeat with conditional ng class not applying css class
ng-mouseover and leave to toggle item using mouse in angularjs
Here's a directive that calculates all of the indices of adjacent cells and adds the adjacent class using jQuery only ... not ng-class.
Assumes that rows will wrap , would need adjusting for individual row elements
.directive('activityThumb', function() {
return {
restrict: 'C',
link: function(scope, elem) {
elem.bind('mouseenter', function(e) {
var elW = elem.width(),
$parent =elem.parent(),
parentW = $parent.width(),
$items = $parent.children(),
numItems =$items.length
itemsPerRow = Math.floor(parentW / elW),
idx = elem.index(),
rowIndex = idx % itemsPerRow;
/* object of various indices , easy to inspect*/
var adjacentIdx = {
top: idx > itemsPerRow ? idx - itemsPerRow : false,
right: rowIndex != itemsPerRow ? idx + 1 : false,
left: rowIndex > 0 ? idx - 1 : false,
bottom: (numItems - idx) > itemsPerRow ? idx + itemsPerRow : false
}
console.dir(adjacentIdx);
$items.removeClass('adjacent')
$.each(adjacentIdx, function(position, index){
if(index !== false){
$items.eq(index).addClass('adjacent');
}
});
});
}
}
});
It wouldn't take much tweaking to remove jQuery dependency either.
Also would need additional directive on parent to remove extra classes when mouse leaves the main parent from one of the edges
DEMO
First, it's not a good idea to deal with DOM elements in the controller.
Also, this problem seems to be mostly styling related, and not functionality related. I would thus try to keep the logic in the View and not in the controller.
There are 2 ways to deal with View-specific logic: 1) using custom directives or 2) View-defined scope variables
The second approach can work here and seems like the cheapest approach, but also a bit ugly. It ng-inits the rowHighlight array in the scope and sets which element is highlighted:
<div ng-repeat="i in getNumArray(20) track by $index" ng-init="rowHighlight = []">
<div class="activity-thumb"
ng-repeat="j in getNumArray(30) track by $index"
ng-class="{'adjacent': rowHighlight[$index-1] || rowHighlight[$index+1]}"
ng-mouseenter="rowHighlight[$index] = true"
ng-mouseleave="rowHighlight[$index] = false">
</div>
</div>
updated fiddle

Continuous nth-child (multiple occurrences)

I have a list made of thousands of items.
In order to display them in a clean fashion, I need to apply a specific css rule to every third item of the list (3th li, 6th li, 9th li,....,3000th li..9999th li...).
Normally, I would use this:
li:nth-child(3),li:nth-child(6),...
but this would obviously be too tedious to write a css rule for each item (not to mention that the list may grow over time)
I also may use a class for every third item of the list but the list is reordered constantly according to a filter by a jQuery plugin (Quicksand), so the 6th li can asynchronously become the 4th one according to the user manipulation.
So, is there a way to use a css rule that would simply do something like this?:
li:nth-child(n*3)
Thank you.
You could use the :nth-child(an+b) pseudo class as li:nth-child(3n+3) in order to select every third list item (a parameter) starting from 3rd <li> element (b parameter).
In which:
n starts from 0
n = 0: (3 * 0 + 3) = 3 => 3rd element
n = 1: (3 * 1 + 3) = 6 => 6th element
n = 2: (3 * 2 + 3) = 9 => 9th element
...
li:nth-child(3n+3) {
background-color: gold;
}
Example Here. (Which is the same as li:nth-child(3n)).
From the MDN:
The :nth-child(an+b) CSS pseudo-class matches an element that has
an+b-1 siblings before it in the document tree, for a given positive
or zero value for n, and has a parent element.
It's worth noting that :nth-child pseudo-class is supported in IE9+.

css inline-block div positioning

I'm trying to fix a positing issue in a responsive design.
I have a container div, containing 4 (but it could be more or less) divs that are displayed as inline-block. I would like to know how to control the number of divs per line when the page is resized (with CSS, if it's possible). For example, when 4 containees no longer fits in the container, the last one is moved to second line. I would like in that case to have 2 containees in the first line and 2 containees in the second line. I dont know how to do that. Your help would be welcomed!
EDIT:
it could also be 6 containees, in the case the layout would be:
- 1 line of 6 blocks if it fits
- 2 lines of 3 blocks
- 3 lines of 2 blocks
- 6 lines of one
the number of containees is variable. I just want to have the same number of containees per line
the html:
<div class="container">
<div class="containee"></div>
<div class="containee"></div>
<div class="containee"></div>
<div class="containee"></div>
</div>
the css:
.containee {
width:200px;
height:200px;
display:inline-block;
background-color:tomato
}
the example can be seen here : http://cssdesk.com/uGLbq
(PS : I tried to find the solution searching the web but I dont really know the good keywords related with this topic)
You can't with CSS (AFAIK).
You can do "the math" dynamically with Javascript in real time.
In your case,
you known the width of one block (in that moment),
you can easily get the window width (in that moment),
you know the number of your block (in that moment);
Simply apply ( (1) the first time you open the page, and (2) every time the number of blocks changes, or (3) the resolution changes) the algorithm in the following code:
// EXAMPLE OF INPUT
var windowWidth = 1400; // read it...
var blockWidth = 200; // read it or use const...
var numberOfBlocks = 10; // read it...
// Calculate the maximum number of blocks per row
var maxBlocksPerRow;
for (var i=0; i < numberOfBlocks; i++) {
if ( (blockWidth * (i + 1)) > windowWidth){
maxBlocksPerRow = i;
break;
}
}
// Check the highest 0 module combination while iterating backwards
var magicNumberForMatchingBlocks = 1; // if not found, it will be 1.
for (var i = maxBlocksPerRow; i > 0 ; i--) {
if ( (numberOfBlocks % i) == 0){
magicNumberForMatchingBlocks = i;
break;
}
}
alert("With " + numberOfBlocks + " blocks, each one wide " +
blockWidth + " pixels, and a window wide " + windowWidth + " pixels,
the number of blocks per row for having always
the same number of block in any row is: " + magicNumberForMatchingBlocks);
Then use that number to populate or re-arrange the elements with Javascript or better with some Javascript library like jQuery.
html:
<div class="container">
<div class="grouped">
<div class="containee"></div>
<div class="containee"></div>
</div>
<div class="grouped">
<div class="containee"></div>
<div class="containee"></div>
</div>
</div>
css:
.containee {
width:200px;
height:200px;
display:inline-block;
background-color:tomato
}
.grouped {
float:left;
}
Try this:
.container
{
min-width: 410px;
}
Give the .containee a float:left; if the page fits for 4, they will be positioned right beside each other, else, you'll have another line of divs. You can give it as well a margin-top:5px; in case you got another line, the divs of the second line won't be glued to the divs of the first line. Note that with this approach, its not obliged to have equal number of .containee in each line, if you have 4, then you re-size, you'll have 3 - 1, then 2 - 2...etc..

Is there any way to select a last element in a Current row of multi-line stack in a block?

For example, i have some <ul> element with <li> blocks floated left.
If i resize my that way, that to <li> elements got place by 3 in a row. Next, i resize window (by mouse for example) and my <ul> got new width with <li> elements placing by 4 in a row for now.
So, how to select last <li> in a every row of that stack of elements, that to set them some CSS rule (margin-right for example).
So i need to know, is there any CSS selector or way to select with behavior explained here:
http://jsfiddle.net/w7PDM/12/
you'll have to calculate the last one, and it's simple.
$('button').click(function(){
$('ul').css('width','200px');
$('.current-last-of-row').removeClass('current-last-of-row');
var itemsPerRow = Math.floor(parseInt($('ul').css('width')) / 40);
//$('li:nth-child(4n+4)').addClass('current-last-of-row');
for(var i=1; i < $('ul li').length; i++)
{
if( i % itemsPerRow == 0 )
{
$('li').eq(i-1).addClass('current-last-of-row');
}
}
$('h1').text('Now, every 4 element is a "last-of-a-row"');
});​
check out the demo: http://jsfiddle.net/jun1st/hK9aZ/1/

Resources