Как фактор гибкой усадки в отступе и рамке?
Допустим, у нас есть гибкий контейнер шириной 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>
Эта проблема
Однако, когда вводится заполнение, результаты сжатия отличаются. Когда дополнение применяется вместе с 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>
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
,