nth-child – CSS-Tricks https://css-tricks.com Tips, Tricks, and Techniques on using Cascading Style Sheets. Tue, 02 Aug 2022 13:10:51 +0000 en-US hourly 1 https://wordpress.org/?v=6.1.1 https://i0.wp.com/css-tricks.com/wp-content/uploads/2021/07/star.png?fit=32%2C32&ssl=1 nth-child – CSS-Tricks https://css-tricks.com 32 32 45537868 Implicit Grids, Repeatable Layout Patterns, and Danglers https://css-tricks.com/implicit-grids-repeatable-layout-patterns-and-danglers/ https://css-tricks.com/implicit-grids-repeatable-layout-patterns-and-danglers/#comments Tue, 02 Aug 2022 13:10:49 +0000 https://css-tricks.com/?p=367158 Dave Rupert with some modern CSS magic that tackles one of those classic conundrums: what happens when the CSS for component is unable to handle the content we throw at it?

The specific situation is when a layout grid expects …


Implicit Grids, Repeatable Layout Patterns, and Danglers originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Dave Rupert with some modern CSS magic that tackles one of those classic conundrums: what happens when the CSS for component is unable to handle the content we throw at it?

The specific situation is when a layout grid expects an even number of items, but is supplied with an odd number instead. We’re left with a “dangling” element at the end that throws off the layout. Sounds like what’s needed is some Defensive CSS and Dave accomplishes it.

He reaches for :has() to write a nifty selector that sniffs out the last item in a grid that contains an odd number of items:

.items:has(.item:last-of-type:nth-of-type(odd)) .item:first-of-type { }

Breaking that down:

  • We have a parent container of .items.
  • If the container :has() an .item child that is the last of its type,
  • …and that .item happens to be an odd-numbered instance,
  • …then select the first .item element of that type and style it!

In this case, that last .item can be set to go full-width to prevent holes in the layout.

If… then… CSS has conditional logic powers! We’re only talking about support for Safari TP and Edge/Chrome Canary at the moment, but that’s pretty awesome.

As chance has it, Temani Afif recently shared tricks he learned while experimenting with implicit grids. By taking advantage of CSS Grid’s auto-placement algorithm, we don’t even have to explicitly declare a fixed number of columns and rows for a grid — CSS will create them for us if they’re needed!

No, Temani’s techniques aren’t alternative solutions to Dave’s “dangler” dilemma. But combining Temani’s approach to repeatable grid layout patterns with Dave’s defensive CSS use of :has(), we get a pretty powerful and complex-looking grid that’s lightweight and capable of handling any number of items while maintaining a balanced, repeatable pattern.


Implicit Grids, Repeatable Layout Patterns, and Danglers originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/implicit-grids-repeatable-layout-patterns-and-danglers/feed/ 2 367158
Conditionally Styling Selected Elements in a Grid Container https://css-tricks.com/conditionally-styling-selected-elements-in-a-grid-container/ https://css-tricks.com/conditionally-styling-selected-elements-in-a-grid-container/#comments Wed, 15 Jun 2022 14:15:50 +0000 https://css-tricks.com/?p=366252 Calendars, shopping carts, galleries, file explorers, and online libraries are some situations where selectable items are shown in grids (i.e. square lattices). You know, even those security checks that ask you to select all images with crosswalks or whatever.

🧐…


Conditionally Styling Selected Elements in a Grid Container originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Calendars, shopping carts, galleries, file explorers, and online libraries are some situations where selectable items are shown in grids (i.e. square lattices). You know, even those security checks that ask you to select all images with crosswalks or whatever.

🧐

I found a neat way to display selectable options in a grid. No, not recreating that reCAPTCHA, but simply being able to select multiple items. And when two or more adjoining items are selected, we can use clever :nth-of-type combinators, pseudo elements, and the :checked pseudo-class to style them in a way where they look grouped together.

The whole idea of combinators and pseudos to get the rounded checkboxes came from a previous article I wrote. It was a simple single-column design:

This time, however, the rounding effect is applied to elements along both the vertical and horizontal axes on a grid. You don’t have to have read my last article on checkbox styling for this since I’m going to cover everything you need to know here. But if you’re interested in a slimmed down take on what we’re doing in this article, then that one is worth checking out.

Before we start…

It’ll be useful for you to take note of a few things. For example, I’m using static HTML and CSS in my demo for the sake of simplicity. Depending on your application you might have to generate the grid and the items in it dynamically. I’m leaving out practical checks for accessibility in order to focus on the effect, but you would definitely want to consider that sort of thing in a production environment.

Also, I’m using CSS Grid for the layout. I’d recommend the same but, of course, it’s only a personal preference and your mileage may vary. For me, using grid allows me to easily use sibling-selectors to target an item’s ::before and ::after pseudos.

Hence, whatever layout standard you might want to use in your application, make sure the pseudos can still be targeted in CSS and ensure the layout stays in tact across different browsers and screens.

Let’s get started now

As you may have noticed in the earlier demo, checking and unchecking a checkbox element modifies the design of the boxes, depending on the selection state of the other checkboxes around it. This is possible because I styled each box using the pseudo-elements of its adjacent elements instead of its own element.

The following figure shows how the ::before pseudo-elements of boxes in each column (except the first column) overlap the boxes to their left, and how the ::after pseudo-elements of boxes in each row (except the first row) overlap the boxes above.

Two grids of checkboxes showing the placement of before and after pseudos.

Here’s the base code

The markup is pretty straightforward:

<main>
  <input type=checkbox> 
  <input type=checkbox> 
  <input type=checkbox>
  <!-- more boxes -->
</main>

There’s a little more going on in the initial CSS. But, first, the grid itself:

/* The grid */
main {
  display: grid;
  grid:  repeat(5, 60px) / repeat(4, 85px);
  align-items: center;
  justify-items: center;
  margin: 0;
}

That’s a grid of five rows and four columns that contain checkboxes. I decided to wipe out the default appearance of the checkboxes, then give them my own light gray background and super rounded borders:

/* all checkboxes */
input {
  -webkit-appearance: none;
  appearance: none;
  background: #ddd;
  border-radius: 20px;
  cursor: pointer;
  display: grid;
  height: 40px;
  width: 60px;
  margin: 0;
}

Notice, too, that the checkboxes themselves are grids. That’s key for placing their ::before and ::after pseudo-elements. Speaking of which, let’s do that now:

/* pseudo-elements except for the first column and first row */
input:not(:nth-of-type(4n+1))::before,
input:nth-of-type(n+5)::after {
  content: '';        
  border-radius: 20px;
  grid-area: 1 / 1;
  pointer-events: none;
}

We’re only selecting the pseudo-elements of checkboxes that are not in the first column or the first row of the grid. input:not(:nth-of-type(4n+1)) starts at the first checkbox, then selects the ::before of every fourth item from there. But notice we’re saying :not(), so really what we’re doing is skipping the ::before pseudo-element of every fourth checkbox, starting at the first. Then we’re applying styles to the ::after pseudo of every checkbox from the fifth one.

Now we can style both the ::before and ::after pseudos for each checkbox that is not in the first column or row of the grid, so that they are moved left or up, respectively, hiding them by default.

/* pseudo-elements other than the first column */
input:not(:nth-of-type(4n+1))::before { 
  transform: translatex(-85px);
}

/* pseudo-elements other than the first row */
input:nth-of-type(n+5)::after {
 transform: translatey(-60px); 
}

Styling the :checked state

Now comes styling the checkboxes when they are in a :checked state. First, let’s give them a color, say a limegreen background:

input:checked { background: limegreen; }

A checked box should be able to re-style all of its adjacent checked boxes. In other words, if we select the eleventh checkbox in the grid, we should also be able to style the boxes surrounding it at the top, bottom, left, and right.

A four-by-five grid of squares numbered one through 20. 11 is selected and 7, 10, 12, and 15 are highlighted.

This is done by targeting the correct pseudo-elements. How do we do that? Well, it depends on the actual number of columns in the grid. Here’s the CSS if two adjacent boxes are checked in a 5⨉4 grid:

/* a checked box's right borders (if the element to its right is checked) */
input:not(:nth-of-type(4n)):checked + input:checked::before { 
  border-top-right-radius: 0; 
  border-bottom-right-radius: 0; 
  background: limegreen;
}
/* a checked box's bottom borders (if the element below is checked) */
input:nth-last-of-type(n+5):checked + * + * + * + input:checked::after {
  border-bottom-right-radius: 0;
  border-bottom-left-radius: 0;
  background: limegreen;
}
/* a checked box's adjacent (right side) checked box's left borders */
input:not(:nth-of-type(4n)):checked + input:checked + input::before {         
  border-top-left-radius: 0; 
  border-bottom-left-radius: 0; 
  background: limegreen;
}
/* a checked box's adjacent (below) checked box's top borders */
input:not(:nth-of-type(4n)):checked + * + * + * +  input:checked + input::before { 
  border-top-left-radius: 0; 
  border-top-right-radius: 0; 
  background: limegreen;
}

If you prefer you can generate the above code dynamically. However, a typical grid, say an image gallery, the number of columns will be small and likely a fixed number of items, whereas the rows might keep increasing. Especially if designed for mobile screens. That’s why this approach is still an efficient way to go. If for some reason your application happens to have limited rows and expanding columns, then consider rotating the grid sideways because, with a stream of items, CSS Grid arranges them left-to-right and top-to-bottom (i.e. row by row).

We also need to add styling for the last checkboxes in the grid — they’re not all covered by pseudo-elements as they are the last items in each axis.

/* a checked box's (in last column) left borders */
input:nth-of-type(4n-1):checked + input:checked {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}
/* a checked box's (in last column) adjacent (below) checked box's top borders */
input:nth-of-type(4n):checked + * + * + * + input:checked {
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}

Those are some tricky selectors! The first one…

input:nth-of-type(4n-1):checked + input:checked

…is basically saying this:

A checked <input> element next to a checked <input> in the second last column.

And the nth-of-type is calculated like this:

4(0) - 1 = no match
4(1) - 1 = 3rd item
4(2) - 1 = 7th item
4(3) - 1 = 11th item
etc.

So, we’re starting at the third checkbox and selecting every fourth one from there. And if a checkbox in that sequence is checked, then we style the checkboxes adjacent, too, if they are also checked.

And this line:

input:nth-of-type(4n):checked + * + * + * + input:checked

Is saying this:

An <input> element provided that is checked, is directly adjacent to an element, which is directly adjacent to another element, which is also directly adjacent to another element, which, in turn, is directly adjacent to an <input> element that is in a checked state.

What that means is we’re selecting every fourth checkbox that is checked. And if a checkbox in that sequence is checked, then we style the next fourth checkbox from that checkbox if it, too, is checked.

Putting it to use

What we just looked at is the general principle and logic behind the design. Again, how useful it is in your application will depend on the grid design.

I used rounded borders, but you can try other shapes or even experiment with background effects (Temani has you covered for ideas). Now that you know how the formula works, the rest is totally up to your imagination.

Here’s an instance of how it might look in a simple calendar:

Again, this is merely a rough prototype using static markup. And, there would be lots and lots of accessibility considerations to consider in a calendar feature.


That’s a wrap! Pretty neat, right? I mean, there’s nothing exactly “new” about what’s happening. But it’s a good example of selecting things in CSS. If we have a handle on more advanced selecting techniques that use combinators and pseudos, then our styling powers can reach far beyond the styling one item — as we saw, we can conditionally style items based on the state of another element.


Conditionally Styling Selected Elements in a Grid Container originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/conditionally-styling-selected-elements-in-a-grid-container/feed/ 3 366252
CSS Pseudo Commas https://css-tricks.com/css-pseudo-commas/ https://css-tricks.com/css-pseudo-commas/#comments Mon, 30 Aug 2021 21:20:00 +0000 https://css-tricks.com/?p=350670 A bonafide CSS trick if there ever was one! @ShadowShahriar created a CodePen demo that uses pseudo-elements to place commas between list items that are displayed inline, and the result is a natural-looking complete sentence with proper punctuation.

CodePen Embed…


CSS Pseudo Commas originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
A bonafide CSS trick if there ever was one! @ShadowShahriar created a CodePen demo that uses pseudo-elements to place commas between list items that are displayed inline, and the result is a natural-looking complete sentence with proper punctuation.

How it works

The trick? First, it’s to make an unordered list an inline element with no markers or spacing:

ul {
  padding: 0;
  margin: 0;
  display: inline;
  list-style-type: none;
}

Next, we display list items inline so they flow naturally as text in a sentence:

li {
  display: inline;
}

Then we add commas between list items by selecting their ::after pseudo-element, and setting it’s content property with a comma (,) value.

li::after{
  content: var(--separator);
}

Oh, but wait! What about the ol’ Oxford comma? Use :nth-last-of-type() to select the second-to-last list item, and set its ::after pseudo-element’s content property to ", and" before the last list item.

li:nth-last-of-type(2)::after{
  content: ", and ";
}

We’re not done. @ShadowShahriar considers an edge case where there are only two items. All we need is to display an “and” between those two items, so:

li:first-of-type:nth-last-of-type(2)::after {
  content: " and ";
}

I had to look that up on Selectors Explained to make sure I was reading it correctly. That’s saying:

The after pseudo-element

… of a <li> element provided it is the first of its type in its parent and the nth of its type from the end (formula) in its parent.

What a mouthful! The final touch is a period at the end of the list:

li:last-of-type::after {
  content: ".";
}

Using custom properties

We just looked at an abridged version of the actual code. @ShadowShahriar does a nice thing by setting a comma and the “and” as custom properties:

ul {
  --separator: ",";
  --connector: "and";

  padding: 0;
  margin: 0;
  display: inline;
  list-style-type: none;
}

That way, when we can swap those out for other ways to separate list items later. Nice touch.


This caught my eye not only for its clever use of pseudo-element trickery, but also for its simplicity. It’s using tried and true CSS principles in a way that supports semantic HTML — no extra classes, elements, or even JavaScript to help manipulate things. It almost makes me wonder if HTML could use some sort of inline list element (<il> anyone???) to help support sentences convey list items without breaking out of a paragraph.

To Shared LinkPermalink on CSS-Tricks


CSS Pseudo Commas originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/css-pseudo-commas/feed/ 8 350670
:nth-child Between Two Fixed Indexes https://css-tricks.com/nth-child-between-two-fixed-indexes/ https://css-tricks.com/nth-child-between-two-fixed-indexes/#comments Tue, 29 Jun 2021 14:37:21 +0000 https://css-tricks.com/?p=342736 I needed to select some elements between two fixed indexes the other day — like literally the second through fifth elements. Ironically, I have a whole post on “Useful :nth-child Recipes” but this wasn’t one of them.

The answer, it …


:nth-child Between Two Fixed Indexes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
I needed to select some elements between two fixed indexes the other day — like literally the second through fifth elements. Ironically, I have a whole post on “Useful :nth-child Recipes” but this wasn’t one of them.

The answer, it turns out, isn’t that complicated. But it did twist my brain a little bit.

Say you want to select all divs from the second one and beyond:

div:nth-child(n + 2) {

}
/* [ ]  [x]  [x]  [x]  [x]  [x]  [x]  [x], etc. */

That makes logical sense to me. If n is 0, the expression is 2, and n increments upwards from there and selects everything beyond it.

But then how do you “stop” the selecting at a specific index? Like…

/* Not real */
div:nth-child(minmax(2, 5)) {

}
/* [ ]  [x]  [x]  [x]  [x]  [x]  [ ]  [ ], etc. */

Well, we can do the opposite thing, selecting only the first set of elements then stopping (constraining in the other direction) by reversing the value of n.

div:nth-child(-n + 6) {

}
/* [x]  [x]  [x]  [x]  [x]  [ ]  [ ]  [ ], etc. */

That will select the the first five elements and then stop because, as n gets bigger, the expression value goes to 0 and into negative numbers.

So, the CSS trick here is to combine both of those :nth-child expressions.

We know that CSS pseudo-selectors are additive in the sense that they must both be true in order to select them.

a:first-child:hover {
  /* selects the <a> if it is BOTH the first child and in a hover state */
}

To accomplish the idea of “2 and over” and “5 and under” we chain the pseudo-selectors:

div:nth-child(n + 2):nth-child(-n + 6) {
  background: green;
}

That’ll do:

The part that twisted my brain was thinking about “additive” pseudo-selectors. I was thinking that selecting “2 and up” would do just that, and “5 and under” would do just that, and those things combined meant “all elements.” But that’s just wrong thinking. It’s the conditions that are additive, meaning that every element must meet both conditions.

If you found this confusing like I did, wait until you check out Quanity Queries. By nesting a lot of nth-style pseudo-selectors, you can build logic that, for example, only selects elements depending on how many of them are in the DOM.

div:nth-last-child(n+2):nth-last-child(-n+5):first-child, 
div:nth-last-child(n+2):nth-last-child(-n+5):first-child ~ div {
  /* Only select if there are at least 2 and at most 5 */
}

Una broke this down even further for us a while back.


:nth-child Between Two Fixed Indexes originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/nth-child-between-two-fixed-indexes/feed/ 6 342736
Pseudo-Randomly Adding Illustrations with CSS https://css-tricks.com/pseudo-randomly-adding-illustrations-with-css/ https://css-tricks.com/pseudo-randomly-adding-illustrations-with-css/#comments Fri, 17 Apr 2020 20:28:48 +0000 https://css-tricks.com/?p=306866 Between each post of Eric Meyer’s blog there’s this rather lovely illustration that can randomly be one of these five options:

Eric made each illustration into a separate background image then switches out that image with the nth-of-type CSS property, …


Pseudo-Randomly Adding Illustrations with CSS originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Between each post of Eric Meyer’s blog there’s this rather lovely illustration that can randomly be one of these five options:

Eric made each illustration into a separate background image then switches out that image with the nth-of-type CSS property, like this:

.entry:nth-of-type(2n+1)::before {
   background-image: url(image-1.png);
}

.entry:nth-of-type(3n+1)::before {
   background-image: url(image-2.png);
}

.entry:nth-of-type(4n+1)::before {
   background-image: url(image-3.png);
}

.entry:nth-of-type(5n+1)::before {
   background-image: url(image-4.png);
}

This seems like a good time to plug our very own little :nth Tester tool. It definitely helps me understand what something like (2n+1) means in English. You can type in any string you like and see what effect that has on your site:

Anyway, back to Eric’s post. As he mentions, his technique is pseudo-random in that it looks like a random image on the page but it technically isn’t. Either way, I think it’s a really lovely technique! And it certainly breaks up the visual monotony that happens when you’re looking at a website for too long.

Here’s what it looks like in practice:

Lovely stuff!

Another way to do this is to use random numbers in CSS. For example, we could set a variable in JavaScript and then apply it with CSS custom properties. Or we could put all the images in a single sprite file and change the background-position based on a random number.

This is definitely one of those things in CSS where there are no wrong answers; just different ways to do the same awesome thing!

To Shared LinkPermalink on CSS-Tricks


Pseudo-Randomly Adding Illustrations with CSS originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/pseudo-randomly-adding-illustrations-with-css/feed/ 3 306866
CSS :nth-of-class selector https://css-tricks.com/css-nth-of-class-selector/ Mon, 23 Mar 2020 19:08:43 +0000 https://css-tricks.com/?p=305459 That’s not a thing.

But it kinda is!

Bram covers how frustrating .bar:nth-child(2) is. It’s not “select the second element of class .bar.” It’s “select the second element if it also has the class .bar.” The good news? …


CSS :nth-of-class selector originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
That’s not a thing.

But it kinda is!

Bram covers how frustrating .bar:nth-child(2) is. It’s not “select the second element of class .bar.” It’s “select the second element if it also has the class .bar.” The good news? There is a real selector that does the former:

:nth-child(2 of .bar) { }

Safari only. Here are the tickets for Chrome and Firefox.

To Shared LinkPermalink on CSS-Tricks


CSS :nth-of-class selector originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
305459
Staggered CSS Transitions https://css-tricks.com/staggered-css-transitions/ https://css-tricks.com/staggered-css-transitions/#comments Wed, 14 Aug 2019 14:08:47 +0000 https://css-tricks.com/?p=294214 Let’s say you wanted to move an element on :hover for a fun visual effect.

@media (hover: hover) {
  .list--item {
    transition: 0.1s;
    transform: translateY(10px);
  }
  .list--item:hover,
  .list--item:focus {
    transform: translateY(0);
  }
}

Cool cool. But what if you had …


Staggered CSS Transitions originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Let’s say you wanted to move an element on :hover for a fun visual effect.

@media (hover: hover) {
  .list--item {
    transition: 0.1s;
    transform: translateY(10px);
  }
  .list--item:hover,
  .list--item:focus {
    transform: translateY(0);
  }
}

Cool cool. But what if you had several list items, and you wanted them all to move on hover, but each one offset with staggered timing?

The trick lies within transition-delay and applying a slightly different delay to each item. Let’s select each list item individually and apply different delays. In this case, we’ll select an internal span just for fun.

@media (hover: hover) {
  .list li a span {
    transform: translateY(100px);
    transition: 0.2s;
  }
  .list:hover span {
    transform: translateY(0);
  }
  .list li:nth-child(1) span {
    transition-delay: 0.0s;
  }
  .list li:nth-child(2) span {
    transition-delay: 0.05s;
  }
  .list li:nth-child(3) span {
    transition-delay: 0.1s;
  }
  .list li:nth-child(4) span {
    transition-delay: 0.15s;
  }
  .list li:nth-child(5) span {
    transition-delay: 0.2s;
  }
  .list li:nth-child(6) span {
    transition-delay: 0.25s;
  }
}

See the Pen
Staggered Animations
by Chris Coyier (@chriscoyier)
on CodePen.

If you wanted to give yourself a little more programmatic control, you could set the delay as a CSS custom property:

@media (hover: hover) {
  .list {
    --delay: 0.05s;
  }
  .list li a span {
    transform: translateY(100px);
    transition: 0.2s;
  }
  .list:hover span {
    transform: translateY(0);
  }
  .list li:nth-child(1) span {
    transition-delay: calc(var(--delay) * 0);
  }
  .list li:nth-child(2) span {
    transition-delay: calc(var(--delay) * 1);
  }
  .list li:nth-child(3) span {
    transition-delay: calc(var(--delay) * 2);
  }
  .list li:nth-child(4) span {
    transition-delay: calc(var(--delay) * 3);
  }
  .list li:nth-child(5) span {
    transition-delay: calc(var(--delay) * 4);
  }
  .list li:nth-child(6) span {
    transition-delay: calc(var(--delay) * 5);
  }
}

This might be a little finicky for your taste. Say your lists starts to grow, perhaps to seven or more items. The staggering suddenly isn’t working on the new ones because this doesn’t account for that many list items.

You could pass in the delay from the HTML if you wanted:

<ul class="list">
  <li><a href="#0" style="--delay: 0.00s;">① <span>This</span></a></li>
  <li><a href="#0" style="--delay: 0.05s;">② <span>Little</span></a></li>
  <li><a href="#0" style="--delay: 0.10s;">③ <span>Piggy</span></a></li>
  <li><a href="#0" style="--delay: 0.15s;">④ <span>Went</span></a></li>
  <li><a href="#0" style="--delay: 0.20s;">⑤ <span>To</span></a></li>
  <li><a href="#0" style="--delay: 0.25s;">⑥ <span>Market</span></a></li>
</ul>
@media (hover: hover) {
  .list li a span {
    transform: translateY(100px);
    transition: 0.2s;
  }
  .list:hover span {
    transform: translateY(0);
    transition-delay: var(--delay); /* comes from HTML */
  }
}

Or if you’re Sass-inclined, you could create a loop with more items than you need at the moment (knowing the extra code will gzip away pretty efficiently):

@media (hover: hover) {
 
 /* base hover styles from above */

  @for $i from 0 through 20 {
    .list li:nth-child(#{$i + 1}) span {
      transition-delay: 0.05s * $i;
    }
  }
}

That might be useful whether or not you choose to loop for more than you need.


Staggered CSS Transitions originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/staggered-css-transitions/feed/ 16 294214
Some Extremely Handy `:nth-child` Recipes as Sass Mixins https://css-tricks.com/extremely-handy-nth-child-recipes-sass-mixins/ https://css-tricks.com/extremely-handy-nth-child-recipes-sass-mixins/#comments Wed, 17 May 2017 12:18:16 +0000 http://css-tricks.com/?p=254901 There is no such thing as one-size-fits-all styling. An image gallery with three images might need to be styled differently than an image gallery with twelve. There are some cool tricks that you can use to add some number-based logic …


Some Extremely Handy `:nth-child` Recipes as Sass Mixins originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
There is no such thing as one-size-fits-all styling. An image gallery with three images might need to be styled differently than an image gallery with twelve. There are some cool tricks that you can use to add some number-based logic to your CSS! Using :nth-child and :nth-last-child, you can get some surprisingly complex information without ever leaving your stylesheet.

This post will assume that you have a basic understanding of how the :nth-child pseudo-selector works. If you need a quick refresher, Chris has a great post covering that topic.

Writing Complex :nth-child() Selectors

You may be aware that along with :nth-child there is the related :nth-last-child. It works exactly the same as :nth-child except that it starts from the end of the parent. For example, you can select the first three children of a parent by using the selector :nth-child(-n + 3). You can use :nth-last-child(-n + 3) to select the last three. Let’s take a look an unordered list for an example.

See the Pen 1. Selecting The Last Three by Adam Giese (@AdamGiese) on CodePen.

Similarly, you can use :nth-last-child(n + 4) to select all children except the last three.

See the Pen 2. Selecting All But The Last Three by Adam Giese (@AdamGiese) on CodePen.

The real magic happens when you start combining :nth-last-child with :first-child. By using both selectors to see if an element is both the first child of the parent and one of the last three elements, you can style the first element of a parent only if there are at most three elements.

li:nth-last-child(-n + 3):first-child {
  /* your styling here */
}

Continuing with our list example, here is a way to visualize how this works:

See the Pen 3. Chaining Together “first-child” and “last three” by Adam Giese (@AdamGiese) on CodePen.

Conversely, you can use li:nth-last-child(n + 4):first-child to select the first item of a list that has four or more items:

See the Pen 4. At Least Three Selector by Adam Giese (@AdamGiese) on CodePen.

Pretty cool, right? But chances are, you’ll want to style more than just the first item in a list. By using the general sibling selector, you can style any list items that follows this first element. Add both selectors separated by a comma, and you can select all elements.

li:nth-last-child(n + 4):first-child,
li:nth-last-child(n + 4):first-child ~ li {
  /* your styling here */
}

See the Pen 5. At Least Four Selector by Adam Giese (@AdamGiese) on CodePen.

This leads to a lot of interesting possibilities! You also don’t need to just limit yourself to counting the total number of elements. By chaining together :first-child and :nth-last child, you can check if any valid :nth-child expression applies to the total number of elements. You can write styling if there are a total number of odd children, if there are exactly seven children, or if there are 3n + 2 children.

One real world use case that this technique can be used for is styling dropdown menus that have been automatically generated by a CMS. For an example, let’s take a look at the code generated by the WordPress wp_nav_menu() function, cleaned up for readability:

See the Pen WordPress Menu nth-child example by Adam Giese (@AdamGiese) on CodePen.

This looks pretty standard. Hover over the Members menu item, and notice the sub-menu items.

Now, let’s look at the same menu with a few more members added:

See the Pen WordPress Menu nth-child example, more children by Adam Giese (@AdamGiese) on CodePen.

Whoa! The styling that worked fine for four items doesn’t scale well to twelve. By applying the previous example, you can style the WordPress default menu purely in the stylesheet: no need to write a custom filter to change the class depending on the number of menu items: you can keep the styling in the stylesheet.

See the Pen WordPress Menu nth-child example, compact by Adam Giese (@AdamGiese) on CodePen.

Here are some other possible use cases.

Limitations

There are a lot of cool things that you can do with :nth-child. However, there are some limitations. For example, you are not able to style the parent, only the children. You can’t add any styling for a ul by the number of li elements it contains.

Another consideration is whether or not to use :nth-child or :nth-of-type. Using :nth-child will select all of the elements, which may or may not be what you want. For example, if you want to add styling to a .post-content based on the number of paragraphs, you would want to use p:nth-of-type. Unfortunately, using this method you would only be able to style children after (and including) the first paragraph tag. If there were an h2 tag at the beginning of the content, you would not be able to style the heading based on the number of p tags. Additionally, nth-of-type only works on elements: you would not be able to check the quantity of a specific class.

I have found that this trick works best when applied to elements with predictable siblings. li is a perfect candidate, since they are the only valid children of ul and ol. Automatically generated content can also work well.

Abstractions

This is a cool trick, but unfortunately the syntax is a little bit hairy. If you are using Sass, however, you can easily add a layer of abstraction to make it much easier to use! This will make the use of these complex selectors much more readable and intuitive.

Since all of these selectors are based on a single pattern, you can start with a general mixin:

@mixin has-nth($expression, $element: '*') {
  &:nth-last-child(#{$expression}):first-child,
  &:nth-last-child(#{$expression}):first-child ~ #{$element} {
    @content;
  }
}

Which would be called in SCSS using something like:

li {
  @include has-nth('n + 4', 'li') { //four or more
    /* your styling here */
  }
}

While this is definitely less cluttered than writing pure CSS, you can add another layer of abstraction by defining a few more mixins. Here is an example of how to write an at-least mixin:

@mixin at-least($quantity, $element: '*') {
  @include has-nth('n + #{$quantity}', $element) {
    @content;
  }
}

These would be called in the code like this:

li {
  @include at-least(4, 'li') { // four or more
    // styling goes here...
  }
}

Definitely an improvement in readability! You can even chain together mixins by nesting them.

Here is a collection of Sass mixins using some complex nth-child logic.

Future Selectors

There are some additional features that are currently in the W3C Editor’s Draft that could greatly increase the flexibility of this technique. One of these is the selector list argument for nth-child. This works by adding an additional optional argument to the nth-child selector. This works similarly to how the nth-of-type works, except that it works for any selector, not just elements. For example, of you could use the selector li:nth-child(odd of .active) to style every other list item with a class of active. Using this feature, we can detect the quantity of a specific class: for example:

li.active:nth-last-child(n + 5 of .active).first-child,
li:nth-last-child(n + 5 of .active).first-child ~ li.active {
  /* styling goes here... */
}

This will style any active list items if there are at least five. You can read more about the selector list here. Browser support is currently very limited, however; it is only available on Safari (both iOS and OSX).

Another feature is the relational pseudo-class selector. This proposed selector accepts a selector list argument and matches if the selector exists relative to the base selector. For example, you can style ul:has(li) to add styling to any lists with at least on li. You can add much more complicated selectors as well: .post-content:has(h1, h2, h3, h4, h5, h6) can style any .post-content with at least one heading element. Using this feature combined with some of the advanced nth-child recipes that we learned about, we can write ul:has(li:nth-last-child(n + 5):first-child) to style any ul with at least five li.

As of now, styling by quantity is mostly useful for styling element with predictable siblings, such as lists or tables. If these two features become supported, then this technique will be much more flexible.


Some Extremely Handy `:nth-child` Recipes as Sass Mixins originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/extremely-handy-nth-child-recipes-sass-mixins/feed/ 11 254901
Cicada Principle and CSS https://css-tricks.com/cicada-principle-css/ Fri, 07 Oct 2016 13:31:32 +0000 http://css-tricks.com/?p=246249 Charlotte Jackson uses this classic clever technique to pseudo randomize border-radius, making irregular circles for a photo grid.

A cicada is a rather grim looking little bug. You may have heard of them. There is a kind called the Periodical


Cicada Principle and CSS originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Charlotte Jackson uses this classic clever technique to pseudo randomize border-radius, making irregular circles for a photo grid.

A cicada is a rather grim looking little bug. You may have heard of them. There is a kind called the Periodical Cicada, which simultaneously emerge in masses every 7, 11, 13 or 17 years; they find a mate and then they die. It’s not much of a life.

However, the interesting thing is that these numbers are all prime numbers.

Alex Walker dug into this back in 2011 and made some cool demos like randomized non-repeating backgrounds and infinite lego dude variations.

Here’s a demo by yoksel combining the idea with blend modes:

See the Pen The Cicada Principle background + background-blend-mode by yoksel (@yoksel) on CodePen.

To Shared LinkPermalink on CSS-Tricks


Cicada Principle and CSS originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
246249