Можно ли установить пропорциональные столбцы сетки на основе содержимого?

Используя Flexbox или CSS Grid, можно ли изменить размер моих столбцов на основе содержимого одного из столбцов?

Вот что я хочу:

У меня есть 2 столбца: основной и боковой.

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

Я хочу, чтобы размер стороны автоматически определялся в зависимости от ее содержимого, и я хочу, чтобы основная была в два раза шире, чем сторона, при минимум. Он может стать больше, но не меньше.

По мере увеличения контейнера основной будет увеличиваться с той же скоростью, в то время как боковая ширина останется автоматической.

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

Контейнер может уменьшиться в 3 раза по сравнению с стороной, после чего основная будет в два раза шире стороны. Я хочу, чтобы это было точкой останова.

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

Если контейнер еще больше сжимается, я хочу, чтобы столбцы складывались, и теперь оба столбца имеют ширину 100%:

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

Вот что я пробовал:

Я пытался сделать это с помощью Flexbox и Grid, но не смог заставить основной столбец определять свой размер на основе бокового столбца.

.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 */

Единственное работающее решение, которое я пробовал, — это знание фиксированной ширины бокового столбца (которую мне пришлось бы предсказывать, не зная его содержимого), а затем использование медиа-запроса в 3 раза больше его ширины. И, конечно же, медиа-запрос работает только с шириной окна, а не с шириной контейнера, поэтому мне пришлось бы вычислять медиа-запрос, используя любые родительские элементы контейнера.

.container-grid {
  display: grid;
  grid-template-columns: 1fr 15em;
}
@media screen and (max-width: 45em) {
  .container-grid {
    grid-template-columns: 1fr;
  }
}

person chharvey    schedule 08.02.2018    source источник


Ответы (1)


Вот одно из решений, использующее Flexbox, где вы используете значение flex-grow, которое намного больше для main, чем для side.

При этом side заполнит родительский элемент при переносе, а на широком экране, с гораздо более высоким значением main, flex-growth на side практически не будет.

В сочетании с min-width на main, который вдвое превышает размер side, он будет обертываться до того, как станет меньше, и для этого мы можем использовать процент, поскольку он основан на ширине родителя.

Таким образом, в этом случае удвоенный размер main будет составлять 2/3 родителя, 66,666%.

демонстрация скрипта

Фрагмент стека

.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>

person Ason    schedule 08.02.2018
comment
Мне кажется идеальным решением .... Я не понимаю ваш комментарий ближе всего я могу прийти - person vals; 08.02.2018
comment
@vals Спасибо ... изменю эту часть, потому что, когда вы так говорите, это звучит странно :) - person Ason; 08.02.2018
comment
@vals Я представляю себе часть «ближе всего я могу подойти», потому что это кажется немного хакерским: установка flex-grow на произвольно большое число. Но похоже, что это может сработать, поэтому я готов попробовать. - person chharvey; 08.02.2018
comment
@chharvey Да, это правильно. И причина в том, что необходимо установить flex-grow на 1 в side, иначе он не заполнит родителя при обертке, но при разворачивании flex-grow на main должен быть достаточно большим, поэтому, когда остается место, после уменьшения содержимого, рассчитывается, main должен занять все, иначе side тоже немного вырастет. Так что технически side получит 1/10001 оставшегося места, а main получит 10000/10001, поэтому я сказал ближайший :) - person Ason; 09.02.2018
comment
@LGSon - Ваша логика совершенно верна; Просто я обычно так не думаю, когда пишу CSS. Обычно в CSS есть свойство или значение, которое делает именно то, что я хочу… большую часть времени. Вот почему я назвал ваш метод немного «хакерским». Но это решает проблему, поэтому я отмечаю его как решение, пока не появится лучшее решение! (FTR, я использовал 999999, потому что это выше и легче набирать.) - person chharvey; 09.02.2018
comment
Ооо, я только сейчас понял, что вы можете использовать flex: 999999 0 66.666%; вместо min-width, так что это решение также может работать для flex-direction: column;. - person chharvey; 06.03.2018
comment
@chharvey Технически, при установке initial flex-basis в сочетании с flex-shrink равным нулю, да, хотя проверьте, полностью ли кроссбраузерны, так как в некоторых ситуациях вложенный гибкий элемент с использованием flex-basis с процентами не всегда работает, следовательно, width или min-width может понадобиться. - person Ason; 06.03.2018
comment
@chharvey Также обратите внимание, что использование процентов для height элемента может быть проблематичным, поскольку элементы не выбирают процент на основе height так же, как это делается с width, и это связано с тем, что обычное значение height по умолчанию для элементов равно auto, а для width это 100%. - person Ason; 06.03.2018