问题
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