How to select even rows with list items

梦想的初衷 提交于 2019-12-24 06:31:19

问题


I have the following layout with an unordered list:

https://codepen.io/barkins/pen/qjrpKJ

ul{
  max-width:1200px;
  list-style:none;
  margin:0 auto;
  padding:0;
  display:flex;
  flex-wrap:wrap;
}
li{
  width:12%;
  @media (max-width:720px){
    width:16%;
  }
  @media (max-width:480px){
    width:22%;
  }
}

I need to select only even rows, no matter the media query break points to add a border to only the 2nd row.

.second-row-items{
  border:1px solid red;
}

Is this possible to do with CSS and perhaps JavaScript (jQuery)?


I tried utilizing the following CSS rule to manually select the 2nd row, however it would best to have this be done automatically with JavaScript, somehow, and ideally select all the other even rows as well.

&:nth-child(n+9):nth-child(-n+16){
     border:1px solid red; 
  }

回答1:


Since you use SCSS , you can use a loop to generate your :nth-child(xn+x) selectors :https://codepen.io/anon/pen/VWpQbY?editors=1100

li {
  width: 12%;

  @for $i from 1 through 8 {
    &:nth-child(16n + #{$i}) {
      background: red;
    }
  }

  @media (max-width: 720px) {
    width: 16%;
    &:nth-child(1n) {
      background: none;/* reset previous rule */
    }

    @for $i from 1 through 6 {
      &:nth-child(12n + #{$i}) {
        background: red;
      }
    }
  }
  @media (max-width: 480px) {
    width: 22%;
    &:nth-child(1n) {
      background: none;/* reset previous rule */
    }

    @for $i from 1 through 4 {
      &:nth-child(8n + #{$i}) {
        background: red;
      }
    }
  }
}



回答2:


That should do the job if you want to select only second row:

@media (max-width:480px)
{
  li:nth-child(5),
  li:nth-child(6),
  li:nth-child(7),
  li:nth-child(8)
  {
    background-color: red;
  }
}
@media (min-width:481px) and (max-width:720px)
{
  li:nth-child(7),
  li:nth-child(8),
  li:nth-child(9),
  li:nth-child(10),
  li:nth-child(11),
  li:nth-child(12)
  {
    background-color: red;
  }
}
@media (min-width:721px)
{
  li:nth-child(9),
  li:nth-child(10),
  li:nth-child(11),
  li:nth-child(12),
  li:nth-child(13),
  li:nth-child(14),
  li:nth-child(15),
  li:nth-child(16)
  {
    background-color: red;
  }  
}

And if you want all even rows, then use:

@media (max-width:480px)
{
  li:nth-child(8n-3),
  li:nth-child(8n-2),
  li:nth-child(8n-1),
  li:nth-child(8n)
  {
    background-color: red;
  }
}
@media (min-width:481px) and (max-width:720px)
{
  li:nth-child(12n-5),
  li:nth-child(12n-4),
  li:nth-child(12n-3),
  li:nth-child(12n-2),
  li:nth-child(12n-1),
  li:nth-child(12n)
  {
    background-color: red;
  }
}
@media (min-width:721px)
{
  li:nth-child(16n-7),
  li:nth-child(16n-6),
  li:nth-child(16n-5),
  li:nth-child(16n-4),
  li:nth-child(16n-3),
  li:nth-child(16n-2),
  li:nth-child(16n-1),
  li:nth-child(16n),
  {
    background-color: red;
  }  
}



回答3:


👉 Selecting elements in the second row only with CSS (breakpoint-specific)

It's not possible to select the elements in the second row regardless of the media query breakpoints, so you will have to create selectors for the elements in that row for each breakpoint.

You can use two :nth-child pseudo-classes to select a range of elements. For example:

li:nth-child(n + 7):nth-child(-n + 12)

Will select elements 7 to 12, both included. That is, the second row if you have 6 columns.

img {
  max-width:100%;
  height:auto;
}

ul {
  max-width:1200px;
  list-style:none;
  margin:0 auto;
  padding:0;
  display:flex;
  flex-wrap:wrap;
}

li {
  width:12%;
  font-size: 0;
}

@media (min-width: 721px) { 
  li:nth-child(n+9):nth-child(-n+16) {
    margin: 4px 0;
    padding: 16px 0;
    background: cyan;
  }
}

@media (max-width: 720px) {
  li {
    width: 16%;
  }
  
  li:nth-child(n+7):nth-child(-n+12) {
    margin: 4px 0;
    padding: 16px 0;
    background: red;
  }
}

@media (max-width: 480px) {
  li {
    width: 22%;
  }
  
  li:nth-child(n+5):nth-child(-n+8) {
    margin: 4px 0;
    padding: 16px 0;
    background: yellow;
  }
}
<ul>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
</ul>

👉 Selecting elements in the second row with JS (breakpoint-independent)

If you really need a generic solution that doesn't depend on specific code for each breakpoint, you can use jQuery or plain JavaScript to select the elements in the second row based on their position and add them a class.

Basically, you iterate them all and, each time the value of their .offsetTop changes, you just stepped into the next row.

Note you will have to listen to the resize event in order to update the selected elements, just in case a different breakpoint is active and the number of columns has changed:

function styleSecondRow() {  
  let row = -1;
  let currentTop = -1;

  $('#grid > li').each(function() {
    let top = this.offsetTop;

    if (top > currentTop) {
      // We stepped into the next row:
      
      currentTop = top;
      
      ++row;
    }

    if (row === 1) {
      // Second row:
      
      this.classList.add('second-row');
    } else {
      // Remove .second-row from other rows:
      
      this.classList.remove('second-row');
    }
  });
}

// Update second row styling if window is resized:

$(window).resize(function() {
  styleSecondRow();
});

// Initialize second row styling for the firss time:

styleSecondRow();
img {
  max-width:100%;
  height:auto;
}

ul {
  max-width:1200px;
  list-style:none;
  margin:0 auto;
  padding:0;
  display:flex;
  flex-wrap:wrap;
}

li {
  width:12%;
  font-size: 0;
}

.second-row {
  margin: 4px 0;
  padding: 16px 0;
  background: cyan;
}

@media (max-width: 720px) {
  li {
    width: 16%;
  }
}

@media (max-width: 480px) {
  li {
    width: 22%;
  }
}
<ul id="grid">
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
  <li><img src="http://placehold.it/300x300"></li>
</ul>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

👉 Selecting elements in any even row using CSS

If you want to select elements in any even row, you need multiple selectors for each breakpoint, as @JacobDesight suggested. For example, if you had 8 columns, you would do this:

@media (...) {
    li {
        width: 12%;
    }

    li:nth-child(16n + 9),
    li:nth-child(16n + 10),
    li:nth-child(16n + 11),
    li:nth-child(16n + 12),
    li:nth-child(16n + 13),
    li:nth-child(16n + 14),
    li:nth-child(16n + 15),
    li:nth-child(16n + 16) {
        background: pink;

        ...
    }
}

Note you have multiple rules but just a single block of properties.

👉 Selecting elements in any even row using SCSS, avoiding duplicated code

To do the same but using SCSS, if you forget about the media query for a second, you would normally use @mixin, @include, @for and placeholder selector:

// Placeholder selector that we will extend to avoid duplicating
// the properties for each generated nth-child selector:

%even-row { background: pink; }

// Mixin to avoid duplicating the @for block multiple times.
// It takes the number of columns as a parameter:

@mixin even-rows-mixin($columns) {
    @for $i from 1 through $columns {
        &:nth-child(#{2 * $columns}n + #{$i + $columns}) {
            @extend %even-row;
        }
    }
}

li {
    @include even-rows-mixin(8);
    width: 12%;
}

This will generate the following code:

li:nth-child(16n + 9),
li:nth-child(16n + 10),
li:nth-child(16n + 11),
li:nth-child(16n + 12),
li:nth-child(16n + 13),
li:nth-child(16n + 14),
li:nth-child(16n + 15),
li:nth-child(16n + 16) {
    background: pink;
}

li {
    width: 12%;
}

However, you can't use @extend inside media queries.

If you remove the @extend, you will end up with something similar to what @GCyrillus suggested. You can wrap that in a mixin to avoid duplicating the @for block in each media query, but that will still generate duplicated code. The mixin will look like this:

@mixin even-rows-mixin($columns) {
    @for $i from 1 through $columns {
        &:nth-child(#{2 * $columns}n + #{$i + $columns}) {
            background: pink;
        }
    }
}

It will generate $columns selectors and blocks of duplicated properties (only background in this example), which will make your stylesheet grow fast if you use this mixin too much or if you add more properties to it.

EDIT: I suspected this could be done using interpolation, but was not sure about it, so I opened another question and someone came to the rescue: SCSS @extend inside media query alternatives to avoid duplicate properties

Basically, you should build a selector variable in the mixin and use interpolation to create a rule with a fixed set of properties, or @content if you prefer to set them dynamically:

@mixin even-rows-mixin($columns, $rule) {
    $selector : '';

    @for $i from 1 through $columns {
        $selector:  $selector + $rule + '('+ #{2 * $columns}n  + ' + ' + #{$i + $columns} + '),';
    }  

    #{$selector} {
        @content; // Or just add your properties here.
    }
}

...

@media(...) {

    ...

    @include even-rows-mixin(8, 'li:nth-child') {
        background: pink; 
    };

    ...

}

Note this code does not compile in CodePen, but it does when using node-sass or this other online compiler: http://beautifytools.com/scss-compiler.php




回答4:


Okay the key is to know how many images will be in each row on each breakpoint.

If at large screen, you have 6 items in a row, then you want 7-12 underlined (the second row), but not 13-18, but 19-24, etc. For medium, it may be 4. Small 2, Extra small, 1 (just an example).

You could use Javascript to select those rows, and add your class .second-row-items to them.

You might have to take the width of the container and divide it by the width of the images to find out how many items can fit in a row (n), and then take the total number of items and divide that by the number of items that fit in a row to get the number of rows. Then you could write a function that selects every nth child (to get get the row) and nth siblings (to get the entire row) to add your class.




回答5:


If you just want to select even li then go with :nth-child{even}

In your case, code would be

ul li:nth-child(even){ border: 1px solid black;}


来源:https://stackoverflow.com/questions/44636845/how-to-select-even-rows-with-list-items

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!