Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

● id: Jxck ● github: Jxck ● blog: https://blog.jxck.io ● podcast: http://mozaic.fm ● Love: music Jack

Slide 4

Slide 4 text

4 めでたい FlexBox の Java 実装らしい

Slide 5

Slide 5 text

それ CSS でできるよ 5

Slide 6

Slide 6 text

FlexBox で 実装する 6

Slide 7

Slide 7 text

7

Slide 8

Slide 8 text

8 あたりまえ

Slide 9

Slide 9 text

本題 9

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

FlexBox でを 実装する 11

Slide 12

Slide 12 text

12

Slide 13

Slide 13 text

What is... ● FlexBox ○ 要素を良い感じに敷き詰めるやつ ● Houdini ○ CSS でなんか色々できるようにするやつ ● Layout API ○ 要素を好き勝手に並べたりするやつ ● Layout Worklet ○ それを別スレッドで良い感じに処理してくれるやつ 13 詳しくは仕 様で!!

Slide 14

Slide 14 text

justify-content: space-between 14 http://labs.jxck.io/flexbox/justify-content.html ここの隙間が良い感じで嬉しい

Slide 15

Slide 15 text

実装 15

Slide 16

Slide 16 text

addModule .container { display: layout(space-between); }
Child 1
Child 2
Child 3
Child 4
CSS.layoutWorklet.addModule('flex-box.js'); 16 Layout Worklet を登録し そこで公開される API を CSS で呼び出す

Slide 17

Slide 17 text

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 で渡す スタイル。

Slide 18

Slide 18 text

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 コンテンツ元来のサイズ (折り返さないサイズ) を返す

Slide 19

Slide 19 text

Logical Size 19 inlineSize (width) blockSize (height) inlineStart (left) inlineEnd (right) blockEnd (bottom) blockStart (top) window LtR, TtB だけじゃないから

Slide 20

Slide 20 text

*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

Slide 21

Slide 21 text

// 作った領域で子要素をレイアウトした際の 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 普通にレ イアウトし た時の幅 を得る

Slide 22

Slide 22 text

// 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

Slide 23

Slide 23 text

// 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

Slide 24

Slide 24 text

// 算出した領域で Fragment のレイアウトを依頼 return { inlineSize: inlineSize, blockSize: blockSize, childFragments: childFragments, } } layout(5) 24 良い感じに並んだ!! (画像はイメージです )

Slide 25

Slide 25 text

進捗 25 https://bugs.chromium.org/p/chromium/issues/detail?id=726125&desc=2 https://ishoudinireadyyet.com/

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

Jack thanks