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

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

Jxck
January 10, 2018

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

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

Jxck

January 10, 2018
Tweet

More Decks by Jxck

Other Decks in Technology

Transcript

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

    podcast: http://mozaic.fm • Love: music Jack
  2. 7

  3. 12

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

    でなんか色々できるようにするやつ • Layout API ◦ 要素を好き勝手に並べたりするやつ • Layout Worklet ◦ それを別スレッドで良い感じに処理してくれるやつ 13 詳しくは仕 様で!!
  5. 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 で呼び出す
  6. 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 で渡す スタイル。
  7. 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 コンテンツ元来のサイズ (折り返さないサイズ) を返す
  8. Logical Size 19 inlineSize (width) blockSize (height) inlineStart (left) inlineEnd

    (right) blockEnd (bottom) blockStart (top) window LtR, TtB だけじゃないから
  9. *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
  10. // 作った領域で子要素をレイアウトした際の 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 普通にレ イアウトし た時の幅 を得る
  11. // 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
  12. // 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
  13. // 算出した領域で Fragment のレイアウトを依頼 return { inlineSize: inlineSize, blockSize: blockSize,

    childFragments: childFragments, } } layout(5) 24 良い感じに並んだ!! (画像はイメージです )