-
-
Notifications
You must be signed in to change notification settings - Fork 261
Description
The free space distribution algorithm in litehtml doesn't exactly match the one outlined in the spec, which leads to incorrect rendering in certain situations. I have multiple examples here, where litehtml doesn't work correctly, each of which is a different deviation from the spec, but I though it would be simpler to just make one issue for all of them.
When growing, the initial sum of flex grow factors is used, rather than the sum of unfrozen items
Step 4.c
says: (emphasis mine)
If using the flex grow factor
Find the ratio of the item’s flex grow factor to the sum of the flex grow factors of all unfrozen items on the line. Set the item’s target main size to its flex base size plus a fraction of the remaining free space proportional to the ratio.
But litehtml always uses the initial sum, which means when an item is clamped to its max size, other items grow less than they should. This in itself is fairly easy to fix tough.
Example
<!DOCTYPE html>
<head>
<style>
.flexbox {
display: flex;
flex-direction: row;
justify-content: space-around;
width: 500px;
background-color: blue;
}
.item1 {
flex-grow: 10;
width: 10px;
max-width: 15px;
background-color: red;
}
.item2 {
flex-grow: 1;
width: 10px;
background-color: green;
}
</style>
</head>
<html>
<div class="flexbox">
<span class="item1"></span>
<span class="item2">hello</span>
<span class="item2">world</span>
</div>
</html>
Used flex factor is determined from flex base sizes, rather than hypothetical main sizes
Step 1
says that to determined whether the items need to shrink or grow, one should "sum the outer hypothetical main sizes of all items on the line" and compare that to the container's main size.
However litehtml instead compares the container's main size with the sum of the items' flex base size. (The difference between the two is mostly that the hypothetical main size is clamped between the min and max main sizes.)
Take an example where a flex item has a small base size, but large min size, which combined with the base size of some other item overflows the container. The correct behavior is to clamp the first item to its min size and shrink the other one. Litehtml instead will try to grow both items.
Example
<!DOCTYPE html>
<head>
<style>
.flexbox {
display: flex;
flex-direction: row;
justify-content: space-around;
width: 500px;
height: 20px;
background-color: blue;
}
.item1 {
flex-grow: 0;
flex-shrink: 1;
width: 10px;
min-width: 400px;
height: 10px;
background-color: red;
}
.item2 {
flex-grow: 0;
flex-shrink: 1;
width: 200px;
height: 10px;
background-color: green;
}
</style>
</head>
<html>
<div class="flexbox">
<span class="item1">hello</span>
<span class="item2">world</span>
</div>
</html>
Flex factor sums less than one are handled incorrectly
The algorithm in the spec handles flex factor sums less then one in the remaining free space calculation in step 4.b
.
Litehtml instead only checks for this once at the start of the algorithm. This leads to incorrect behavior if the sum flex factor becomes less than one due to an item getting frozen.
The example is from here: https://stackoverflow.com/questions/76291155/understanding-flex-shrink-when-the-value-is-less-than-1
The hypothetical main sizes overflow the container, so shrinking happens. The first item gets clamped to its min size. The remaining second item has a flex shrink factor less than one, so it shouldn't shrink all the way down to fit the container, it should overflow. In litehtml there is no overflow.
Details
<!DOCTYPE html>
<head>
<style>
.flexbox {
display: flex;
flex-direction: row;
justify-content: space-around;
width: 220px;
height: 20px;
background-color: blue;
}
.item1 {
flex-shrink: 1;
width: 200px;
min-width: 100px;
height: 10px;
background-color: red;
}
.item2 {
flex-shrink: .25;
width: 200px;
min-width: 100px;
height: 10px;
background-color: green;
}
</style>
</head>
<html>
<div class="flexbox">
<span class="item1">hello</span>
<span class="item2">world</span>
</div>
</html>
To handle this correctly requires taking the initial free space calculated in step 3
, which also might not be entirely right here, since litehtml doesn't do step 2
, where inflexible items are frozen.
Min/max violations are not always handled correctly
The way min/max violations are handled is different between litehtml and the spec. I don't fully understand why the spec does it that particular way, but I did find at least one problem with the way litehtml works. When growing items, their min size is not considered. They only get clamped sometime later, when they are rendered, causing an overflow in this example.
Details
<!DOCTYPE html>
<head>
<style>
.flexbox {
display: flex;
flex-direction: row;
justify-content: space-around;
width: 500px;
height: 20px;
background-color: blue;
}
.item1 {
flex-grow: 10;
width: 10px;
height: 10px;
background-color: red;
}
.item2 {
flex-grow: 1;
width: 10px;
min-width: 100px;
height: 10px;
background-color: green;
}
</style>
</head>
<html>
<div class="flexbox">
<span class="item1">hello</span>
<span class="item2">world</span>
</div>
</html>