ONYX
ONYX

Reputation: 5859

Selecting items in the last row of a CSS grid based on class and data attribute

How do I group div items by year in a CSS grid without specifying the year in the CSS? The year is included as a data-group attribute in every div. I want to pick the last divs of any year for .year, .link and .title and group them with a border.

I need to do something like below but it doesn't work at all. I need to group items by year without actually knowing what year it is.

.year[data-group="unknown"]:last-of-type {
      border-bottom: 1px solid gray;
}
<div class="grid">
          <div data-group="2018" class="year">2018</div>
          <div data-group="2018" class="link"><a href="#"></a></div>
          <div data-group="2018" class="title">Avengers: Infinity War <span>as Natasha Romanoff / Black Widow</span></div>

          <div data-group="2017" class="year">2017</div>
          <div data-group="2017" class="link"><a href="#"></a></div>
          <div data-group="2017" class="title">Ghost In The Shell <span>as Major Mira Killian / Motoko Kusanagi</span></div>

          <div data-group="2017" class="year">2017</div>
          <div data-group="2017" class="link"><a href="#"></a></div>
          <div data-group="2017" class="title">Thor: Ragnarok <span>as Natasha Romanoff / Black Widow (archive footage / uncredited)</span></div>

</div>
    

Upvotes: 3

Views: 769

Answers (2)

FluffyKitten
FluffyKitten

Reputation: 14312

This cannot be done using CSS only, but as you tagged javascript I assume you are happy with a solution using js.

The difficulty in doing this is that we are not just looking for the last element with the data-group for that year - we are looking for last data-group for each class type for each year. Therefore we have to keep track of the classes and years that we have found.

Based on the HTML you have provided, the code below will find the last year, link and title classes for each year and add a CSS class with a border.

What is it doing:

  1. Create a CSS class for the styling
  2. Create an array to keep track of each year and class combination (e.g. 2017 .year, 2017 .link etc) - I've called this processedDivs in the code below
  3. Get a list of all the elements with the data-group attribute
  4. Loop through these in reverse... this means that the first elements of a particular type that we process in out loop are the actually the last in your data
  5. Check if we have added this year and class to our processedDivs
  6. if not, then this is the first time we have found this class and year, so add our CSS style

Working Example:

/* 2. array to keep a record of the years and classes we have processed */
let processedDivs = new Array; 

/* 3. get all years in an array */
let allYears = document.querySelectorAll('[data-group]');

/* 4. loop through the Divs in reverse so we add the style to the first in our list*/
for (i = allYears.length-1; i >= 0; i--) {
    // Get the year and class name
    year = allYears[i].getAttribute('data-group');
    className = allYears[i].className;

    // 5. if we haven't added the CSS to this class for this year...
    if (processedDivs.indexOf(year+className) === -1) {
        processedDivs.push(year+className);           // add to the list
        allYears[i].classList.add("year-separator")  // add the CSS class
    }
}
/* 1. our class to apply to the last "row" for each year */
.year-separator {
    border-bottom: 1px solid gray;
}
.grid { 

  display: grid;
  grid-template-columns: 50px 50px 1fr;
}
.grid div {

}
<div class="grid flex-row-container">
      <div data-group="2018" class="year">2018</div>
      <div data-group="2018" class="link"><a href="#"></a></div>
      <div data-group="2018" class="title">Avengers: Infinity War <span>as Natasha Romanoff / Black Widow</span></div>

      <div data-group="2017" class="year">2017</div>
      <div data-group="2017" class="link"><a href="#"></a></div>
      <div data-group="2017" class="title">Ghost In The Shell <span>as Major Mira Killian / Motoko Kusanagi</span></div>

      <div data-group="2017" class="year">2017</div>
      <div data-group="2017" class="link"><a href="#"></a></div>
      <div data-group="2017" class="title">Thor: Ragnarok <span>as Natasha Romanoff / Black Widow (archive footage / uncredited)</span></div>

    </div>

Upvotes: 2

simmer
simmer

Reputation: 2711

This isn't really a CSS grid issue. The issue is that there's no CSS selector available to group elements by attribute value.

Also, :last-of-type will only find the last element of a given element type, not the last with a certain attribute or attribute value. Doesn't matter if you know the possible values for data-group or not, :last-of-type won't help.

Your best options here are:

  1. Change the markup if you have control over it. Group each year with something like <div class="year-group"> ... </div>, and add a border to .year-group
  2. Use javascript to change the markup or add classnames if you don't have direct control over the HTML markup. Iterate through the child nodes of .grid, and either wrap the grouped years in a containing element as above, or do something like adding a has-bottom-border classname to the last div for each year.

Upvotes: 0

Related Questions