Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Houdini Layout API で FelxBox を実装する / FlexBox by houdini layout api

1ff811939fd0923df8321ec6d8bf9d4b?s=47 Jxck
January 10, 2018

Houdini Layout API で FelxBox を実装する / FlexBox by houdini layout api

このスライドはフィクションです。
https://connpass.com/event/65989/

1ff811939fd0923df8321ec6d8bf9d4b?s=128

Jxck

January 10, 2018
Tweet

Transcript

  1. このスライドはフィクションです 登場する実装や仕様は作業中であり 今はまだ実現していません 1

  2. FlexBox を 実装する thagikura GitHub star 10k party @2018/1/10 Jxck

  3. • id: Jxck • github: Jxck • blog: https://blog.jxck.io •

    podcast: http://mozaic.fm • Love: music Jack
  4. 4 めでたい FlexBox の Java 実装らしい

  5. それ CSS でできるよ 5

  6. FlexBox で 実装する 6

  7. 7

  8. 8 あたりまえ

  9. 本題 9

  10. それ Houdini でもできるよ ていだよ 10

  11. FlexBox でを 実装する 11

  12. 12

  13. What is... • FlexBox ◦ 要素を良い感じに敷き詰めるやつ • Houdini ◦ CSS

    でなんか色々できるようにするやつ • Layout API ◦ 要素を好き勝手に並べたりするやつ • Layout Worklet ◦ それを別スレッドで良い感じに処理してくれるやつ 13 詳しくは仕 様で!!
  14. justify-content: space-between 14 http://labs.jxck.io/flexbox/justify-content.html ここの隙間が良い感じで嬉しい

  15. 実装 15

  16. addModule <style> .container { display: layout(space-between); } </style> <div class="container">

    <div class=child>Child 1</div> <div class=child>Child 2</div> <div class=child>Child 3</div> <div class=child>Child 4</div> </div> <script> CSS.layoutWorklet.addModule('flex-box.js'); </script> 16 Layout Worklet を登録し そこで公開される API を CSS で呼び出す
  17. LayoutWorklet // ‘space-between’ を登録 引数の無名クラスがコールバック registerLayout('space-between', class { static get

    inputProperties() {} static get childrenInputProperties() {} static get childDisplay() {} // callback が generator *intrinsicSizes(styleMap, children) { } *layout(space, children, styleMap, edges, breakToken) { // ここにレイアウトのロジックを書く } }) 17 LayoutWorklet に対して 合意されたハンドラ実装を template pattern で渡す スタイル。
  18. intrinsicSize // (折り返さない)元来のコンテンツサイズを返す *intrinsicSizes(styleMap, children) { const childrenSizes = yield

    children.map((child) => { return child.intrinsicSizes() }) const maxContentSize = childrenSizes.reduce((sum, childSizes) => { return sum + childSizes.maxContentContribution }, 0) const minContentSize = childrenSizes.reduce((max, childSizes) => { return sum + childSizes.minContentContribution }, 0) // 子要素をレイアウトした時に取り得る最大 /最小の大きさ return {maxContentSize, minContentSize} } 18 コンテンツ元来のサイズ (折り返さないサイズ) を返す
  19. Logical Size 19 inlineSize (width) blockSize (height) inlineStart (left) inlineEnd

    (right) blockEnd (bottom) blockStart (top) window LtR, TtB だけじゃないから
  20. *layout(space, children, styleMap, edges, breakToken) { // 親が 100px で

    space が 40% だったら 40px 、を計算する API つまり、領域の縦横がわかる const inlineSize = resolveInlineSize(space, styleMap) const blockSize = resolveBlockSize(space, styleMap) // border, padding, scrollbar を除く、コンテンツに使えるサイズが出る const availableInlineSize = inlineSize - edges.all.inline const availableBlockSize = blockSize - edges.all.block // そのサイズで ConstraintSpace を作る const childConstraintSpace = new ConstraintSpace({ inlineSize: availableInlineSize, blockSize: availableBlockSize, }) layout(1) 20 ここの 大きさを 出す border + padding + scrollbar inlineSize availableInlineSize
  21. // 作った領域で子要素をレイアウトした際の Fragment を得る const unconstrainedChildFragments = yield children.map((child) =>

    { return child.layoutNextFragment(childConstraintSpace) }) // 各 Fragment の幅とその合計を得る const unconstrainedSizes = [] const totalSize = unconstrainedChildFragments.reduce((sum, fragment, i) => { unconstrainedSizes[i] = fragment.inlineSize return sum + fragment.inlineSize }, 0) layout(2) 21 inlineSize 普通にレ イアウトし た時の幅 を得る
  22. // Fragment を横に並べた時の残りを出す const remainingSpace = Math.max(0, inlineSize - totalSize)

    // これを Fragment で割ると、間の余白が出る const extraSpace = remainingSpace / children.length // 余白を割り振ってレイアウトし直し Fragment を再度出す const childFragments = yield children.map((child, i) => { return child.layoutNextFragment(new ConstraintSpace({ inlineSize: unconstrainedSizes[i] + extraSpace, inlineSizeFixed: true, blockSize: availableBlockSize // ここは同じ高さで揃える })) }) layout(3) 22 remainingSpace 空きを出す 余白を挟んで レイアウトし直す extraSpace
  23. // Fragment を並べる let inlineOffset = 0 // 一番端から let

    maxChildBlockSize = 0 // 一番大きいブロックサイズが残る for (let fragment of childFragments) { fragment.inlineOffset = inlineOffset // offset を指定 fragment.blockOffset = edges.all.blockStart // 上端は同じ inlineOffset += fragment.inlineSize // 使用した分 offset をずらす maxChildBlockSize = Math.max(maxChildBlockSize, fragment.blockSize) } // Style を踏まえた上で必要なブロックサイズを出す const blockSize = resolveBlockSize(space, styleMap, maxChildBlockSize) layout(4) 23 maxBlockSize
  24. // 算出した領域で Fragment のレイアウトを依頼 return { inlineSize: inlineSize, blockSize: blockSize,

    childFragments: childFragments, } } layout(5) 24 良い感じに並んだ!! (画像はイメージです )
  25. 進捗 25 https://bugs.chromium.org/p/chromium/issues/detail?id=726125&desc=2 https://ishoudinireadyyet.com/

  26. DEMO http://labs.jxck.io/houdini/layout/flex-box/ (このデモは現状いかなるフラグを有効にしても動きません) 26

  27. 27 See also https://drafts.css-houdini.org/css-layout-api/ https://mozaic.fm/episodes/29/houdini.html

  28. このスライドはフィクションです 登場する実装や仕様は作業中であり 今はまだ実現していません 28

  29. Jack thanks