Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to set proportional grid columns based on content?

Using either Flexbox or CSS Grid, is it possible to size my columns based on the contents of one of the columns?

Here’s What I Want:

I have 2 columns, a main and a side.

|------------------------container--------------------------|
|                                                           |
||----------------------------------------|----------------||
||               main                     |      side      ||
||----------------------------------------|----------------||
|                                                           |
|-----------------------------------------------------------|

I want the side to be automatically sized based on its content, and I want the main to be twice as wide as the side, at a minimum. It can grow bigger, but no smaller.

As the container increases, the main will grow at the same rate, while the side remains its auto width.

|--------------------------container increases----------------------|
|                                                                   |
||------------------------------------------------|----------------||
||                   main increases               |      side      ||
||------------------------------------------------|----------------||
|                                                                   |
|-------------------------------------------------------------------|

The container can shrink down to 3 times as big as the side, at which point the main will be twice as wide as the side. I want this to be the breakpoint.

|--------------------container----------------------|
|                                                   |
||--------------------------------|----------------||
||               main             |      side      ||
||--------------------------------|----------------||
|                                                   |
|---------------------------------------------------|

If the container shrinks any more, I want the columns to stack, where both columns are now 100% width:

|--------------------container--------------------|
|                                                 |
||-----------------------------------------------||
||               main                            ||
||-----------------------------------------------||
||-----------------------------------------------||
||                           side                ||
||-----------------------------------------------||
|                                                 |
|-------------------------------------------------|

Here’s What I’ve Tried:

I tried doing this with Flexbox and with Grid, but I couldn’t get the main column to determine its size based on the side column.

.container-grid {
  display: grid;
  grid-template-columns: 1fr auto; /* works, but doesn’t wrap when left column gets too small */
  /* I also tried the repeat() syntax, but that only worked for similarly-sized columns */
}
.container-flex {
  display: flex;
  flex-wrap: wrap;
}
.main { flex: 2; } .side { flex: 1; } /* same problem, doesn’t wrap */
.main ( flex: 0 1 auto; } .side { flex: 0 0 auto; } /* wraps columns too early, any time main is smaller than intrinsic width */

The only solution I’ve tried that works is knowing the fixed width of the side column (which I would have to predict without knowing its content), and then using a media query at 3 times its width. And of course, the media query only works on window width, not container width, so I would have to calculate the media query using any parent elements of the container.

.container-grid {
  display: grid;
  grid-template-columns: 1fr 15em;
}
@media screen and (max-width: 45em) {
  .container-grid {
    grid-template-columns: 1fr;
  }
}
like image 660
chharvey Avatar asked Oct 29 '22 19:10

chharvey


1 Answers

Here is one solution, using Flexbox, where you use a flex-grow value being very much bigger on main than on side.

With this, the side will fill parent when wrapped, and when on wide screen, with the so much higher value on the main, the flex-growth on side will practically be none.

Combined with a min-width on the main being twice the size of the side, it will wrap before it gets smaller, and for that we can use percent as that is based on parent's width.

So in this case twice the size on main will be 2/3 of parent, 66.666%.

Fiddle demo

Stack snippet

.container-flex {
  display: flex;
  flex-wrap: wrap;
}

.main {
  flex: 10000;
  min-width: 66.666%;
  background: lightblue;
}

.side {
  flex: 1 0 auto;
  background: lightgreen;
}

span {
  display: inline-block;
  padding: 20px;
}
<div class="container-flex">

  <div class="main">
    <span>Fill remain, min. twice the "side"</span>
  </div>

  <div class="side">
    <span>Take content size</span>
  </div>

</div>
like image 131
Asons Avatar answered Nov 16 '22 23:11

Asons