Utilizing CSS Mod Queries with Vary Selectors – A Record Aside

Just lately, I used to be requested to construct a easy checklist that may show in a grid—one that would begin with a single factor and develop all through the day, but alway be tidy whatever the size. So, as you do typically once you’re busy with one factor and requested if you are able to do one thing fully totally different, I attempted to think about any cause why it couldn’t be completed, got here up clean, and distractedly mentioned, “Sure.”

Article Continues Under

On the time, I used to be engaged on a London-based information group’s web site. We’d spent the earlier yr migrating their CMS to the Adobe AEM platform whereas concurrently implementing a responsive UI—each massive enhancements. Since that section was full, we have been beginning to give attention to finessing the UI and constructing new options. The event mission was divided into various small semiautonomous groups. My staff was specializing in hub pages, and I used to be main the UI effort.

Every hub web page is actually a listing of lists, merely there to assist readers discover content material that pursuits them. As you possibly can think about, a information web site is sort of solely made from content material lists! A web page filled with generic vertical lists could be unhelpful and unappealing; we needed readers to take pleasure in shopping the content material associated to their sphere of curiosity. Sections wanted to be distinct and the lists needed to be each individually distinguishable and sit harmoniously collectively. Briefly, the visible show was essential to the usability and effectiveness of the complete web page.

That “easy checklist” I mentioned I’d construct could be excessive profile, sitting in its personal panel close to the highest of a hub web page and serving to spotlight a particular focal point. Beginning with one merchandise and rising all through the day as associated articles have been revealed, the checklist wanted to be an oblong grid fairly than a single column, and by no means have “leftover” objects within the final row. And regardless of what number of little one components it contained at any given second, it needed to keep tidy and neat as a result of it will show above the fold. Every merchandise could be roughly sq., with the primary merchandise set at 100% width, the second two at 50%, and all subsequent objects 33% and organized in rows of three. My easy checklist out of the blue wasn’t so easy.

Not everybody needs a generic grid or stack of similar objects—there’s one thing good about selective prominence, grouped components, and swish line endings. These kinds might be hardcoded if the checklist will all the time be an actual size, but it surely turns into extra of a problem when the size can change. How may I hold that final row tidy when there have been fewer than three objects?

Various arrangements of list items that do and do not break the planned layout in the bottom row.
Our meant format would break visually as extra objects have been added to the checklist.

When it got here to really constructing the factor, I noticed that realizing the size of the checklist wasn’t very useful. Having beloved Heydon Pickering’s wonderful article on amount queries for CSS, I assumed I may discover out the size of the checklist utilizing QQs, then model it accordingly and all could be fantastic.

However since my checklist could possibly be any size, I’d want an infinite variety of QQs to fulfill the necessities! I couldn’t have a QQ for each eventuality. Plus, there have been rumors a “Load Extra” button is likely to be added down the highway, letting customers dynamically inject one other 10 or so objects. I wanted a special resolution.

After a minor meltdown, I requested myself, What would Lea Verou do? Properly, not panicking could be an excellent begin. Additionally, it will assist to simplify and determine the underlying necessities. Because the checklist would basically comprise rows of three, I wanted to know the rest from mod 3.

The “mod” question#section2

Having the ability to choose and magnificence components by the variety of siblings is nice, however there’s extra to this than mere size. On this case, it will be a lot better to know if my checklist is divisible by a sure quantity fairly than how lengthy it’s.

Sadly, there isn’t a local mod question in CSS, however we are able to create one by combining two selectors: :nth-child(3n) (aka the “modulo” selector) and the :first-child selector.

The next question selects all the pieces if the checklist is divisible by three:

li:nth-last-child(3n):first-child,
li:nth-last-child(3n):first-child ~ li { 
 … selects all the pieces in a listing divisible by three … 
}
Four rows of list items (cats in boxes). The top and bottom rows are selected (full color, not grayed out) because each is divisible by 3.
Solely these rows divisible by three are chosen. See the Pen Utilizing CSS Mod Queries with Vary Selectors: Fig 2 by Patrick (@clanceyp) on CodePen. Cat picture through Paper Chicken Publishing.

Let’s discuss via that code. (I take advantage of li for “checklist merchandise” within the examples.)

The css selector:

li:nth-last-child(3n):first-child ~ li

Choose all following siblings:

... ~ li

The primary little one (first li within the checklist, on this case):

...:first-child ...

Each third merchandise ranging from the tip of the checklist:

...:nth-last-child(3n):...

That mixture principally means if the primary little one is 3n from the tip, choose all of its siblings.

The question selects all siblings of the primary merchandise, however doesn’t embrace the primary merchandise itself, so we have to add a selector for it individually.

li:nth-last-child(3n):first-child,
li:nth-last-child(3n):first-child ~ li { 
… kinds for checklist objects in a listing divisible by 3 …  
}

Try the demo and provides it a strive!

What about remainders? #section3

With my mod question, I can choose all of the objects in a listing if the checklist is divisible by three, however I’ll want to use totally different kinds if there are remainders. (Within the case of the rest 1, I’ll simply have to depend again within the CSS from the second-to-last factor, as an alternative of the final. This may be achieved by merely including +1 to the question.)

li:nth-last-child(3n+1):first-child,
li:nth-last-child(3n+1):first-child ~ li { 
… kinds for components in checklist size, mod 3 the rest = 1 …  
}

Ditto for the rest 2—I simply add +2 to the question.

li:nth-last-child(3n+2):first-child,
li:nth-last-child(3n+2):first-child ~ li { 
… kinds for components in checklist size, mod 3 the rest = 2 …  
} 

Creating a variety selector#section4

Now I’ve a solution to decide if the checklist size is divisible by any given quantity, with or with out remainders, however I nonetheless want to pick out a variety. As with mod question, there isn’t a local CSS vary selector, however we are able to create one by combining two selectors: :nth-child(n) (i.e., “all the pieces above”) and :nth-child(-n) (i.e., “all the pieces beneath”).

This enables us to pick out objects 3 to five, inclusive:

li:nth-child(n+3):nth-child(-n+5){ 
... kinds for objects 3 to five inclusive ...
}
A row of six list items (graphics of cats in boxes). The two on the left are grayed out, followed by three “selected” cats in full color, and the one on the right is grayed out.
We’ve chosen a variety: cats 3, 4, and 5.

True, that would simply as simply be achieved with easy :nth-child(n) syntax and focusing on the merchandise positions straight—li:nth-child(3), li:nth-child(4), li:nth-child(5){ ... }—however defining a begin and finish to a variety is clearly way more versatile. Let’s shortly unpack the selector to see what it’s doing.

Selects all of the objects as much as and together with the fifth merchandise:

li:nth-child(n+3):nth-child(-n+5){ … }

Selects all of the objects from the third merchandise onwards:

li:nth-child(n+3):nth-child(-n+5){ … }

Combining the 2—li:nth-child(n+3):nth-child(-n+5)—creates a variety selector.

If we have a look at an instance, we’d have a product grid the place the checklist objects comprise a picture, title, and outline. Let’s say the product picture speaks for itself, so within the first row we promote the picture and conceal all of the textual content. With the second and third row, we show the title and picture as a thumbnail, whereas in subsequent rows we disguise the picture and present the title and outline on a single line.

A grid of three cat graphics in a top row, then two rows of  blocks each comprising a cat graphic and a product title, then four rows each listing text for product title and  product details.
A product grid of our cats. We have now standalone graphics within the high row, small graphics plus product titles within the second and third rows, after which we lose the graphics and solely present textual content for all rows after that. See the Pen Utilizing CSS Mod Queries with Vary Selectors: Fig 4 by Patrick (@clanceyp) on CodePen.

Through the use of the vary selector, we are able to choose the primary three, the fourth via ninth, and the tenth onwards. This enables us to vary the ranges at totally different breakpoints within the CSS so we are able to hold our product grid good and responsive.

Notes on SCSS mixins#section5

Since I used to be utilizing a CSS preprocessor, I simplified my code through the use of preprocessor features; these are SCSS mixins for creating vary selectors and mod queries.

// vary selector mixin
@mixin select-range($begin, $finish){
  &:nth-child(n+#{$begin}):nth-child(-n+#{$finish}){
   @content material;
   }
}
// mod question mixin
@mixin mod-list($mod, $the rest){
  &:nth-last-child(#{$mod}n+#{$the rest}):first-child,
  &:nth-last-child(#{$mod}n+#{$the rest}):first-child ~ li {
    @content material;
    }
}

Then in my code I may nest the mixins.

li {
@embrace mod-list(3, 0){
  @embrace select-range(3, 5){
    // kinds for objects 3 to five in a listing mod 3 the rest = 0
    }
  }
}

Which is, if nothing else, a lot simpler to learn!

Placing all of it collectively#section6

So now that I’ve slightly arsenal of instruments to assist me cope with mods, ranges, and ranges inside mods, I can break free from standard-implementation mounted size or fixed-layout lists. Inventive use of mod queries and vary selectors lets me apply kinds to vary the format of components.

Getting again to the unique requirement—getting my checklist to behave—it turned clear that if I styled the checklist assuming it was a a number of of three, then there would solely be two different use circumstances to help:

  • Mod 3, the rest 1
  • Mod 3, the rest 2

If there was one remaining merchandise, I’d make the second row take three objects (as an alternative of the default two), but when the rest was 2, I may make the third row take two objects (with the fourth and fifth objects at 50%).

Ultimately, I didn’t want quite a few queries in any respect, and those I did want have been truly fairly easy.

There was one particular case: What if the checklist solely contained two components?

That was solved with a question to pick out the second merchandise when it’s additionally the final little one.

li:nth-child(2):last-child { 
... kinds for the final merchandise if it’s additionally the second merchandise ...
}

The queries finally weren’t as exhausting as I’d anticipated; I simply wanted to mix the mod and vary selectors.

li:nth-last-child(3n):first-child /* mod question */ 
~ li:nth-child(n+3):nth-child(-n+5){ /* vary selector */
... kinds for third to fifth components, in a listing divisible by 3 ...
}

Altogether, my CSS seemed one thing like this in the long run:

/* 
  default settings for checklist (when its mod 3 the rest 0)
  checklist objects are 33% broad
  besides; the primary merchandise is 100% 
          the second and third are 50%
*/
li {
  width: 33.33%;
}
li:first-child {
  width: 100%;
}
/* vary selector for 2nd and third */
li:nth-child(n+2):nth-child(-n+3){
  width: 50%;
}
/* overrides */
/* mod question override, test for mod 3 the rest = 1 */  
li:nth-last-child(3n+1):first-child ~ li:nth-child(n+2):nth-child(-n+3) {
  width: 33.33%; /* override default 50% width for 2nd and third objects */
}
/* mod question override, test for mod 3 the rest = 2 */ 
li:nth-last-child(3n+2):first-child ~ li:nth-child(n+4):nth-child(-n+5) {
  width: 50%; /* override default 33% width for 4th and fifth objects */
}
/* particular case, checklist comprises solely two objects */
li:nth-child(2):last-child {
  margin-left: 25%;
}

Expertise for your self (and a word on browser help)#section7

The mod queries and vary selectors used on this article depend on the CSS3 selectors, so they are going to work in all fashionable browsers that help CSS3, together with Web Explorer 9 and above (however bear in mind, IE will count on a legitimate doctype).

I created a small mod question generator that you should use to experiment with mod queries.

Once I first got here throughout QQs, I assumed they have been nice and attention-grabbing however largely theoretical, with out many sensible real-world use circumstances. Nonetheless, with cellular utilization outstripping desktop, and responsive design now the norm, the necessity to show lists, goal components of lists relying on the size/mod, and show lists otherwise at totally different breakpoints has grow to be way more frequent. This actually brings the sensible software of QQs into focus, and I’m discovering greater than ever that they’re a vital a part of the UI developer’s toolkit.

Extra sources#section8

Leave a Comment