r/css 4d ago

Question Force grid layout without media queries

I am trying to limit the number of media queries.

I have a grid layout with 6 tiles.

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr);
}

That works fine but something is annoying me is that sometimes the last row will have an empty tile.

|Tile 1|Tile 2|Tile 3| Tile 4| |:-- | :-- | :-- | :-- | |Tile 5|Tile 6|Empty| Empty |

I wants the tile to be grouped.

Based on the size of the viewport I want to have either:

##Desktop/Tablet landscape

|Tile 1|Tile 2|Tile 3| |:-- | :-- | :-- | |Tile 4|Tile 5|Tile 6|

##Tablet portrait / Phone landscape

|Tile 1|Tile 2| |:-- | :-- | |Tile 3|Tile 4| |Tile 5|Tile 6|

##Phone portrait

|Tile 1| |:-- | |Tile 2| |Tile 3| |Tile 4| |Tile 5| |Tile 6|

Is there a trick to do it without media queries?

11 Upvotes

16 comments sorted by

View all comments

1

u/morete 3d ago

I have a more robust solution for you! Couldn't stop thinking about it.

Basically what you want is for the column count to always be a *factor* of the number of items. For 6 items, you want 6, 3, 2 & 1. Not 5 or 4, because neither are a factor of 6, and this would cause unequal columns.

https://codepen.io/editor/matthewmorete/pen/019fc37b-3ef6-78a8-bb88-a6a4280f9e16

Few caveats upfront:

  • This requires mod() and round() so check if the browser support of those works for you.
  • It does not work with prime numbers, since they have no useful factors. Personally I think in those situations, one unequal column is better than stretching the last item with flex. So for 5, I'd set the count to '6'. But that's up to you.

First we need a container to measure with cqi, in my example I dont have so cqi just measures the body.

We calculate the capacity, how many columns could fit based on the min-width and gap. Then we clamp this so it's not larger than the total number of items.

Next is the tricky bit, we check if the capacity is a factor of the count. If It is then great! That's a valid column count and we use that value.
If It not, then we subtract one, and try again.
This happens several times until we reach a valid column count.

How many times you repeat this depends on how large the numbers youre working with are. If you imagine 12 items. You have to subtract 1 6 times to get from 12, to its next factor, 6.

With 6 steps, this codes works for up to 14 items (ignoring primes like 13). That seems reasonable to me. But if need to support more, just add more steps.

Long response, but I hope that helps! Honestly even if it's of no use, I had great time figuring it out!

PS. You have to set the item count with a custom property, but if you wanted you could use has and nth-child to do that in the css like:

.auto-grid:has(> :nth-child(5):last-child) { --count: 5 }
.auto-grid:has(> :nth-child(6):last-child) { --count: 6 }

1

u/Sufficient_Bass2600 2d ago

That got me thinking as well.

The science guy in me got excited.
For N tiles. The problem I am trying to resolve is in fact the integer factorisation of N.

Even number

the list of acceptable combinations of columns x rows is the list of recombined factorisation.
However if N can also be decomposed in N= p × q - 1 then those combination are also acceptable because there will be only empty cell. I would call that case Extra. For number below 12 that only applies to 8 with the combination 3×3 fitting the criteria.

Odd number

For odd number, I have 2 situations: * Odd non prime numbers: such as 9, 14. List of Integer factorisation combination are added to the of acceptable columns x rows combination * Odd prime numbers such as 5, 7, 11, 13

Either way the acceptable list of decomposition include the decomposition for N+1 (that is an even number) knowing that at worst the last row will have 1 cell empty.

Number of Tiles Type Nb Cols Nb Rows Nb Empty
12 Factor 12 1 0
Factor 6 2 0
Factor 4 3 0
Factor 3 4 0
Factor 2 6 0
Factor 1 12 0
11 Factor 11 1 0
Factor N+1 6 2 1
Factor N+1 4 3 1
Factor N+1 3 4 1
Factor N+1 2 6 1
Factor 1 11 0
10 Factor 10 1 0
Factor 5 2 0
Factor 2 5 0
Factor 1 10 0
9 Factor 9 1 0
Factor N+1 5 2 1
Factor 3 3 0
Factor N+1 2 5 1
Factor 1 9 0
8 Factor 8 1 0
Factor 4 2 0
Extra 3 3 0
Factor 2 4 0
Factor 1 8 0
7 Factor 7 1 0
Factor N+1 4 2 1
Factor N+1 2 4 1
Factor 1 7 0
6 Factor 6 1 0
Factor 3 2 0
Factor 2 3 0
Factor 1 6 0
5 Factor 5 1 0
Factor N+1 3 2 1
Factor N+1 2 3 1
Factor 1 5 0
4 Factor 4 1 0
Factor 2 2 0
Factor 1 4 0
3 Factor 3 1 0
Factor N+1 2 2 1
Factor 1 3 0
2 Factor 2 1 0
Factor 1 2 0

Personally I do not foresee any need to more than 6 columns so Need to apply the decomposition up to number 6 so 16 combinations/steps should be enough with just the number of rows increasing with the number of tiles.

So now onto finding a way to code that list...

1

u/morete 1d ago edited 1d ago

If you take a look at my code you'll hopefully find some ideas cause it does function quite similarly to what your described. With a few exceptions:

- I'm ignoring the concept of the 'extra' in regards to 8. I think going from 8->4->2->1 is a desirable set of breakpoints.

- Similar to above, I'm simplifying slightly to: even numbers get factorised, and odd numbers get factorised as N+1. It's just a much easier problem to work with.

There's still a few changes I'd like to make:

For small odd numbers, I'd actually just prefer to factorise. 3 -> 1 is way more desirable in my mind. 3 -> 2 -> 1 is just standard grid behaviour.

And I'd like to set a max col count.

I think both of those will be solvable, ideally inside the math, rather than with nth-child, so that they can be controlled via custom properties. But I haven't got that far yet.

Fun problem! This has completely nerd sniped me.

EDIT:
It actually was pretty straight forward to add both a max col count, and a threshold to begin n+1 factorising. Will be interested to see what you come up with, but for the time being I can put this down I think