Как фактор гибкой усадки в отступе и рамке?

Допустим, у нас есть гибкий контейнер шириной 400 пикселей.

Внутри этого контейнера находятся три гибких предмета:

:nth-child(1) { flex: 0 2 300px; }   /* flex-grow, flex-shrink, flex-basis */
:nth-child(2) { flex: 0 1 200px; }
:nth-child(3) { flex: 0 2 100px; }

Таким образом, общая ширина гибких элементов составляет 600 пикселей, а свободное пространство в контейнере -200 пикселей.

С помощью этого вопроса, этой статьи и спецификации flexbox я выучил базовую формулу для распределения отрицательного свободного пространства среди элементов flex:

Шаг 1

Умножьте каждое значение сжатия на его основу и сложите их все вместе:

:nth-child(1)  2 * 300 = 600
:nth-child(2)  1 * 200 = 200
:nth-child(3)  2 * 100 = 200

ИТОГО = 1000

Шаг 2

Разделите каждый элемент выше на общую сумму, чтобы определить коэффициент сжатия:

:nth-child(1)  600 / 1000 = .6
:nth-child(2)  200 / 1000 = .2
:nth-child(3)  200 / 1000 = .2

Шаг 3

Умножьте коэффициент сжатия на отрицательное свободное пространство, чтобы определить пространство, удаленное от каждого элемента:

:nth-child(1)  .6 * -200px = -120px
:nth-child(2)  .2 * -200px =  -40px
:nth-child(3)  .2 * -200px =  -40px

Итак, вычисляемый размер каждого элемента flex должен быть:

:nth-child(1)  300px - 120px = 180px
:nth-child(2)  200px -  40px = 160px
:nth-child(3)  100px -  40px =  60px

Проверенные в Chrome, Firefox и IE11 цифры проверены. Расчет работает отлично.

.flex {
  display: flex;
  width: 400px;
  height: 50px;
  margin: 0;
  padding: 0;
  list-style: none;
  text-align: center;
}

.flex li:nth-child(1) {
  flex: 0 2 300px;
  background: orange;
}

.flex li:nth-child(2) {
  flex: 0 1 200px;
  background: chartreuse;
}

.flex li:nth-child(3) {
  flex: 0 2 100px;
  background: aqua;
}
<ul class="flex1 flex">
  <li>180px</li>
  <li>160px</li>
  <li>60px</li>
</ul>

jsFiddle demo


Эта проблема

Однако, когда вводится заполнение, результаты сжатия отличаются. Когда дополнение применяется вместе с box-sizing: border-box это приводит к еще одному набору чисел.

введите описание изображения здесь

Что такое flex-shrink расчет при padding а также box-sizing вовлечены?

.flex {
  display: flex;
  width: 400px;
  height: 50px;
  margin: 0;
  padding: 0;
  list-style: none;
  text-align: center;
  border-bottom: 1px solid #ccc;
}

.flex li:nth-child(1) {
  flex: 0 2 300px;
  background: orange;
}

.flex li:nth-child(2) {
  flex: 0 1 200px;
  background: chartreuse;
}

.flex li:nth-child(3) {
  flex: 0 2 100px;
  background: aqua;
}

.flex2 li {
  padding: 0 10px;
}

.flex3 li {
  padding: 0 10px;
  box-sizing: border-box;
}
<ul class="flex1 flex">
  <li>180px</li>
  <li>160px</li>
  <li>60px</li>
</ul>

<ul class="flex2 flex">
  <li>144px</li>
  <li>148px</li>
  <li>48px</li>
</ul>

<ul class="flex3 flex">
  <li>175.5px</li>
  <li>160px</li>
  <li>64.4px</li>
</ul>

jsFiddle demo

2 ответа

Решение

Flexbox определяет это как

Для каждого незамерзшего предмета на линии умножьте его коэффициент усадки на изгиб на его внутренний размер базового изгиба и отметьте его как масштабированный коэффициент усадки. Найти отношение масштабного коэффициента изгиба элемента к сумме масштабированных коэффициентов изгибания всех незамерзших элементов в строке. Установите целевой основной размер элемента равным его базовому размеру за вычетом доли абсолютного значения оставшегося свободного пространства, пропорционального отношению.

Упрощенные, замороженные изогнутые элементы - это те, которые не могут или не должны больше сгибаться. Я приду нет min-width ограничения и ненулевые гибкие факторы сжатия. Таким образом, все flex-элементы изначально размораживаются, и все они замораживаются после одной итерации цикла flex.

Размер внутреннего гибкого основания зависит от значения box-sizing определяется CSS2UI как

  • content-box: Указанные ширина и высота (и соответствующие свойства min/max) применяются к ширине и высоте соответственно поля содержимого элемента. Обивка и граница элемента размечаются и выводятся за пределы указанной ширины и высоты.

  • border-box: Значения длины и процента для ширины и высоты (и соответствующие свойства min/max) для этого элемента определяют границу рамки элемента. То есть любые отступы или границы, указанные в элементе, размечаются и отрисовываются внутри указанного width а также height, Ширина и высота содержимого вычисляются путем вычитания ширины границ и отступов соответствующих сторон из указанных свойств ширины и высоты. [...] Используемые значения, представленные, например, через getComputedStyle(), также относятся к рамке границы.

По сути, это означает, что размеры (ширина, гибкие основания) имеют внутренний и внешний варианты. Внутренний размер включает только содержимое, внешний также включает отступы и ширину границ. Длина, указанная в таблице стилей, будет использоваться в качестве внутреннего размера в случае box-sizing: content-box или как внешний в случае box-sizing: border-box, Другой может быть рассчитан путем сложения или вычитания ширины границ и отступов.

Пренебрегая множеством деталей, алгоритм будет что-то вроде

let sumScaledShrinkFactors = 0,
    remainingFreeSpace = flexContainer.innerMainSize;
for (let item of flexItems) {
  remainingFreeSpace -= item.outerFlexBasis;
  item.scaledShrinkFactor = item.innerFlexBasis * item.flexShrinkFactor;
  sumScaledShrinkFactors += item.scaledShrinkFactor;
}
for (let item of flexItems) {
  let ratio = item.scaledShrinkFactor / sumScaledShrinkFactors;
  item.innerWidth = item.innerFlexBasis + ratio * remainingFreeSpace;
}

Без прокладок, это как вы объясняете

                                   (width)
                                   innerW │ padd │ outerW
                                   ───────┼──────┼───────
300px * (1 + 2 / 1000px * -200px) = 180px │  0px │  180px
200px * (1 + 1 / 1000px * -200px) = 160px │  0px │  160px
100px * (1 + 2 / 1000px * -200px) =  60px │  0px │   60px
                                   ───────┼──────┼───────
                                    400px │  0px │  400px

С 10px горизонтальные отступы, доступное пространство уменьшается на 3 * 2 * 10px = 60px так что теперь это -260px,

                                   (width)
                                   innerW │ padd │ outerW
                                   ───────┼──────┼───────
300px * (1 + 2 / 1000px * -260px) = 144px │ 20px │  164px
200px * (1 + 1 / 1000px * -260px) = 148px │ 20px │  168px
100px * (1 + 2 / 1000px * -260px) =  48px │ 20px │   68px
                                   ───────┼──────┼───────
                                    340px │ 60px │  400px

Когда вы используете box-sizing: border-box указанные гибкие основы являются внешними, поэтому из них вычитаются отступы для вычисления внутренних, которые 280px, 180px, 80px, Тогда сумма масштабированных коэффициентов гибкой усадки становится 2*280px + 180px + 2*80px = 900px, Доступное пространство такое же, как и в случае без заполнения, потому что внешние гибкие основания одинаковы. Обратите внимание width получено getComputedStyle теперь будет внешним, так что отступы добавляются в конце.

                                                    (width)
                                    innerW │ padd │  outerW
                                   ────────┼──────┼────────
280px * (1 + 2 / 900px * -200px) ≈ 155.6px │ 20px │ 175.6px
180px * (1 + 1 / 900px * -200px) = 140.0px │ 20px │ 160.0px
 80px * (1 + 2 / 900px * -200px) ≈  44.4px │ 20px │  64.4px
                                   ────────┼──────┼────────
                                   340.0px │ 60px │ 400.0px

В дополнение к ответу Ориола (который он теперь обновил), padding / border-box будет

280px * (1 + 2 / 900px * -200px) + 20px = 175.5px
180px * (1 + 1 / 900px * -200px) + 20px = 160px
 80px * (1 + 2 / 900px * -200px) + 20px = 64.4px

где кажется, что отступ сначала удаляется из flex-base, а затем снова добавляется после фактического расчета, что имеет некоторый смысл, поскольку именно это происходит с padding,

Другие вопросы по тегам