Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

flex-basis 实现与浏览器有差异 #159

Closed
temper357 opened this issue Apr 15, 2021 · 10 comments
Closed

flex-basis 实现与浏览器有差异 #159

temper357 opened this issue Apr 15, 2021 · 10 comments
Assignees
Labels
bug Something isn't working

Comments

@temper357
Copy link
Contributor

使用的 Kraken 版本 | What version of kraken are you using

0.7

重现步骤 | Steps To Reproduce

flex item 主轴的 size 由 width(或者 height 视 flex-direction 而定) 和 flex-basis 共同决定,以 flex-direction 为 row 为例:

  1. 当 flex-basis 为 auto 时,size 为 width。
  2. 当 flex-basis 不为 auto 时,需要和 flex item 的 minimum content size 即最小内容 size 作比较,如果小于 minimum content size 则 flex-basis 不应该生效,如果大于则使用 flex-basis。

目前 Kraken 是在 flex container 的 performLayout 中根据 flex-basis 来设置 flex item 的 constraints,但是根据 Flutter 的 layout 机制,在设置 constraints 时拿不到 children 的 size(children 尚未 layout),因此 flex-basis 需要延迟到 flex-item 自身的 layout 阶段做才行。

重现代码 | Code example:

it("with flex", async () => {
    let div;
    div = createElement(
      'div',
      {
        style: {
          'box-sizing': 'border-box',
          display: 'flex',
          'flex-direction': 'column',
          border: '1px solid purple',
        },
      },
      [
        createElement(
          'div',
          {
            style: {
              'box-sizing': 'border-box',
            },
          },
          [createText(`Header`)]
        ),
        createElement(
          'div',
          {
            style: {
              'box-sizing': 'border-box',
              flex: '1',
            },
          },
          [
            createText(`Flexible content`),
          ]
        ),
      ]
    );
    BODY.appendChild(div);

    await matchViewportSnapshot();
  });

预期结果 | Expected results:

image

实际结果 | Actual results:

image

@temper357 temper357 added the bug Something isn't working label Apr 15, 2021
@temper357 temper357 self-assigned this Apr 15, 2021
This was referenced Apr 15, 2021
@army8735
Copy link

当 flex-basis 不为 auto 时,需要和 flex item 的 minimum content size 即最小内容 size 作比较,如果小于 minimum content size 则 flex-basis 不应该生效,如果大于则使用 flex-basis。

这点不对,应该是:hypothetical = clamp(min_main_size, flex_base_size, max_main_size)

当basis>max content时,取max。

https://zhuanlan.zhihu.com/p/363240190

@temper357
Copy link
Contributor Author

当 flex-basis 不为 auto 时,需要和 flex item 的 minimum content size 即最小内容 size 作比较,如果小于 minimum content size 则 flex-basis 不应该生效,如果大于则使用 flex-basis。

这点不对,应该是:hypothetical = clamp(min_main_size, flex_base_size, max_main_size)

当basis>max content时,取max。

https://zhuanlan.zhihu.com/p/363240190

flex item main size 的计算规则有多条,你上面列举的规则对应的是 flexBasis 大于 max content 的 case 要如何处理,但是我 issue 中的 case 是 flex basis 小于 minimum main size 时要如何处理,比如 flex-basis 为 0 时 flex item 的宽度要如何计算,规范中定义的是 flex-basis 不能小于 minimum main size,也就是说当 minimum main size 不为 0 时,flex-basis 设为 0 其实是不生效的。参考 issue 中的示例,flex: 1 的 flex-item 对应的 flex-basis 实际为 0,但是浏览器计算出来的 height 并不是 0 而是该 flex item 的内容高度。
参考链接 https://stackoverflow.com/a/63131269

@army8735
Copy link

我知道,我是补充下第2点,因为看说明以为写的只是考虑最小而不考虑最大。如果都考虑了就没问题。

hypothetical = clamp(min_main_size, flex_base_size, max_main_size)

这个伪代码意思就是假设主尺寸取值是clamp函数,在min和max之间。

@army8735
Copy link

image
这个test也有问题,flex-item的mpb计算,以及递归子节点的计算。

<div style="display:flex;width:100px">
  <span style="flex:1 1 50px;background:#F00;padding-left:10px">a</span>
  <span style="flex:1 1 40px;background:#00F">a</span>
</div>
<div style="display:flex;width:100px">
  <span style="flex:1 1 auto;background:#F00"><strong style="padding-left:10px">a</strong></span>
  <span style="flex:1 1 auto;background:#00F"><strong style="">a</strong></span>
</div>
<div style="display:flex;width:100px">
  <span style="flex:1 1 auto;background:#F00"><strong style="padding-left:10%">a</strong></span>
  <span style="flex:1 1 auto;background:#00F"><strong>a</strong></span>
</div>
var div1 = document.createElement('div');
div1.style.display = 'flex';
div1.style.width = '100px';
var span = document.createElement('span');
span.style.paddingLeft = '10px';
span.style.backgroundColor = '#F00';
span.style.flexGrow = 1;
span.style.flexShrink = 1;
span.style.flexBasis = '50px';
var text = document.createTextNode('a');
span.appendChild(text);
div1.appendChild(span);
span = document.createElement('span');
span.style.backgroundColor = '#00F';
span.style.flexGrow = 1;
span.style.flexShrink = 1;
span.style.flexBasis = '40px';
text = document.createTextNode('a');
span.appendChild(text);
div1.appendChild(span);

var div2 = document.createElement('div');
div2.style.display = 'flex';
div2.style.width = '100px';
var strong = document.createElement('strong');
strong.style.paddingLeft = '10px';
text = document.createTextNode('a');
strong.appendChild(text);
span = document.createElement('span');
span.style.backgroundColor = '#F00';
span.style.flexGrow = 1;
span.style.flexShrink = 1;
span.style.flexBasis = 'auto';
span.appendChild(strong);
div2.appendChild(span);
strong = document.createElement('strong');
text = document.createTextNode('a');
strong.appendChild(text);
span = document.createElement('span');
span.style.backgroundColor = '#00F';
span.style.flexGrow = 1;
span.style.flexShrink = 1;
span.style.flexBasis = 'auto';
span.appendChild(strong);
div2.appendChild(span);


var div3 = document.createElement('div');
div3.style.display = 'flex';
div3.style.width = '100px';
strong = document.createElement('strong');
strong.style.paddingLeft = '10%';
text = document.createTextNode('a');
strong.appendChild(text);
span = document.createElement('span');
span.style.backgroundColor = '#F00';
span.style.flexGrow = 1;
span.style.flexShrink = 1;
span.style.flexBasis = 'auto';
span.appendChild(strong);
div3.appendChild(span);
strong = document.createElement('strong');
text = document.createTextNode('a');
strong.appendChild(text);
span = document.createElement('span');
span.style.backgroundColor = '#00F';
span.style.flexGrow = 1;
span.style.flexShrink = 1;
span.style.flexBasis = 'auto';
span.appendChild(strong);
div3.appendChild(span);

document.body.appendChild(div1);
document.body.appendChild(div2);
document.body.appendChild(div3);

@temper357
Copy link
Contributor Author

image
这个test也有问题,flex-item的mpb计算,以及递归子节点的计算。

<div style="display:flex;width:100px">
  <span style="flex:1 1 50px;background:#F00;padding-left:10px">a</span>
  <span style="flex:1 1 40px;background:#00F">a</span>
</div>
<div style="display:flex;width:100px">
  <span style="flex:1 1 auto;background:#F00"><strong style="padding-left:10px">a</strong></span>
  <span style="flex:1 1 auto;background:#00F"><strong style="">a</strong></span>
</div>
<div style="display:flex;width:100px">
  <span style="flex:1 1 auto;background:#F00"><strong style="padding-left:10%">a</strong></span>
  <span style="flex:1 1 auto;background:#00F"><strong>a</strong></span>
</div>
var div1 = document.createElement('div');
div1.style.display = 'flex';
div1.style.width = '100px';
var span = document.createElement('span');
span.style.paddingLeft = '10px';
span.style.backgroundColor = '#F00';
span.style.flexGrow = 1;
span.style.flexShrink = 1;
span.style.flexBasis = '50px';
var text = document.createTextNode('a');
span.appendChild(text);
div1.appendChild(span);
span = document.createElement('span');
span.style.backgroundColor = '#00F';
span.style.flexGrow = 1;
span.style.flexShrink = 1;
span.style.flexBasis = '40px';
text = document.createTextNode('a');
span.appendChild(text);
div1.appendChild(span);

var div2 = document.createElement('div');
div2.style.display = 'flex';
div2.style.width = '100px';
var strong = document.createElement('strong');
strong.style.paddingLeft = '10px';
text = document.createTextNode('a');
strong.appendChild(text);
span = document.createElement('span');
span.style.backgroundColor = '#F00';
span.style.flexGrow = 1;
span.style.flexShrink = 1;
span.style.flexBasis = 'auto';
span.appendChild(strong);
div2.appendChild(span);
strong = document.createElement('strong');
text = document.createTextNode('a');
strong.appendChild(text);
span = document.createElement('span');
span.style.backgroundColor = '#00F';
span.style.flexGrow = 1;
span.style.flexShrink = 1;
span.style.flexBasis = 'auto';
span.appendChild(strong);
div2.appendChild(span);


var div3 = document.createElement('div');
div3.style.display = 'flex';
div3.style.width = '100px';
strong = document.createElement('strong');
strong.style.paddingLeft = '10%';
text = document.createTextNode('a');
strong.appendChild(text);
span = document.createElement('span');
span.style.backgroundColor = '#F00';
span.style.flexGrow = 1;
span.style.flexShrink = 1;
span.style.flexBasis = 'auto';
span.appendChild(strong);
div3.appendChild(span);
strong = document.createElement('strong');
text = document.createTextNode('a');
strong.appendChild(text);
span = document.createElement('span');
span.style.backgroundColor = '#00F';
span.style.flexGrow = 1;
span.style.flexShrink = 1;
span.style.flexBasis = 'auto';
span.appendChild(strong);
div3.appendChild(span);

document.body.appendChild(div1);
document.body.appendChild(div2);
document.body.appendChild(div3);

与浏览器不一致是因为 Kraken 目前只支持 box-sizing: border-box;与浏览器的默认值 content-box 不一致,进而导致盒模型中的尺寸计算与浏览器不一致,你在示例代码中加上以下样式后浏览器的展示与 Kraken 就一样了。box-sizing 这个差异在 Kraken 文档中也有写。

<style>
    * {
    box-sizing: border-box;
    }
</style>

@army8735
Copy link

image
这个test也不对,container尺寸固定了。

<div style="display:flex;width:100px;height:30px;border:1px solid #0F0">
  <span style="width:50px;height:50px;background:#F00"></span>
  <span style="flex:1 1 0;background:#00F"></span>
</div>
var div = document.createElement('div');
div.style.display = 'flex';
div.style.width = '100px';
div.style.height = '30px';
div.style.border = '1px solid #0F0';
var span = document.createElement('span');
span.style.backgroundColor = '#F00';
span.style.width = '50px';
span.style.height = '50px';
div.appendChild(span);
span = document.createElement('span');
span.style.backgroundColor = '#00F';
span.style.flexGrow = 1;
span.style.flexShrink = 1;
span.style.flexBasis = '0';
div.appendChild(span);

document.body.appendChild(div);

@army8735
Copy link

  • {
    box-sizing: border-box;
    }

ok,paddingLeft:10%,还有点问题。
image

@army8735
Copy link

image
图片等具有宽高比的节点:

<div style="display:flex;width:100px;border:1px solid #0F0">
  <span style="flex:1 1 0;">哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈</span>
  <img style="height:50px" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkAQMAAABKLAcXAAAABlBMVEX1CAD////Q9ly2AAAAhUlEQVQ4y93TMQ6AIAwF0BIHRo/AUTyaHM2jeARGBoNSkvqNkBASh8YO/rzR9kOqZjllth8pmqc8OSgRWSgSGSjkEL3D53C3KM8sSiwrOlhTW5FlRIFFbe1Fa0v85RyWL3IqNPwPnb109onNd2+Ea+LSzRYg0J66WWhd1Ui0Vc/L+Vaa5gJ+8ifpfqdy4gAAAABJRU5ErkJggg=="/>
</div>
var div = document.createElement('div');
div.style.display = 'flex';
div.style.width = '100px';
div.style.border = '1px solid #0F0';
var span = document.createElement('span');
span.style.flexGrow = 1;
span.style.flexShrink = 1;
span.style.flexBasis = 0;
var text = document.createTextNode('哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈');
span.appendChild(text);
div.appendChild(span);
var img = document.createElement('img');
img.style.height = '50px';
img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkAQMAAABKLAcXAAAABlBMVEX1CAD////Q9ly2AAAAhUlEQVQ4y93TMQ6AIAwF0BIHRo/AUTyaHM2jeARGBoNSkvqNkBASh8YO/rzR9kOqZjllth8pmqc8OSgRWSgSGSjkEL3D53C3KM8sSiwrOlhTW5FlRIFFbe1Fa0v85RyWL3IqNPwPnb109onNd2+Ea+LSzRYg0J66WWhd1Ui0Vc/L+Vaa5gJ+8ifpfqdy4gAAAABJRU5ErkJggg==';
div.appendChild(img);

document.body.appendChild(div);

@temper357
Copy link
Contributor Author

上面几个用例确实有 bug,我这边着手解决下,感谢提出问题。

@temper357
Copy link
Contributor Author

前面两个 flex item 百分比与高度问题已经 fix,最后一个文本 width 问题已登记到 #401

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants