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

CSS Display Sliver 提案的讨论 #239

Open
wssgcg1213 opened this issue Nov 5, 2020 · 7 comments
Open

CSS Display Sliver 提案的讨论 #239

wssgcg1213 opened this issue Nov 5, 2020 · 7 comments

Comments

@wssgcg1213
Copy link

Hi All,

这个 Issue 抛出一个关于 CSS 的提案,我希望能够在 Web 中文兴趣组内先进行一些讨论,收集意见和建议,最终目标是能够贡献到 CSSWG。

需要注意的是这个文档目前还只是一个"提议",还不算是比较完整的提案。

提案的目的是解决 Web 标准下滚动视图的复用回收问题,客户端开发中有 RecyclerView/UITableView 来实现滚动回收的布局容器,提案的 Display Sliver 定义了容器的布局方式以及当子元素滚动出 viewport 后的回收特性。

属性

增加 CSS Display 属性值: sliver

sliver 属于 W3C Box Layout Modes 中定义的 Inner Display Layout Models 类型,详见 https://www.w3.org/TR/css-display-3/#inner-model

当 display 为 sliver 时,该元素的 overflow 表现为 auto,越界的内容会被裁减,容器可滚动并显示滚动条。

增加 CSS 属性 sliver-direction : row|column 默认 column

sliver-direction 指定了 Sliver 容器的主轴方向 (Main Axis),Sliver 容器的主轴方向即滚动方向;Sliver 容器的交叉轴 (Cross Axis) 方向与主轴方向交叉,Sliver 容器在交叉轴方向不可滚动。

  • row: 可滚动方向为水平方向
  • column: 可滚动方向为垂直方向

布局特性

在主轴方向 (Main Axis) 上可滚动, 其值由 sliver-direction 指定, 默认值为 column

主轴方向上的尺寸需要由 CSS 显式的 width/height 定义,否则默认值为 0。

交叉轴 (Cross Axis) 方向上的尺寸会填充满父容器尺度上的剩余空间, 与 flow layout 中的 block-level 的表现相同。

对容器的每一个子元素,其主轴方向上的尺寸需要由子元素在 CSS 中定义,否则默认值为 0;其交叉轴方向上的尺寸会填充满 SliverContainer 的剩余空间;

回收特性

当 Sliver 容器中的子元素滚动出该容器的 Viewport 时,可以将该子元素中用于渲染的 renderobject 回收以达到节省内存占用的目的。当子元素重新出现时,根据 DOM 描述重新生成 renderobject。

一些补充

  1. 具体实现中, 滚动时当子元素边界出 viewport 后, 可以等待一个 remainDistance 的距离再销毁; 当子元素处于 viewport 外,将要移入 viewport 时,可以在 remainDistance 的时候就开始创建 renderobject; 这些措施是出于性能和体验考虑
  2. 具体可销毁的对象, 是除了 Element 本身描述(attr,styleDeclaration)外的对象, 这里应该存在不同实现的差异性
  3. 我们这边已经基于 Flutter RenderObject 实现了类似的布局能力

我希望讨论的内容

  1. 必要性
  2. display 新属性的命名, sliver 的出处是参考了 Flutter
  3. 提案的描述
  4. 关于实现可行性
  5. 提案的流程
@flyingzl
Copy link

flyingzl commented Nov 5, 2020

貌似google已经有了草案 content-visibility

说明请参考: https://web.dev/content-visibility/

@wssgcg1213
Copy link
Author

貌似google已经有了草案 content-visibility

说明请参考: https://web.dev/content-visibility/

@flyingzl 我们有注意到这个 draft, 也已在我们这边实现了 content-visibility 的能力, https://drafts.csswg.org/css-contain/#using-cv-auto 此处提到了 content-visibility: auto 可以用来实现 virtual-list,仍提出提案的必要性出于以下的想法:

  1. 出发点是考虑减少内存和 CPU 计算, content-visibility 的描述侧重于节点是否参与 layout/style/paint (here), 我们对 c-v 的实现中也并没有 dispose renderobject;
  2. 新增布局的必要性在于简化 off-screen 的计算逻辑,c-v auto 需要依赖父层的布局容器计算其布局位置后再决定是否显示, 这可能会导致实际计算中至少要有一次布局计算参与, 也就没有办法做到延迟创建 renderobject 了。sliver 布局的设计需要指定子元素在主轴上的尺度, 也就是只依赖 style declaration 即可, 这样也就不需要在一开始就创建 renderobject.

@yuanyan
Copy link
Member

yuanyan commented Nov 5, 2020

适用场景上有比较明显区别,display: sliver 适用长列表的场景,content-visibility 因为是基于节点当前是否可见来决定渲染,在长列表场景下需要给每一行都加上 content-visibility: auto,因为长列表的行数都会非常多,快速滚动时会导致大量的计算,所以 content-visibility 更适用大面积的以屏级为粒度的场景,像 SPA 里 tabbar 切换页面时、初始化时首屏之外的内容等。

@jincdream
Copy link

jincdream commented Nov 10, 2020

  • 如果父元素设定了display:sliver,当子元素内容布局过于复杂的时候,就不能再使用display:grid进行布局了,而需要再嵌套一个子节点并将它设定为布局容器才行。那么对于容器的子元素优化的场景是不是就过于局限了?

@yuanyan
Copy link
Member

yuanyan commented Nov 10, 2020

  • 如果父元素设定了display:sliver,当子元素内容布局过于复杂的时候,就不能再使用display:grid进行布局了,而需要再嵌套一个子节点并将它设定为布局容器才行。那么对于容器的子元素优化的场景是不是就过于局限了?

Inner Display Layout Models (参考 https://www.w3.org/TR/css-display-3/#inner-model )这是无法避免的

@Gaubee
Copy link

Gaubee commented Aug 2, 2021

我粗略了看了flutter那边的文档,好像对于sliver是为了能够共享滚动行为?
但看提案描述,好像是想解决虚拟滚动的问题?
如果想不依赖js,只是想用纯html分析解决问题,也许应该用这样的代码来解决?
(这里用template与microdata来做组合,以确保seo也能正确识别出来)

<virtual-scroll for="some-data-id">
    <div itemscope itemtype="a">
      <span itemprop="title"></span>
    </div>
    <div itemscope itemtype="b">
      <span itemprop="age"></span>
    </div>
</virtual-scroll>
<script id="some-data-id" type="text/json">
[
{
  "type": "a",
  "prop": {
    "title": "Microdata"
  }
},
{
  "type": "b",
  "prop": {
    "age": 10
  }
}
]
</script>

@wssgcg1213
Copy link
Author

我粗略了看了flutter那边的文档,好像对于sliver是为了能够共享滚动行为? 但看提案描述,好像是想解决虚拟滚动的问题? 如果想不依赖js,只是想用纯html分析解决问题,也许应该用这样的代码来解决? (这里用template与microdata来做组合,以确保seo也能正确识别出来)

<virtual-scroll for="some-data-id">
    <div itemscope itemtype="a">
      <span itemprop="title"></span>
    </div>
    <div itemscope itemtype="b">
      <span itemprop="age"></span>
    </div>
</virtual-scroll>
<script id="some-data-id" type="text/json">
[
{
  "type": "a",
  "prop": {
    "title": "Microdata"
  }
},
{
  "type": "b",
  "prop": {
    "age": 10
  }
}
]
</script>

共享滚动行为指的应该是 ScrollContext 吧,sliver 是一种类似 ListView 的回收模型。virtual-scroll 的实现上势必会有频繁 DOM op 的问题,所以建议直接基于渲染引擎的实现会好一些

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants