0

I have an HTML Grid in a JSP that will have an unknown amount of columns from 1-3 that need to each be equal width to each other, followed by two more columns at a fixed width

Is there any way to use the grid's own CSS, for example grid-template-columns, to be able to do this? Or would I have to set it on the last two divs directly?

I know fr will make it expand to fill empty space, but I'm not sure how I could make that work with the grid-template-columns

The other alternative would be making a flexbox inside a single div, and set that column to fr, but I wanted to see if there was a way to do it with the grid first

Example mockup:

<div class="grid-div">
  <%-- A list of items, will be from 1-3 --%>
  <c:forEach items="${itemList}" var="item">
    <div>${item.info}</div>
  </c:forEach>
  <div>Checkboxes here</div>
  <div>Buttons here</div>
</div>
.grid-div {
  display: grid;
  gap: 5px;
  grid-template-columns: <something?> 120px 100px;
}

Edit for clarification: The grid as a whole is also a fixed width on the screen, with the two fixed-width columns on the right

The 1-3 variable columns need to evenly split the remaining space on the left

4
  • Could the array have zero items in it or will there always be at least one? Commented Jul 28 at 18:49
  • @AHaworth It will always be a minimum of one Commented Jul 28 at 19:03
  • Are you saying that if there is only 1 initial "flexy" column, it must span all 3 initial columns? It's not quite clear to me what this should look like. Or, the 1st 3 columns (whether there or not) must take up 1/3 each of the space of the 3 column layout and then be followed by the 2 fixed columns. codepen.io/Paulie-D/pen/ZYbBOLe Commented Jul 28 at 19:47
  • @Paulie_D Yes, sorry for not clarifying; the overall grid is a fixed width with two fixed-width columns, the remaining columns from the loop should split the space on the left of the grid evenly between them Commented Jul 28 at 20:07

3 Answers 3

3

You can use the combination :nth-last-child():first-child, something like this:

.grid-div {
  --n: 3;
  display: grid;
  grid-template-columns: repeat(var(--n), 1fr) 120px 100px;
  gap: 6px;
  &:has(:nth-last-child(3):first-child) {
    --n: 1;
  }
  &:has(:nth-last-child(4):first-child) {
    --n: 2;
  }

  /* decor */ 
  div {
    padding: 4px;
    text-align: center;
    border: solid 1px #ccc;
  }
  &:not(:last-child) {
    margin-bottom: 16px;
  }
}
<div class="grid-div">
  <div>1</div>
  <div>Checkboxes here</div>
  <div>Buttons here</div>
</div>
<div class="grid-div">
  <div>1</div>
  <div>2</div>
  <div>Checkboxes here</div>
  <div>Buttons here</div>
</div>
<div class="grid-div">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>Checkboxes here</div>
  <div>Buttons here</div>
</div>

Sign up to request clarification or add additional context in comments.

1 Comment

--n - looks good. Can also --columns, or --col ))
1

You can do this in CSS using grid as long as you can work out whether there are 1, 2 or 3 items in a particular grid-div before the two fixed-sized ones.

I don't know JSP but you'll be able to find the size of itemList.

Put it into the style attribute of the related grid-div as a CSS variable. e.g. if there are 2 items:

<div class="grid-div" style="--n: 2;">

UPDATE @imhvost has shown a CSS-only way of finding --n - see CSS at the end of this post

Set the grid to have 6 columns of size 1fr each and then the two fixed sized ones:

  grid-template-columns: repeat(6, 1fr) 120px 100px;

We can target the 1, 2 or 3 items by counting back from the end of grid-div.

Looking at nth-last-child(3) it will be

if --n=3, in column 5 and spanning 2 columns

if --n=2, in column 3 and spanning 3 columns

if --n=1, in column 1 and spanning 6 columns

These values are obtained by calc(var(--n) * 2 -1) and calc(--n / 2)

Looking at nth-last-child(4) it will be

if --n=3, in column 3 and spanning 2 columns

if --n=2, in columns 4 and spanning 3 columns

These values are obtained by calc(6 - var(--n)) and calc(6 / var(--n))

Looking at nth-last-child(5)

it will be in column 1 and spanning 2 columns

So the CSS for these 3 child items becomes

.grid-div :nth-last-child(3) {
  grid-column: calc(var(--n) * 2 -1) / span calc(--n / 2);
}
.grid-div :nth-last-child(4) {
  grid-column: calc(6 - var(--n)) / span calc(6 / var(--n));
}
.grid-div :nth-last-child(5) {
  grid-column: 1 / span 2;
}

And for the CSS-only way of setting --n:

.grid-div {
  display: grid;
  grid-template-columns: repeat(6, 1fr) 120px 100px;
  gap: 6px;
  --n: 3;
  &:has(:nth-last-child(3):first-child) {
    --n: 1;
  }
  &:has(:nth-last-child(4):first-child) {
    --n: 2;
  }
}

2 Comments

Ah, I didn't know about CSS setting variables on an element like this. In that case, wouldn't it be simpler to set the CSS for the element as grid-column-template: repeat(var(--n), 1fr) 120px 100px? Or would that not work?
That wouldn’t work as it’s a different —n for different rows.
0

Flexbox is more suitable here

.grid-div {
  display: flex;
  margin: 5px;
  gap: 5px;
  div {
    flex: 1;
    padding: 5px;
    border: solid 1px;
  }
  :nth-last-child(1) {flex: 0 100px}
  :nth-last-child(2) {flex: 0 120px}
}
<div class="grid-div">
  <div>1</div>
  <div>Checkboxes </div>
  <div>Buttons </div>
</div>
<div class="grid-div">
  <div>1</div>
  <div>2</div>
  <div>Checkboxes </div>
  <div>Buttons </div>
</div>
<div class="grid-div">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>Checkboxes </div>
  <div>Buttons </div>
</div>

1 Comment

Agreed flexbox is more, well, flexible and doesn’t need anything outside CSS. But the question was wanting to explore whether it could be done with grid.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.