summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/css/css-position
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/css/css-position
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/css/css-position')
-rw-r--r--testing/web-platform/tests/css/css-position/META.yml3
-rw-r--r--testing/web-platform/tests/css/css-position/animations/bottom-composition.html78
-rw-r--r--testing/web-platform/tests/css/css-position/animations/bottom-interpolation.html78
-rw-r--r--testing/web-platform/tests/css/css-position/animations/left-composition.html91
-rw-r--r--testing/web-platform/tests/css/css-position/animations/left-interpolation.html76
-rw-r--r--testing/web-platform/tests/css/css-position/animations/position-interpolation.html61
-rw-r--r--testing/web-platform/tests/css/css-position/animations/right-composition.html78
-rw-r--r--testing/web-platform/tests/css/css-position/animations/right-interpolation.html77
-rw-r--r--testing/web-platform/tests/css/css-position/animations/top-composition.html78
-rw-r--r--testing/web-platform/tests/css/css-position/animations/top-interpolation.html79
-rw-r--r--testing/web-platform/tests/css/css-position/backdrop-inherit-computed.html42
-rw-r--r--testing/web-platform/tests/css/css-position/backdrop-inherit-rendered-ref.html15
-rw-r--r--testing/web-platform/tests/css/css-position/backdrop-inherit-rendered.html18
-rw-r--r--testing/web-platform/tests/css/css-position/backdrop-tree-abiding-slotted.html27
-rw-r--r--testing/web-platform/tests/css/css-position/change-insets-inside-strict-containment-nested.html19
-rw-r--r--testing/web-platform/tests/css/css-position/containing-block-change-button-ref.html21
-rw-r--r--testing/web-platform/tests/css/css-position/containing-block-change-button.html35
-rw-r--r--testing/web-platform/tests/css/css-position/containing-block-change-scrollframe-ref.html32
-rw-r--r--testing/web-platform/tests/css/css-position/containing-block-change-scrollframe.html46
-rw-r--r--testing/web-platform/tests/css/css-position/crashtests/inline-containing-block-crash.html9
-rw-r--r--testing/web-platform/tests/css/css-position/crashtests/position-absolute-crash-014.html24
-rw-r--r--testing/web-platform/tests/css/css-position/crashtests/scroll-tree-parent-construction.html52
-rw-r--r--testing/web-platform/tests/css/css-position/fixed-z-index-blend-ref.html10
-rw-r--r--testing/web-platform/tests/css/css-position/fixed-z-index-blend.html62
-rw-r--r--testing/web-platform/tests/css/css-position/hypothetical-box-scroll-parent-ref.html12
-rw-r--r--testing/web-platform/tests/css/css-position/hypothetical-box-scroll-parent.html17
-rw-r--r--testing/web-platform/tests/css/css-position/hypothetical-box-scroll-viewport-ref.html7
-rw-r--r--testing/web-platform/tests/css/css-position/hypothetical-box-scroll-viewport.html15
-rw-r--r--testing/web-platform/tests/css/css-position/hypothetical-dynamic-change-001-ref.html15
-rw-r--r--testing/web-platform/tests/css/css-position/hypothetical-dynamic-change-001.html30
-rw-r--r--testing/web-platform/tests/css/css-position/hypothetical-dynamic-change-002.html33
-rw-r--r--testing/web-platform/tests/css/css-position/hypothetical-dynamic-change-003.html34
-rw-r--r--testing/web-platform/tests/css/css-position/inheritance.html31
-rw-r--r--testing/web-platform/tests/css/css-position/invalidate-opacity-negative-z-index-ref.html8
-rw-r--r--testing/web-platform/tests/css/css-position/invalidate-opacity-negative-z-index.html19
-rw-r--r--testing/web-platform/tests/css/css-position/multicol/static-position/vlr-in-multicol-ref.html21
-rw-r--r--testing/web-platform/tests/css/css-position/multicol/static-position/vlr-ltr-ltr-in-multicol.html60
-rw-r--r--testing/web-platform/tests/css/css-position/multicol/static-position/vlr-ltr-rtl-in-multicol.tentative.html60
-rw-r--r--testing/web-platform/tests/css/css-position/multicol/static-position/vlr-rtl-ltr-in-multicol.tentative.html60
-rw-r--r--testing/web-platform/tests/css/css-position/multicol/static-position/vlr-rtl-rtl-in-multicol.html60
-rw-r--r--testing/web-platform/tests/css/css-position/multicol/static-position/vrl-in-multicol-ref.html21
-rw-r--r--testing/web-platform/tests/css/css-position/multicol/static-position/vrl-ltr-ltr-in-multicol.html60
-rw-r--r--testing/web-platform/tests/css/css-position/multicol/static-position/vrl-ltr-rtl-in-multicol.tentative.html60
-rw-r--r--testing/web-platform/tests/css/css-position/multicol/static-position/vrl-rtl-ltr-in-multicol.tentative.html60
-rw-r--r--testing/web-platform/tests/css/css-position/multicol/static-position/vrl-rtl-rtl-in-multicol.html60
-rw-r--r--testing/web-platform/tests/css/css-position/multicol/vlr-in-multicols-ref.html41
-rw-r--r--testing/web-platform/tests/css/css-position/multicol/vlr-ltr-ltr-in-multicols.html97
-rw-r--r--testing/web-platform/tests/css/css-position/multicol/vlr-ltr-rtl-in-multicols.tentative.html97
-rw-r--r--testing/web-platform/tests/css/css-position/multicol/vlr-rtl-ltr-in-multicols.tentative.html97
-rw-r--r--testing/web-platform/tests/css/css-position/multicol/vlr-rtl-rtl-in-multicols.html97
-rw-r--r--testing/web-platform/tests/css/css-position/multicol/vrl-in-multicols-ref.html41
-rw-r--r--testing/web-platform/tests/css/css-position/multicol/vrl-ltr-ltr-in-multicols.html97
-rw-r--r--testing/web-platform/tests/css/css-position/multicol/vrl-ltr-rtl-in-multicols.tentative.html97
-rw-r--r--testing/web-platform/tests/css/css-position/multicol/vrl-rtl-ltr-in-multicols.tentative.html97
-rw-r--r--testing/web-platform/tests/css/css-position/multicol/vrl-rtl-rtl-in-multicols.html97
-rw-r--r--testing/web-platform/tests/css/css-position/nested-positions-crash.html12
-rw-r--r--testing/web-platform/tests/css/css-position/overlay/animation/overlay-interpolation.html80
-rw-r--r--testing/web-platform/tests/css/css-position/overlay/green-ref.html3
-rw-r--r--testing/web-platform/tests/css/css-position/overlay/overlay-computed.html19
-rw-r--r--testing/web-platform/tests/css/css-position/overlay/overlay-invalid.html15
-rw-r--r--testing/web-platform/tests/css/css-position/overlay/overlay-popover-backdrop-crash.html25
-rw-r--r--testing/web-platform/tests/css/css-position/overlay/overlay-transition-backdrop-entry.html26
-rw-r--r--testing/web-platform/tests/css/css-position/overlay/overlay-transition-backdrop.html22
-rw-r--r--testing/web-platform/tests/css/css-position/overlay/overlay-transition-dialog-ref.html6
-rw-r--r--testing/web-platform/tests/css/css-position/overlay/overlay-transition-dialog.html27
-rw-r--r--testing/web-platform/tests/css/css-position/overlay/overlay-transition-finished.html40
-rw-r--r--testing/web-platform/tests/css/css-position/overlay/overlay-transition-in-rendering.html29
-rw-r--r--testing/web-platform/tests/css/css-position/overlay/overlay-transition-out-rendering.html34
-rw-r--r--testing/web-platform/tests/css/css-position/overlay/overlay-transition-property.html15
-rw-r--r--testing/web-platform/tests/css/css-position/overlay/overlay-transition.html45
-rw-r--r--testing/web-platform/tests/css/css-position/overlay/overlay-user-agent-rules.html42
-rw-r--r--testing/web-platform/tests/css/css-position/overlay/overlay-valid.html15
-rw-r--r--testing/web-platform/tests/css/css-position/parsing/bottom-computed.html28
-rw-r--r--testing/web-platform/tests/css/css-position/parsing/bottom-invalid.html20
-rw-r--r--testing/web-platform/tests/css/css-position/parsing/bottom-valid.html21
-rw-r--r--testing/web-platform/tests/css/css-position/parsing/inset-computed.html42
-rw-r--r--testing/web-platform/tests/css/css-position/parsing/inset-invalid.html42
-rw-r--r--testing/web-platform/tests/css/css-position/parsing/inset-valid.html62
-rw-r--r--testing/web-platform/tests/css/css-position/parsing/left-computed.html28
-rw-r--r--testing/web-platform/tests/css/css-position/parsing/left-invalid.html20
-rw-r--r--testing/web-platform/tests/css/css-position/parsing/left-valid.html21
-rw-r--r--testing/web-platform/tests/css/css-position/parsing/position-computed.html22
-rw-r--r--testing/web-platform/tests/css/css-position/parsing/position-invalid.html18
-rw-r--r--testing/web-platform/tests/css/css-position/parsing/position-valid.html21
-rw-r--r--testing/web-platform/tests/css/css-position/parsing/right-computed.html28
-rw-r--r--testing/web-platform/tests/css/css-position/parsing/right-invalid.html20
-rw-r--r--testing/web-platform/tests/css/css-position/parsing/right-valid.html21
-rw-r--r--testing/web-platform/tests/css/css-position/parsing/top-computed.html28
-rw-r--r--testing/web-platform/tests/css/css-position/parsing/top-invalid.html20
-rw-r--r--testing/web-platform/tests/css/css-position/parsing/top-valid.html21
-rw-r--r--testing/web-platform/tests/css/css-position/parsing/z-index-computed.html20
-rw-r--r--testing/web-platform/tests/css/css-position/parsing/z-index-invalid.html20
-rw-r--r--testing/web-platform/tests/css/css-position/parsing/z-index-positioned-computed.html25
-rw-r--r--testing/web-platform/tests/css/css-position/parsing/z-index-valid.html21
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-abspos-table-dynamic.html36
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-center-001.html39
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-center-002.html39
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-center-003.html18
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-center-004.html18
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-center-006.html10
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-center-007.html10
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-chrome-bug-001.html58
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-chrome-bug-002.html39
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-container-dynamic-002.html47
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-container-dynamic.html35
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-001.html28
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-002.html30
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-003.html29
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-004.html41
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-005.html56
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-006.html33
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-007.html68
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-008.html17
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-009.html37
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-010.html14
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-011.html67
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-012.html25
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-013.html19
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-dynamic-auto-overflow.html14
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-dynamic-containing-block.html140
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-dynamic-list-marker.html37
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-dynamic-overflow-001.html36
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-dynamic-overflow-002.html46
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-dynamic-relayout-001.html22
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-dynamic-relayout-002.html14
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-dynamic-relayout-003.html14
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-dynamic-relayout-004.html20
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-flex.html12
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-floats-001.html49
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-floats-002.html55
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-floats-003.html56
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-floats-004.html50
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-inline.html13
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-margin-001.html57
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-margin-002.html59
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-table-cell.html32
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position.html39
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-fieldset.html8
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-fit-content.html11
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-iframe-print-001.sub.html21
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-iframe-print-002.sub.html21
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-iframe-print-ref.html6
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-in-inline-001.html25
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-in-inline-002.html51
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-in-inline-003.html30
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-in-inline-004.html33
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-in-inline-crash.html24
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-large-negative-inset-ref.html9
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-large-negative-inset.html26
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-margin-auto-001.html34
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-multicol-001.html15
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-padding-percentage.html59
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-percentage-height.html59
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-replaced-intrinsic-size.tentative.html7
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-replaced-minmax.html355
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-replaced-no-intrinsic-size.tentative.html7
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-replaced-with-display-table.html7
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-root-element-flex.html30
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-root-element-grid.html30
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-root-element-ref.html26
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-button-ref.html23
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-button.html28
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-input-ref.html34
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-input.html42
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-other-ref.html32
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-other.html40
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-table-001.html112
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-under-non-containing-stacking-context-ref.html9
-rw-r--r--testing/web-platform/tests/css/css-position/position-absolute-under-non-containing-stacking-context.html17
-rw-r--r--testing/web-platform/tests/css/css-position/position-change-ref.html9
-rw-r--r--testing/web-platform/tests/css/css-position/position-change.html25
-rw-r--r--testing/web-platform/tests/css/css-position/position-fixed-at-bottom-right-on-viewport.html31
-rw-r--r--testing/web-platform/tests/css/css-position/position-fixed-dynamic-transformed-sibling-ref.html17
-rw-r--r--testing/web-platform/tests/css/css-position/position-fixed-dynamic-transformed-sibling.html40
-rw-r--r--testing/web-platform/tests/css/css-position/position-fixed-overflow-print-ref.html21
-rw-r--r--testing/web-platform/tests/css/css-position/position-fixed-overflow-print.html26
-rw-r--r--testing/web-platform/tests/css/css-position/position-fixed-root-element-flex.html30
-rw-r--r--testing/web-platform/tests/css/css-position/position-fixed-root-element-grid.html30
-rw-r--r--testing/web-platform/tests/css/css-position/position-fixed-root-element-ref.html26
-rw-r--r--testing/web-platform/tests/css/css-position/position-fixed-scroll-nested-fixed-ref.html3
-rw-r--r--testing/web-platform/tests/css/css-position/position-fixed-scroll-nested-fixed.html14
-rw-r--r--testing/web-platform/tests/css/css-position/position-fixed-scroll-overlap-ref.html2
-rw-r--r--testing/web-platform/tests/css/css-position/position-fixed-scroll-overlap.html35
-rw-r--r--testing/web-platform/tests/css/css-position/position-fixed-video-controls-print.html7
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-001.html10
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-002.html10
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-003.html12
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-004.html16
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-005.html16
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-006.html8
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-007.html8
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-008.html14
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-009.html14
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-010.html14
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-011.html14
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-012.html14
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-013.html14
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-014.html21
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-table-caption.html43
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-table-left-ref.html41
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-table-tbody-left-absolute-child.html61
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-table-tbody-left.html55
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-table-tbody-top-absolute-child.html62
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-table-tbody-top.html56
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-table-td-left.html58
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-table-td-top.html59
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-table-tfoot-left-absolute-child.html61
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-table-tfoot-left.html55
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-table-tfoot-top-absolute-child.html65
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-table-tfoot-top-ref.html41
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-table-tfoot-top.html59
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-table-thead-left-absolute-child.html61
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-table-thead-left.html55
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-table-thead-top-absolute-child.html65
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-table-thead-top.html59
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-table-top-ref.html42
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-table-tr-left-absolute-child.html64
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-table-tr-left.html58
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-table-tr-top-absolute-child.html63
-rw-r--r--testing/web-platform/tests/css/css-position/position-relative-table-tr-top.html59
-rw-r--r--testing/web-platform/tests/css/css-position/positon-absolute-scrollable-overflow-001.html73
-rw-r--r--testing/web-platform/tests/css/css-position/resources/position-absolute-iframe-child-002.sub.html16
-rw-r--r--testing/web-platform/tests/css/css-position/resources/position-absolute-iframe-child.html6
-rw-r--r--testing/web-platform/tests/css/css-position/resources/position-sticky-fixed-ancestor-iframe-child.html61
-rw-r--r--testing/web-platform/tests/css/css-position/resources/ref-rectangle.js34
-rw-r--r--testing/web-platform/tests/css/css-position/resources/sticky-util.js109
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/htb-ltr-ltr.html74
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/htb-ltr-rtl.tentative.html74
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/htb-ref.html37
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/htb-rtl-ltr.tentative.html74
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/htb-rtl-rtl.html74
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-001.html17
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-002.html17
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-003.html17
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-004.html17
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-005.html17
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-006.html17
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-007.html17
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-008.html17
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-009.html17
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-010.html17
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-011.html17
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-012.html17
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-013.html11
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-014.html12
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/vlr-ltr-ltr.html80
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/vlr-ltr-rtl.tentative.html80
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/vlr-ref.html39
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/vlr-rtl-ltr.tentative.html80
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/vlr-rtl-rtl.html80
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/vrl-ltr-ltr.html80
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/vrl-ltr-rtl.tentative.html80
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/vrl-ref.html39
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/vrl-rtl-ltr.tentative.html80
-rw-r--r--testing/web-platform/tests/css/css-position/static-position/vrl-rtl-rtl.html80
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-bottom-002.html121
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-bottom-003.html121
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-bottom.html41
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-change-top-ref.html21
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-change-top.html53
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-child-multicolumn-ref.html50
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-child-multicolumn.html58
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-contained-by-display-table-ref.html48
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-contained-by-display-table.html71
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-details-crash.html10
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-001-ref.html2
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-001.html18
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-002-ref.html9
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-002.html17
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-003.html18
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-004-ref.html9
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-004.html17
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor-002.html53
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor-003.html44
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor-iframe-ref.html93
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor-iframe.html54
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor-ref.html64
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor.html89
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-flex-item-001.html41
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-flex-item-002.html41
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-flex-item-003.html50
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-flex-item-004.html51
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-flexbox-ref.html63
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-flexbox.html83
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-fractional-offset-ref.html40
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-fractional-offset.html80
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-get-bounding-client-rect.html99
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-grid-ref.html76
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-grid.html95
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-hyperlink-ref.html37
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-hyperlink.html41
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-in-fixed-container-ref.html40
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-in-fixed-container.html40
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-inflow-position.html58
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-inline-ref.html69
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-inline.html109
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-input-box-gets-focused-after-scroll.html30
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-large-top-2-ref.html56
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-large-top-2.tentative.html59
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-large-top-ref.html51
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-large-top.tentative.html54
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-left-002.html96
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-left-003.html96
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-left.html43
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-margins.html49
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-bottom.html68
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-inline-ref.html74
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-inline.html119
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-left.html75
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-right.html69
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-table-ref.html66
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-table.html133
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-thead-th.html133
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-top.html74
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-offset-overflow.html44
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-offset-print.html13
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-offset-top-left.html78
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-overflow-clip-container-ref.html38
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-overflow-clip-container.html41
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-overflow-hidden.html86
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-overflow-padding.html54
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-parsing.html59
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-rendering-ref.html104
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-rendering.html159
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-right-002.html96
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-right-003.html96
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-right.html41
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-root-scroller.html31
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-scroll-offset-clamp-crash.html20
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-scroll-reposition-ref.html10
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-scroll-reposition.html20
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-scroll-with-clip-and-abspos-ref.html33
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-scroll-with-clip-and-abspos.html33
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-scrollIntoView.html41
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-scrolled-remove-sibling.html99
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-stacking-context-002.html47
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-stacking-context-ref.html17
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-stacking-context.html46
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-parts-ref.html49
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-parts.html76
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-bottom-ref.html62
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-bottom.html109
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-left-ref.html62
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-left.html118
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-right-ref.html62
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-right.html118
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-top-ref.html62
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-top.html109
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tfoot-bottom-ref.html62
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tfoot-bottom.html124
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-bottom-ref.html62
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-bottom.html127
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-left-ref.html62
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-left.html118
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-right-ref.html62
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-right.html118
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-top-ref.html62
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-top.html127
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-thead-top-ref.html62
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-thead-top.html124
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tr-bottom-ref.html62
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tr-bottom.html121
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tr-top-ref.html62
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tr-top.html121
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-top-002.html121
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-top-003.html121
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-top-and-bottom-003.html102
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-top-and-bottom.html57
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-top.html43
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-transforms-translate.html45
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-transforms.html49
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-writing-modes-ref.html58
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/position-sticky-writing-modes.html73
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-bottom-002-ref.html78
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-fixed-ancestor-002-ref.html20
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-left-002-ref.html74
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-right-002-ref.html68
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-top-002-ref.html83
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-top-and-bottom-003-ref.html83
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/sticky-after-input.html49
-rw-r--r--testing/web-platform/tests/css/css-position/sticky/support/100x100-red.pngbin0 -> 510 bytes
-rw-r--r--testing/web-platform/tests/css/css-position/z-index-blend-will-change-overlapping-layers-ref.html6
-rw-r--r--testing/web-platform/tests/css/css-position/z-index-blend-will-change-overlapping-layers.html25
383 files changed, 18168 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/css-position/META.yml b/testing/web-platform/tests/css/css-position/META.yml
new file mode 100644
index 0000000000..c1ce1ff602
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/META.yml
@@ -0,0 +1,3 @@
+spec: https://drafts.csswg.org/css-position/
+suggested_reviewers:
+ - astearns
diff --git a/testing/web-platform/tests/css/css-position/animations/bottom-composition.html b/testing/web-platform/tests/css/css-position/animations/bottom-composition.html
new file mode 100644
index 0000000000..68a830dfbd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/animations/bottom-composition.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>bottom composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-position-3/#propdef-bottom">
+<meta name="assert" content="bottom support animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+ property: 'bottom',
+ underlying: '50px',
+ addFrom: '100px',
+ addTo: '200px',
+}, [
+ {at: -0.3, expect: '120px'},
+ {at: 0, expect: '150px'},
+ {at: 0.5, expect: '200px'},
+ {at: 1, expect: '250px'},
+ {at: 1.5, expect: '300px'},
+]);
+
+test_composition({
+ property: 'bottom',
+ underlying: '100px',
+ addFrom: '10px',
+ addTo: '2px',
+}, [
+ {at: -0.5, expect: '114px'},
+ {at: 0, expect: '110px'},
+ {at: 0.5, expect: '106px'},
+ {at: 1, expect: '102px'},
+ {at: 1.5, expect: '98px'},
+]);
+
+test_composition({
+ property: 'bottom',
+ underlying: '10%',
+ addFrom: '100px',
+ addTo: '20%',
+}, [
+ {at: -0.3, expect: 'calc(130px + 4%)'},
+ {at: 0, expect: 'calc(100px + 10%)'},
+ {at: 0.5, expect: 'calc(50px + 20%)'},
+ {at: 1, expect: '30%'},
+ {at: 1.5, expect: 'calc(-50px + 40%)'},
+]);
+
+test_composition({
+ property: 'bottom',
+ underlying: '50px',
+ addFrom: '100px',
+ replaceTo: '200px',
+}, [
+ {at: -0.3, expect: '135px'},
+ {at: 0, expect: '150px'},
+ {at: 0.5, expect: '175px'},
+ {at: 1, expect: '200px'},
+ {at: 1.5, expect: '225px'},
+]);
+
+test_composition({
+ property: 'bottom',
+ underlying: '100px',
+ addFrom: '100px',
+ addTo: 'auto',
+}, [
+ {at: -0.3, expect: '200px'},
+ {at: 0, expect: '200px'},
+ {at: 0.5, expect: 'auto'},
+ {at: 1, expect: 'auto'},
+ {at: 1.5, expect: 'auto'},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-position/animations/bottom-interpolation.html b/testing/web-platform/tests/css/css-position/animations/bottom-interpolation.html
new file mode 100644
index 0000000000..272e79fc05
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/animations/bottom-interpolation.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<link rel="help" href="https://drafts.csswg.org/css-position-3/#propdef-bottom">
+<meta name="test" content="bottom supports animation as a length or percentage">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ bottom: 30px;
+}
+.target {
+ position: relative;
+ width: 100px;
+ height: 100px;
+ background-color: black;
+ display: inline-block;
+ margin: 20px 5px 20px 0px;
+ bottom: 10px;
+}
+.expected {
+ background-color: green;
+}
+</style>
+
+<body></body>
+
+<script>
+test_interpolation({
+ property: 'bottom',
+ from: neutralKeyframe,
+ to: '20px',
+}, [
+ {at: -0.3, expect: '7px'},
+ {at: 0, expect: '10px'},
+ {at: 0.5, expect: '15px'},
+ {at: 1, expect: '20px'},
+ {at: 1.5, expect: '25px'},
+]);
+
+test_no_interpolation({
+ property: 'bottom',
+ from: 'initial',
+ to: '20px',
+});
+
+test_interpolation({
+ property: 'bottom',
+ from: 'inherit',
+ to: '20px',
+}, [
+ {at: -0.3, expect: '33px'},
+ {at: 0, expect: '30px'},
+ {at: 0.5, expect: '25px'},
+ {at: 1, expect: '20px'},
+ {at: 1.5, expect: '15px'},
+]);
+
+test_no_interpolation({
+ property: 'bottom',
+ from: 'unset',
+ to: '20px',
+});
+
+test_interpolation({
+ property: 'bottom',
+ from: '-10px',
+ to: '10px'
+}, [
+ {at: -0.3, expect: '-16px'},
+ {at: 0, expect: '-10px'},
+ {at: 0.5, expect: '0px'},
+ {at: 1, expect: '10px'},
+ {at: 1.5, expect: '20px'}
+]);
+</script>
diff --git a/testing/web-platform/tests/css/css-position/animations/left-composition.html b/testing/web-platform/tests/css/css-position/animations/left-composition.html
new file mode 100644
index 0000000000..14b3dfda76
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/animations/left-composition.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>left composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-position-3/#propdef-left">
+<meta name="assert" content="left support animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+ property: 'left',
+ underlying: '50px',
+ addFrom: '100px',
+ addTo: '200px',
+}, [
+ {at: -0.3, expect: '120px'},
+ {at: 0, expect: '150px'},
+ {at: 0.5, expect: '200px'},
+ {at: 1, expect: '250px'},
+ {at: 1.5, expect: '300px'},
+]);
+
+test_composition({
+ property: 'left',
+ underlying: '100px',
+ addFrom: '10px',
+ addTo: '2px',
+}, [
+ {at: -0.5, expect: '114px'},
+ {at: 0, expect: '110px'},
+ {at: 0.5, expect: '106px'},
+ {at: 1, expect: '102px'},
+ {at: 1.5, expect: '98px'},
+]);
+
+test_composition({
+ property: 'left',
+ underlying: '10%',
+ addFrom: '100px',
+ addTo: '20%',
+}, [
+ {at: -0.3, expect: 'calc(130px + 4%)'},
+ {at: 0, expect: 'calc(100px + 10%)'},
+ {at: 0.5, expect: 'calc(50px + 20%)'},
+ {at: 1, expect: '30%'},
+ {at: 1.5, expect: 'calc(-50px + 40%)'},
+]);
+
+test_composition({
+ property: 'left',
+ underlying: '10%',
+ addFrom: '100px',
+ addTo: '-10%',
+}, [
+ {at: -0.3, expect: 'calc(130px + 13%)'},
+ {at: 0, expect: 'calc(100px + 10%)'},
+ {at: 0.5, expect: 'calc(50px + 5%)'},
+ {at: 1, expect: '0%'},
+ {at: 1.5, expect: 'calc(-50px - 5%)'},
+]);
+
+test_composition({
+ property: 'left',
+ underlying: '50px',
+ addFrom: '100px',
+ replaceTo: '200px',
+}, [
+ {at: -0.3, expect: '135px'},
+ {at: 0, expect: '150px'},
+ {at: 0.5, expect: '175px'},
+ {at: 1, expect: '200px'},
+ {at: 1.5, expect: '225px'},
+]);
+
+test_composition({
+ property: 'left',
+ underlying: '100px',
+ addFrom: '100px',
+ addTo: 'auto',
+}, [
+ {at: -0.3, expect: '200px'},
+ {at: 0, expect: '200px'},
+ {at: 0.5, expect: 'auto'},
+ {at: 1, expect: 'auto'},
+ {at: 1.5, expect: 'auto'},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-position/animations/left-interpolation.html b/testing/web-platform/tests/css/css-position/animations/left-interpolation.html
new file mode 100644
index 0000000000..33ed0b4ec3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/animations/left-interpolation.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<link rel="help" href="https://drafts.csswg.org/css-position-3/#propdef-left">
+<meta name="test" content="left supports animation as a length or percentage">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ position: relative;
+ left: 30px;
+}
+.target {
+ position: relative;
+ width: 10px;
+ height: 10px;
+ background-color: black;
+ left: 10px;
+}
+.expected {
+ background-color: green;
+}
+</style>
+<body></body>
+
+<script>
+test_interpolation({
+ property: 'left',
+ from: neutralKeyframe,
+ to: '20px',
+}, [
+ {at: -0.3, expect: '7px'},
+ {at: 0, expect: '10px'},
+ {at: 0.5, expect: '15px'},
+ {at: 1, expect: '20px'},
+ {at: 1.5, expect: '25px'},
+]);
+
+test_no_interpolation({
+ property: 'left',
+ from: 'initial',
+ to: '20px',
+});
+
+test_interpolation({
+ property: 'left',
+ from: 'inherit',
+ to: '20px',
+}, [
+ {at: -0.3, expect: '33px'},
+ {at: 0, expect: '30px'},
+ {at: 0.5, expect: '25px'},
+ {at: 1, expect: '20px'},
+ {at: 1.5, expect: '15px'},
+]);
+
+test_no_interpolation({
+ property: 'left',
+ from: 'unset',
+ to: '20px',
+});
+
+test_interpolation({
+ property: 'left',
+ from: '-10px',
+ to: '10px'
+}, [
+ {at: -0.3, expect: '-16px'},
+ {at: 0, expect: '-10px'},
+ {at: 0.5, expect: '0px'},
+ {at: 1, expect: '10px'},
+ {at: 1.5, expect: '20px'}
+]);
+</script>
diff --git a/testing/web-platform/tests/css/css-position/animations/position-interpolation.html b/testing/web-platform/tests/css/css-position/animations/position-interpolation.html
new file mode 100644
index 0000000000..a4ad50240a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/animations/position-interpolation.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>position interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-position-3/#position-property">
+<meta name="assert" content="position has discrete animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ position: relative;
+ display: inline-block;
+ height: 10px;
+ margin: 0px;
+}
+.target {
+ width: 10px;
+ height: 10px;
+ background-color: black;
+ left: 10px;
+ position: 10px;
+}
+.expected {
+ background-color: green;
+}
+</style>
+
+<body>
+<template id="target-template">
+ <div class="parent">
+ <div class="target"></div>
+ </div>
+</template>
+</body>
+
+<script>
+test_no_interpolation({
+ property: 'position',
+ from: 'absolute',
+ to: 'static',
+});
+
+// This is still discrete interpolation; this test ensures that the neutral
+// keyframe is defined correctly for position.
+test_interpolation({
+ property: 'position',
+ from: neutralKeyframe,
+ to: 'absolute',
+ method: 'CSS Animations',
+}, [
+ {at: -1, expect: 'static'},
+ {at: 0, expect: 'static'},
+ {at: 0.25, expect: 'static'},
+ {at: 0.5, expect: 'absolute'},
+ {at: 0.75, expect: 'absolute'},
+ {at: 1, expect: 'absolute'},
+ {at: 2, expect: 'absolute'},
+]);
+</script>
diff --git a/testing/web-platform/tests/css/css-position/animations/right-composition.html b/testing/web-platform/tests/css/css-position/animations/right-composition.html
new file mode 100644
index 0000000000..995bb8d6be
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/animations/right-composition.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>right composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-position-3/#propdef-right">
+<meta name="assert" content="right support animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+ property: 'right',
+ underlying: '50px',
+ addFrom: '100px',
+ addTo: '200px',
+}, [
+ {at: -0.3, expect: '120px'},
+ {at: 0, expect: '150px'},
+ {at: 0.5, expect: '200px'},
+ {at: 1, expect: '250px'},
+ {at: 1.5, expect: '300px'},
+]);
+
+test_composition({
+ property: 'right',
+ underlying: '100px',
+ addFrom: '10px',
+ addTo: '2px',
+}, [
+ {at: -0.5, expect: '114px'},
+ {at: 0, expect: '110px'},
+ {at: 0.5, expect: '106px'},
+ {at: 1, expect: '102px'},
+ {at: 1.5, expect: '98px'},
+]);
+
+test_composition({
+ property: 'right',
+ underlying: '10%',
+ addFrom: '100px',
+ addTo: '20%',
+}, [
+ {at: -0.3, expect: 'calc(130px + 4%)'},
+ {at: 0, expect: 'calc(100px + 10%)'},
+ {at: 0.5, expect: 'calc(50px + 20%)'},
+ {at: 1, expect: '30%'},
+ {at: 1.5, expect: 'calc(-50px + 40%)'},
+]);
+
+test_composition({
+ property: 'right',
+ underlying: '50px',
+ addFrom: '100px',
+ replaceTo: '200px',
+}, [
+ {at: -0.3, expect: '135px'},
+ {at: 0, expect: '150px'},
+ {at: 0.5, expect: '175px'},
+ {at: 1, expect: '200px'},
+ {at: 1.5, expect: '225px'},
+]);
+
+test_composition({
+ property: 'right',
+ underlying: '100px',
+ addFrom: '100px',
+ addTo: 'auto',
+}, [
+ {at: -0.3, expect: '200px'},
+ {at: 0, expect: '200px'},
+ {at: 0.5, expect: 'auto'},
+ {at: 1, expect: 'auto'},
+ {at: 1.5, expect: 'auto'},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-position/animations/right-interpolation.html b/testing/web-platform/tests/css/css-position/animations/right-interpolation.html
new file mode 100644
index 0000000000..284d435e56
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/animations/right-interpolation.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<link rel="help" href="https://drafts.csswg.org/css-position-3/#propdef-right">
+<meta name="test" content="right supports animation as a length or percentage">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ margin-left: 40px;
+ right: 30px;
+}
+.target {
+ position: relative;
+ width: 10px;
+ height: 10px;
+ background-color: black;
+ right: 10px;
+}
+.expected {
+ background-color: green;
+}
+</style>
+
+<body></body>
+
+<script>
+test_interpolation({
+ property: 'right',
+ from: neutralKeyframe,
+ to: '20px',
+}, [
+ {at: -0.3, expect: '7px'},
+ {at: 0, expect: '10px'},
+ {at: 0.5, expect: '15px'},
+ {at: 1, expect: '20px'},
+ {at: 1.5, expect: '25px'},
+]);
+
+test_no_interpolation({
+ property: 'right',
+ from: 'initial',
+ to: '20px',
+});
+
+test_interpolation({
+ property: 'right',
+ from: 'inherit',
+ to: '20px',
+}, [
+ {at: -0.3, expect: '33px'},
+ {at: 0, expect: '30px'},
+ {at: 0.5, expect: '25px'},
+ {at: 1, expect: '20px'},
+ {at: 1.5, expect: '15px'},
+]);
+
+test_no_interpolation({
+ property: 'right',
+ from: 'unset',
+ to: '20px',
+});
+
+test_interpolation({
+ property: 'right',
+ from: '-10px',
+ to: '10px'
+}, [
+ {at: -0.3, expect: '-16px'},
+ {at: 0, expect: '-10px'},
+ {at: 0.5, expect: '0px'},
+ {at: 1, expect: '10px'},
+ {at: 1.5, expect: '20px'}
+]);
+</script>
diff --git a/testing/web-platform/tests/css/css-position/animations/top-composition.html b/testing/web-platform/tests/css/css-position/animations/top-composition.html
new file mode 100644
index 0000000000..47782e8536
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/animations/top-composition.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>top composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-position-3/#propdef-top">
+<meta name="assert" content="top support animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+ property: 'top',
+ underlying: '50px',
+ addFrom: '100px',
+ addTo: '200px',
+}, [
+ {at: -0.3, expect: '120px'},
+ {at: 0, expect: '150px'},
+ {at: 0.5, expect: '200px'},
+ {at: 1, expect: '250px'},
+ {at: 1.5, expect: '300px'},
+]);
+
+test_composition({
+ property: 'top',
+ underlying: '100px',
+ addFrom: '10px',
+ addTo: '2px',
+}, [
+ {at: -0.5, expect: '114px'},
+ {at: 0, expect: '110px'},
+ {at: 0.5, expect: '106px'},
+ {at: 1, expect: '102px'},
+ {at: 1.5, expect: '98px'},
+]);
+
+test_composition({
+ property: 'top',
+ underlying: '10%',
+ addFrom: '100px',
+ addTo: '20%',
+}, [
+ {at: -0.3, expect: 'calc(130px + 4%)'},
+ {at: 0, expect: 'calc(100px + 10%)'},
+ {at: 0.5, expect: 'calc(50px + 20%)'},
+ {at: 1, expect: '30%'},
+ {at: 1.5, expect: 'calc(-50px + 40%)'},
+]);
+
+test_composition({
+ property: 'top',
+ underlying: '50px',
+ addFrom: '100px',
+ replaceTo: '200px',
+}, [
+ {at: -0.3, expect: '135px'},
+ {at: 0, expect: '150px'},
+ {at: 0.5, expect: '175px'},
+ {at: 1, expect: '200px'},
+ {at: 1.5, expect: '225px'},
+]);
+
+test_composition({
+ property: 'top',
+ underlying: '100px',
+ addFrom: '100px',
+ addTo: 'auto',
+}, [
+ {at: -0.3, expect: '200px'},
+ {at: 0, expect: '200px'},
+ {at: 0.5, expect: 'auto'},
+ {at: 1, expect: 'auto'},
+ {at: 1.5, expect: 'auto'},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-position/animations/top-interpolation.html b/testing/web-platform/tests/css/css-position/animations/top-interpolation.html
new file mode 100644
index 0000000000..f5af530c38
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/animations/top-interpolation.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<link rel="help" href="https://drafts.csswg.org/css-position-3/#propdef-top">
+<meta name="assert" content="top supports animation as a length or percentage">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ top: 30px;
+ margin-bottom: 40px;
+}
+.target {
+ position: relative;
+ width: 10px;
+ height: 10px;
+ background-color: black;
+ display: inline-block;
+ top: 10px;
+}
+.expected {
+ background-color: green;
+ margin-right: 10px;
+}
+</style>
+
+<body></body>
+
+<script>
+test_interpolation({
+ property: 'top',
+ from: neutralKeyframe,
+ to: '20px',
+}, [
+ {at: -0.3, expect: '7px'},
+ {at: 0, expect: '10px'},
+ {at: 0.5, expect: '15px'},
+ {at: 1, expect: '20px'},
+ {at: 1.5, expect: '25px'},
+]);
+
+test_no_interpolation({
+ property: 'top',
+ from: 'initial',
+ to: '20px',
+});
+
+test_interpolation({
+ property: 'top',
+ from: 'inherit',
+ to: '20px',
+}, [
+ {at: -0.3, expect: '33px'},
+ {at: 0, expect: '30px'},
+ {at: 0.5, expect: '25px'},
+ {at: 1, expect: '20px'},
+ {at: 1.5, expect: '15px'},
+]);
+
+test_no_interpolation({
+ property: 'top',
+ from: 'unset',
+ to: '20px',
+});
+
+test_interpolation({
+ property: 'top',
+ from: '-10px',
+ to: '10px'
+}, [
+ {at: -0.3, expect: '-16px'},
+ {at: 0, expect: '-10px'},
+ {at: 0.5, expect: '0px'},
+ {at: 1, expect: '10px'},
+ {at: 1.5, expect: '20px'}
+]);
+</script>
diff --git a/testing/web-platform/tests/css/css-position/backdrop-inherit-computed.html b/testing/web-platform/tests/css/css-position/backdrop-inherit-computed.html
new file mode 100644
index 0000000000..77c6f36264
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/backdrop-inherit-computed.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<title>CSS Position Test: ::backdrop inherits from originating element - computed values</title>
+<link rel="help" href="https://drafts.csswg.org/css-position-4/#backdrop">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ dialog {
+ --foo: bar;
+ --bg: green;
+ left: 100px;
+ color-scheme: dark;
+ }
+ dialog::backdrop {
+ background-color: var(--bg);
+ left: inherit;
+ }
+</style>
+<dialog></dialog>
+<script>
+ let dialog = document.querySelector("dialog");
+ setup(() => {
+ dialog.showModal();
+ });
+
+ test(() => {
+ let style = getComputedStyle(dialog, "::backdrop");
+ assert_equals(style.getPropertyValue("--foo"), "bar");
+ assert_equals(style.getPropertyValue("--bg"), "green");
+ }, "Inherit custom property");
+
+ test(() => {
+ assert_equals(getComputedStyle(dialog, "::backdrop").backgroundColor, "rgb(0, 128, 0)");
+ }, "Apply inherited custom property to background-color");
+
+ test(() => {
+ assert_equals(getComputedStyle(dialog, "::backdrop").colorScheme, "dark");
+ }, "Implicitly inherited color-scheme");
+
+ test(() => {
+ assert_equals(getComputedStyle(dialog, "::backdrop").left, "100px");
+ }, "Explicitly inherited left");
+</script>
diff --git a/testing/web-platform/tests/css/css-position/backdrop-inherit-rendered-ref.html b/testing/web-platform/tests/css/css-position/backdrop-inherit-rendered-ref.html
new file mode 100644
index 0000000000..6343f8d141
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/backdrop-inherit-rendered-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<title>CSS Test Reference</title>
+<style>
+ dialog {
+ inset: 100px;
+ }
+ dialog::backdrop {
+ background-color: green;
+ inset: 100px;
+ }
+</style>
+<dialog>Green backdrop with 100px inset</dialog>
+<script>
+ document.querySelector("dialog").showModal();
+</script>
diff --git a/testing/web-platform/tests/css/css-position/backdrop-inherit-rendered.html b/testing/web-platform/tests/css/css-position/backdrop-inherit-rendered.html
new file mode 100644
index 0000000000..98dfe748ed
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/backdrop-inherit-rendered.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<title>CSS Position Test: ::backdrop inherits from originating element - rendering</title>
+<link rel="help" href="https://drafts.csswg.org/css-position-4/#backdrop">
+<link rel="match" href="backdrop-inherit-rendered-ref.html">
+<style>
+ dialog {
+ --bg: green;
+ inset: 100px;
+ }
+ dialog::backdrop {
+ background-color: var(--bg);
+ inset: inherit;
+ }
+</style>
+<dialog>Green backdrop with 100px inset</dialog>
+<script>
+ document.querySelector("dialog").showModal();
+</script>
diff --git a/testing/web-platform/tests/css/css-position/backdrop-tree-abiding-slotted.html b/testing/web-platform/tests/css/css-position/backdrop-tree-abiding-slotted.html
new file mode 100644
index 0000000000..057b484e26
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/backdrop-tree-abiding-slotted.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Position Test: ::backdrop is tree abiding, allowed after ::slotted</title>
+<link rel="help" href="https://drafts.csswg.org/css-position-4/#backdrop">
+<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#tree-abiding">
+<link rel="help" href="https://drafts.csswg.org/css-scoping/#slotted-pseudo">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div>
+ <template shadowrootmode="open">
+ <style>
+ ::slotted(dialog)::backdrop {
+ background-color: green;
+ }
+ </style>
+ <slot></slot>
+ </template>
+ <dialog id="target"></dialog>
+</div>
+<script>
+ const target = document.getElementById("target");
+ target.showModal();
+
+ test(() => {
+ assert_equals(getComputedStyle(target, "::backdrop").backgroundColor, "rgb(0, 128, 0)");
+ }, "::backdrop is tree-abiding and should be allowed after ::slotted()");
+</script>
diff --git a/testing/web-platform/tests/css/css-position/change-insets-inside-strict-containment-nested.html b/testing/web-platform/tests/css/css-position/change-insets-inside-strict-containment-nested.html
new file mode 100644
index 0000000000..b70ef0e667
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/change-insets-inside-strict-containment-nested.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1286841">
+<link rel="help" href="https://www.w3.org/TR/css-contain-1/">
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#insets">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="contain:strict; width:100px; height:100px; background:red;">
+ <div id="f1" style="position:fixed; left:100px; width:50px; height:100px; background:green;">
+ <div style="contain:strict; width:100px; height:100px;">
+ <div id="f2" style="position:fixed; left:100px; width:50px; height:100px; background:green;"></div>
+ </div>
+ </div>
+</div>
+<script>
+ document.body.offsetTop;
+ f1.style.left = "0";
+ f2.style.left = "50px";
+</script>
diff --git a/testing/web-platform/tests/css/css-position/containing-block-change-button-ref.html b/testing/web-platform/tests/css/css-position/containing-block-change-button-ref.html
new file mode 100644
index 0000000000..c5beee9359
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/containing-block-change-button-ref.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<style>
+ #button {
+ width: 400px;
+ height: 400px;
+ margin: 100px;
+ padding: 0;
+ border: 0;
+ background-color: purple;
+ vertical-align: top;
+ }
+ #button > div {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ }
+</style>
+<button id="button">
+ <div></div>
+</button>
diff --git a/testing/web-platform/tests/css/css-position/containing-block-change-button.html b/testing/web-platform/tests/css/css-position/containing-block-change-button.html
new file mode 100644
index 0000000000..a4d20685ce
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/containing-block-change-button.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Tests that after making a button a containing block, dynamically-inserted abspos boxes still get positioned correctly</title>
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1740439">
+<link rel="help" href="https://drafts.csswg.org/css-position/#abspos-insets">
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="match" href="containing-block-change-button-ref.html">
+<style>
+ #button {
+ width: 400px;
+ height: 400px;
+ margin: 100px;
+ background-color: purple;
+ border: 0;
+ padding: 10px;
+ }
+ #button > div {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ /* Vertically centered to match in-flow button layout of the reference */
+ top: 150px;
+ left: 0;
+ }
+</style>
+<button id="button"></button>
+<script>
+ let button = document.getElementById("button");
+ button.getBoundingClientRect();
+ button.style.position = "relative";
+ button.getBoundingClientRect();
+ button.appendChild(document.createElement("div"));
+</script>
diff --git a/testing/web-platform/tests/css/css-position/containing-block-change-scrollframe-ref.html b/testing/web-platform/tests/css/css-position/containing-block-change-scrollframe-ref.html
new file mode 100644
index 0000000000..63cfe1148a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/containing-block-change-scrollframe-ref.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Test Reference</title>
+<style>
+ #container {
+ width: 400px;
+ height: 400px;
+ margin: 100px;
+ background-color: purple;
+ position: relative;
+ }
+ #spacer {
+ height: 300px;
+ }
+ #bottom {
+ height: 100px;
+ background-color: green;
+ }
+ #abspos {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ top: 0;
+ left: 0;
+ }
+</style>
+<div id="container">
+ <div id="spacer"></div>
+ <div id="bottom"></div>
+ <div id="abspos"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/containing-block-change-scrollframe.html b/testing/web-platform/tests/css/css-position/containing-block-change-scrollframe.html
new file mode 100644
index 0000000000..803512cc1a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/containing-block-change-scrollframe.html
@@ -0,0 +1,46 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Tests that after making a scrolling box a containing block, dynamically-inserted abspos boxes still get positioned correctly</title>
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1735533">
+<link rel="help" href="https://drafts.csswg.org/css-position/#abspos-insets">
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="match" href="containing-block-change-scrollframe-ref.html">
+<style>
+ #container {
+ width: 400px;
+ height: 400px;
+ margin: 100px;
+ background-color: purple;
+ overflow: hidden;
+ }
+ #spacer {
+ height: 700px;
+ }
+ #bottom {
+ height: 100px;
+ background-color: green;
+ }
+ #abspos {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ top: 400px;
+ left: 0;
+ }
+</style>
+<div id="container">
+ <div id="spacer"></div>
+ <div id="bottom"></div>
+</div>
+<script>
+ let container = document.getElementById("container");
+ container.scrollTop = 400;
+ container.getBoundingClientRect();
+ container.style.position = "relative";
+ container.getBoundingClientRect();
+ let abspos = document.createElement("div");
+ abspos.id = "abspos";
+ container.appendChild(abspos);
+</script>
diff --git a/testing/web-platform/tests/css/css-position/crashtests/inline-containing-block-crash.html b/testing/web-platform/tests/css/css-position/crashtests/inline-containing-block-crash.html
new file mode 100644
index 0000000000..db385e38d1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/crashtests/inline-containing-block-crash.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1431205">
+<span style="position: relative;">
+ <div id="target" style="position: absolute; left: 0; top: 0; width: 10px; height: 10px; overflow: hidden;"></div>
+</span>
+<script>
+document.body.offsetTop;
+document.getElementById('target').textContent = 'kaboom';
+</script>
diff --git a/testing/web-platform/tests/css/css-position/crashtests/position-absolute-crash-014.html b/testing/web-platform/tests/css/css-position/crashtests/position-absolute-crash-014.html
new file mode 100644
index 0000000000..a169a7b949
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/crashtests/position-absolute-crash-014.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/1021676">
+<link rel="author" title="Koji Ishii" href="mailto:kojii@chromium.org">
+<style>
+#htmlvar00005 {
+ filter: drop-shadow(-1px -1px 1px yellow);
+ float: left;
+ line-height: 71vw;
+}
+
+#htmlvar00006 {
+ overflow-x: scroll;
+ position: absolute;
+}
+
+.class8 {
+ font: 52px sans-serif;
+}
+</style>
+<ol id="htmlvar00005">
+ <li id="htmlvar00006">
+ <details class="class8"></details>
+ </li>
+</ol>
diff --git a/testing/web-platform/tests/css/css-position/crashtests/scroll-tree-parent-construction.html b/testing/web-platform/tests/css/css-position/crashtests/scroll-tree-parent-construction.html
new file mode 100644
index 0000000000..8a5bf54253
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/crashtests/scroll-tree-parent-construction.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html class="test-wait">
+<head>
+<style>
+ #ifr { border: 5px solid #ddd; width: 200px; height: 150px; }
+</style>
+</head>
+<body>
+<iframe id=ifr srcdoc="
+ <style>
+ body { margin: 0 }
+ * { box-sizing: border-box }
+ .c1 { width: 90px; height: 300px; }
+ .f1 {
+ position: fixed;
+ background: #ddf;
+ left: 30px;
+ top: 10px;
+ width: 120px;
+ height: 120px;
+ }
+ .s1 {
+ overflow: scroll;
+ margin: 10px;
+ height: 100px;
+ width: 100px;
+ border: 5px solid gray;
+ }
+ </style>
+ <div class=c1>AAA</div>
+ <div class=f1>
+ <div class=s1>
+ <div class=c1>AAA</div>
+ </div>
+ </div>"></iframe>
+<script>
+ raf = async () => {
+ return new Promise(resolve => {
+ requestAnimationFrame(resolve);
+ });
+ }
+ onload = async () => {
+ await raf();
+ await raf();
+ ifr.contentWindow.location.reload();
+ for (let i = 0; i < 10; i++)
+ await raf();
+ document.documentElement.className = "";
+ };
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/fixed-z-index-blend-ref.html b/testing/web-platform/tests/css/css-position/fixed-z-index-blend-ref.html
new file mode 100644
index 0000000000..43fd01faa7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/fixed-z-index-blend-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<title>fixed position, z-index, and mix-blend-mode</title>
+<link rel="author" href="mailto:masonf@chromium.org">
+
+<div style="width: 100px; height:4000px;"></div>
+<div style="background: green; width: 100px; height:100px;"></div>
+
+<script>
+window.scrollBy(0, 4000);
+</script>
diff --git a/testing/web-platform/tests/css/css-position/fixed-z-index-blend.html b/testing/web-platform/tests/css/css-position/fixed-z-index-blend.html
new file mode 100644
index 0000000000..c532a5870f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/fixed-z-index-blend.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html class="reftest-wait" style="overflow-x:hidden;">
+<title>fixed position, z-index, and mix-blend-mode</title>
+<link rel="help" href="https://www.w3.org/TR/CSS2/visuren.html#fixed-positioning">
+<link rel="help" href="https://www.w3.org/TR/CSS2/visuren.html#propdef-z-index">
+<link rel="help" href="https://www.w3.org/TR/compositing-1/#mix-blend-mode">
+<meta name="assert" content="Tests fixed, z-index, and mix-blend-mode.
+Passes if there is a green box when the page is scrolled to the bottom.">
+<link rel="author" href="mailto:masonf@chromium.org">
+<link rel="match" href="fixed-z-index-blend-ref.html">
+
+<div class="blend"></div>
+<div class="background"></div>
+<div class="text">
+ <div style="width: 100px; height:4000px;"></div>
+ <div style="background: green; width: 100px; height:100px;"></div>
+</div>
+
+<style>
+.blend {
+ display: block;
+ position: fixed;
+ z-index: 2;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+ mix-blend-mode: overlay;
+}
+
+.background {
+ pointer-events: none;
+ position: fixed;
+ z-index: 1;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+ opacity: 1;
+}
+
+.text {
+ position: relative;
+ z-index: 3;
+ overflow: hidden;
+ width: 100vw;
+ min-height: 100vh;
+ font-size: 50px;
+ line-height: 2;
+}
+</style>
+
+<script src="/common/reftest-wait.js"></script>
+<script>
+requestAnimationFrame(()=>{
+ requestAnimationFrame(()=>{
+ window.scrollBy(0, 4000);
+ takeScreenshot();
+ });
+});
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/hypothetical-box-scroll-parent-ref.html b/testing/web-platform/tests/css/css-position/hypothetical-box-scroll-parent-ref.html
new file mode 100644
index 0000000000..86956adf1d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/hypothetical-box-scroll-parent-ref.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<meta charset=utf-8>
+<!-- Our target div should be placed as if it were a child of the overflowing --
+ -- thing; this is simplest to accomplish by just having the overflowing thing --
+ -- absolutely positioned so the target div is placed as if it were not there -->
+<div style="overflow: auto; height: 100px; width: 200px; position: absolute">
+ <div style="width: 400px; height: 10px"></div>
+</div>
+<div id="target">Modified text</div>
+<script>
+ document.querySelector("div").scrollLeft = 1000;
+</script>
diff --git a/testing/web-platform/tests/css/css-position/hypothetical-box-scroll-parent.html b/testing/web-platform/tests/css/css-position/hypothetical-box-scroll-parent.html
new file mode 100644
index 0000000000..e342e8c275
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/hypothetical-box-scroll-parent.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<meta charset=utf-8>
+<title></title>
+<link rel=match href=hypothetical-box-scroll-parent-ref.html>
+<link rel="help"
+ href="https://www.w3.org/TR/CSS2/visudet.html#abs-non-replaced-width">
+<div style="overflow: auto; height: 100px; width: 200px">
+ <div id="target" style="position: absolute">Original text</div>
+ <div style="width: 400px; height: 10px"></div>
+</div>
+<script>
+ // Scroll the parent.
+ document.querySelector("div").scrollLeft = 1000;
+
+ // Now force relayout of the abs pos div.
+ document.getElementById("target").textContent = "Modified text";
+</script>
diff --git a/testing/web-platform/tests/css/css-position/hypothetical-box-scroll-viewport-ref.html b/testing/web-platform/tests/css/css-position/hypothetical-box-scroll-viewport-ref.html
new file mode 100644
index 0000000000..368da5f6d4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/hypothetical-box-scroll-viewport-ref.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<meta charset=utf-8>
+<div>Modified text</div>
+<div style="width: 200vw; height: 10px"></div>
+<script>
+ window.scrollTo(window.innerWidth * 2, 0);
+</script>
diff --git a/testing/web-platform/tests/css/css-position/hypothetical-box-scroll-viewport.html b/testing/web-platform/tests/css/css-position/hypothetical-box-scroll-viewport.html
new file mode 100644
index 0000000000..9ccb822f10
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/hypothetical-box-scroll-viewport.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<meta charset=utf-8>
+<title></title>
+<link rel=match href=hypothetical-box-scroll-viewport-ref.html>
+<link rel="help"
+ href="https://www.w3.org/TR/CSS2/visudet.html#abs-non-replaced-width">
+<div style="position: absolute">Original text</div>
+<div style="width: 200vw; height: 10px"></div>
+<script>
+ // Scroll the viewport.
+ window.scrollTo(window.innerWidth * 2, 0);
+
+ // Now force relayout of the abs pos div.
+ document.querySelector("div").textContent = "Modified text";
+</script>
diff --git a/testing/web-platform/tests/css/css-position/hypothetical-dynamic-change-001-ref.html b/testing/web-platform/tests/css/css-position/hypothetical-dynamic-change-001-ref.html
new file mode 100644
index 0000000000..12e109bd0b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/hypothetical-dynamic-change-001-ref.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>CSS test reference</title>
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<style>
+ .ancestor {
+ width: 100px;
+ height: 100px;
+ position: fixed;
+ left: 100px;
+ top: 0;
+ background-color: green;
+ }
+</style>
+<div class="ancestor"></div>
diff --git a/testing/web-platform/tests/css/css-position/hypothetical-dynamic-change-001.html b/testing/web-platform/tests/css/css-position/hypothetical-dynamic-change-001.html
new file mode 100644
index 0000000000..996f439211
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/hypothetical-dynamic-change-001.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<title>CSS test: movement of fixed-position ancestor correctly moves fixed-position descendant depending on the static position</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#size-and-position-details">
+<link rel="match" href="hypothetical-dynamic-change-001-ref.html">
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<style>
+ .ancestor, .child {
+ position: fixed;
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ /* NOTE: child remains auto-positioned */
+ }
+ .ancestor {
+ left: 0;
+ top: 0;
+ background-color: red;
+ }
+</style>
+<div class="ancestor">
+ <div class="child"></div>
+</div>
+<script>
+onload = function() {
+ let ancestor = document.querySelector(".ancestor");
+ window.unused = ancestor.getBoundingClientRect();
+ ancestor.style.left = "100px";
+}
+</script>
diff --git a/testing/web-platform/tests/css/css-position/hypothetical-dynamic-change-002.html b/testing/web-platform/tests/css/css-position/hypothetical-dynamic-change-002.html
new file mode 100644
index 0000000000..114b48dc7f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/hypothetical-dynamic-change-002.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<title>CSS test: movement of absolute-position ancestor correctly moves fixed-position descendant depending on the static position</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#size-and-position-details">
+<link rel="match" href="hypothetical-dynamic-change-001-ref.html">
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<style>
+ .ancestor, .child {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ }
+ .child {
+ position: fixed;
+ /* NOTE: child remains auto-positioned */
+ }
+ .ancestor {
+ position: absolute;
+ left: 0;
+ top: 0;
+ background-color: red;
+ }
+</style>
+<div class="ancestor">
+ <div class="child"></div>
+</div>
+<script>
+onload = function() {
+ let ancestor = document.querySelector(".ancestor");
+ window.unused = ancestor.getBoundingClientRect();
+ ancestor.style.left = "100px";
+}
+</script>
diff --git a/testing/web-platform/tests/css/css-position/hypothetical-dynamic-change-003.html b/testing/web-platform/tests/css/css-position/hypothetical-dynamic-change-003.html
new file mode 100644
index 0000000000..26a27c2695
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/hypothetical-dynamic-change-003.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<title>CSS test: movement of relative-position ancestor correctly moves fixed-position descendant depending on the static position</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#size-and-position-details">
+<link rel="match" href="hypothetical-dynamic-change-001-ref.html">
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<style>
+ body { margin: 0 }
+ .ancestor, .child {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ }
+ .child {
+ position: fixed;
+ /* NOTE: child remains auto-positioned */
+ }
+ .ancestor {
+ position: relative;
+ left: 0;
+ top: 0;
+ background-color: red;
+ }
+</style>
+<div class="ancestor">
+ <div class="child"></div>
+</div>
+<script>
+onload = function() {
+ let ancestor = document.querySelector(".ancestor");
+ window.unused = ancestor.getBoundingClientRect();
+ ancestor.style.left = "100px";
+}
+</script>
diff --git a/testing/web-platform/tests/css/css-position/inheritance.html b/testing/web-platform/tests/css/css-position/inheritance.html
new file mode 100644
index 0000000000..ef037dc732
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/inheritance.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Inheritance of CSS Positioned Layout properties</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#property-index">
+<meta name="assert" content="Properties inherit or not according to the spec.">
+<meta name="assert" content="Properties have initial values according to the spec.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/inheritance-testcommon.js"></script>
+</head>
+<body>
+<div id="container">
+<div id="target"></div>
+</div>
+<style>
+#container, #target {
+ position: sticky;
+}
+</style>
+<script>
+assert_not_inherited('position', 'static', 'absolute');
+assert_not_inherited('top', 'auto', '10px');
+assert_not_inherited('right', 'auto', '10px');
+assert_not_inherited('bottom', 'auto', '10px');
+assert_not_inherited('left', 'auto', '10px');
+assert_not_inherited('z-index', 'auto', '123');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/invalidate-opacity-negative-z-index-ref.html b/testing/web-platform/tests/css/css-position/invalidate-opacity-negative-z-index-ref.html
new file mode 100644
index 0000000000..4f8d043e5a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/invalidate-opacity-negative-z-index-ref.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<link rel="help" href="https://www.w3.org/TR/CSS2/visuren.html#propdef-z-index">
+<link rel="help" href="https://www.w3.org/TR/compositing-1/">
+<link rel="author" title="Chris Harrelson" href="mailto:chrishtr@chromium.org">
+
+<div style="position: relative; will-change: transform; z-index: -1"></div>
+<div id="target"
+ style="width: 50px; height: 50px; background: blue; opacity: 0.99"></div>
diff --git a/testing/web-platform/tests/css/css-position/invalidate-opacity-negative-z-index.html b/testing/web-platform/tests/css/css-position/invalidate-opacity-negative-z-index.html
new file mode 100644
index 0000000000..52deaa0806
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/invalidate-opacity-negative-z-index.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <link rel="help" href="https://www.w3.org/TR/CSS2/visuren.html#propdef-z-index">
+ <link rel="help" href="https://www.w3.org/TR/compositing-1/">
+ <link rel="author" title="Chris Harrelson" href="mailto:chrishtr@chromium.org">
+ <link rel="match" href="invalidate-opacity-negative-z-index-ref.html">
+
+ <div style="position: relative; will-change: transform; z-index: -1"></div>
+ <div id="target"
+ style="width: 50px; height: 50px; background: blue; opacity: 0.2"></div>
+ <script>
+ onload = () => {
+ requestAnimationFrame(() => requestAnimationFrame(() => {
+ target.style.opacity = 0.99;
+ document.documentElement.className = "";
+ }));
+ };
+ </script>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/multicol/static-position/vlr-in-multicol-ref.html b/testing/web-platform/tests/css/css-position/multicol/static-position/vlr-in-multicol-ref.html
new file mode 100644
index 0000000000..908f43a002
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/multicol/static-position/vlr-in-multicol-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<style>
+ body { writing-mode: vertical-lr; }
+ .container {
+ background: green;
+ inline-size: 80px;
+ block-size: 600px;
+ }
+ .multicol {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 0;
+ block-size: 100px;
+ inline-size: 160px;
+ }
+</style>
+
+There should be no red.
+<div class="multicol">
+ <div class="container"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/multicol/static-position/vlr-ltr-ltr-in-multicol.html b/testing/web-platform/tests/css/css-position/multicol/static-position/vlr-ltr-ltr-in-multicol.html
new file mode 100644
index 0000000000..45de6ffb42
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/multicol/static-position/vlr-ltr-ltr-in-multicol.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vlr-in-multicol-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ body { writing-mode: vertical-lr; }
+ .container {
+ position: relative;
+ background: green;
+ font: 16px/1 Ahem;
+ inline-size: 80px;
+ block-size: 100px;
+ color: green;
+ }
+ .multicol {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 0;
+ block-size: 100px;
+ inline-size: 160px;
+ }
+ .red { color: red; }
+ .cb {
+ position: relative;
+ inset-block-start: 15px;
+ inset-inline-start: 20px;
+ }
+ .rtl { direction: rtl; }
+ .ltr { direction: ltr; }
+ .inline { display: inline; }
+ .abs { position: absolute; }
+</style>
+
+There should be no red.
+<div class="multicol">
+ <div class="container ltr">
+ X<span class="ltr">X<div class="abs inline">XX</div><span class="red">XX</span></span>
+ </div>
+
+ <div class="container ltr">
+ X<span class="ltr">X<div class="abs block">XX</div><br><span class="red">XX</span></span>
+ </div>
+
+ <div class="container ltr">
+ X<span class="ltr cb">X<div class="abs inline">XX</div><span class="red">XX</span></span>
+ </div>
+
+ <div class="container ltr">
+ X<span class="ltr cb">X<div class="abs block">XX</div><br><span class="red">XX</span></span>
+ </div>
+
+ <div class="container ltr">
+ <span class="cb">X<span class="ltr">X<div class="abs inline">XX</div><span class="red">XX</span></span></span>
+ </div>
+
+ <div class="container ltr">
+ <span class="cb">X<span class="ltr">X<div class="abs block">XX</div><br><span class="red">XX</span></span></span>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/multicol/static-position/vlr-ltr-rtl-in-multicol.tentative.html b/testing/web-platform/tests/css/css-position/multicol/static-position/vlr-ltr-rtl-in-multicol.tentative.html
new file mode 100644
index 0000000000..9cb6c26e9c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/multicol/static-position/vlr-ltr-rtl-in-multicol.tentative.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vlr-in-multicol-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ body { writing-mode: vertical-lr; }
+ .container {
+ position: relative;
+ background: green;
+ font: 16px/1 Ahem;
+ inline-size: 80px;
+ block-size: 100px;
+ color: green;
+ }
+ .multicol {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 0;
+ block-size: 100px;
+ inline-size: 160px;
+ }
+ .red { color: red; }
+ .cb {
+ position: relative;
+ inset-block-start: 15px;
+ inset-inline-start: 20px;
+ }
+ .rtl { direction: rtl; }
+ .ltr { direction: ltr; }
+ .inline { display: inline; }
+ .abs { position: absolute; }
+</style>
+
+There should be no red.
+<div class="multicol">
+ <div class="container ltr">
+ X<span class="rtl">X<div class="abs inline">XX</div><span class="red">XX</span></span>
+ </div>
+
+ <div class="container ltr">
+ X<span class="rtl">X<div class="abs block">XX</div><br><span class="red">XX</span></span>
+ </div>
+
+ <div class="container ltr">
+ X<span class="rtl cb">X<div class="abs inline">XX</div><span class="red">XX</span></span>
+ </div>
+
+ <div class="container ltr">
+ X<span class="rtl cb">X<div class="abs block">XX</div><br><span class="red">XX</span></span>
+ </div>
+
+ <div class="container ltr">
+ <span class="cb">X<span class="rtl">X<div class="abs inline">XX</div><span class="red">XX</span></span></span>
+ </div>
+
+ <div class="container ltr">
+ <span class="cb">X<span class="rtl">X<div class="abs block">XX</div><br><span class="red">XX</span></span></span>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/multicol/static-position/vlr-rtl-ltr-in-multicol.tentative.html b/testing/web-platform/tests/css/css-position/multicol/static-position/vlr-rtl-ltr-in-multicol.tentative.html
new file mode 100644
index 0000000000..5a094987ba
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/multicol/static-position/vlr-rtl-ltr-in-multicol.tentative.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vlr-in-multicol-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ body { writing-mode: vertical-lr; }
+ .container {
+ position: relative;
+ background: green;
+ font: 16px/1 Ahem;
+ inline-size: 80px;
+ block-size: 100px;
+ color: green;
+ }
+ .multicol {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 0;
+ block-size: 100px;
+ inline-size: 160px;
+ }
+ .red { color: red; }
+ .cb {
+ position: relative;
+ inset-block-start: 15px;
+ inset-inline-start: 20px;
+ }
+ .rtl { direction: rtl; }
+ .ltr { direction: ltr; }
+ .inline { display: inline; }
+ .abs { position: absolute; }
+</style>
+
+There should be no red.
+<div class="multicol">
+ <div class="container rtl">
+ X<span class="ltr">X<div class="abs inline">XX</div><span class="red">XX</span></span>
+ </div>
+
+ <div class="container rtl">
+ X<span class="ltr">X<div class="abs block">XX</div><br><span class="red">XX</span></span>
+ </div>
+
+ <div class="container rtl">
+ X<span class="ltr cb">X<div class="abs inline">XX</div><span class="red">XX</span></span>
+ </div>
+
+ <div class="container rtl">
+ X<span class="ltr cb">X<div class="abs block">XX</div><br><span class="red">XX</span></span>
+ </div>
+
+ <div class="container rtl">
+ <span class="cb">X<span class="ltr">X<div class="abs inline">XX</div><span class="red">XX</span></span></span>
+ </div>
+
+ <div class="container rtl">
+ <span class="cb">X<span class="ltr">X<div class="abs block">XX</div><br><span class="red">XX</span></span></span>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/multicol/static-position/vlr-rtl-rtl-in-multicol.html b/testing/web-platform/tests/css/css-position/multicol/static-position/vlr-rtl-rtl-in-multicol.html
new file mode 100644
index 0000000000..e7c4088aa4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/multicol/static-position/vlr-rtl-rtl-in-multicol.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vlr-in-multicol-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ body { writing-mode: vertical-lr; }
+ .container {
+ position: relative;
+ background: green;
+ font: 16px/1 Ahem;
+ inline-size: 80px;
+ block-size: 100px;
+ color: green;
+ }
+ .multicol {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 0;
+ block-size: 100px;
+ inline-size: 160px;
+ }
+ .red { color: red; }
+ .cb {
+ position: relative;
+ inset-block-start: 15px;
+ inset-inline-start: 20px;
+ }
+ .rtl { direction: rtl; }
+ .ltr { direction: ltr; }
+ .inline { display: inline; }
+ .abs { position: absolute; }
+</style>
+
+There should be no red.
+<div class="multicol">
+ <div class="container rtl">
+ X<span class="rtl">X<div class="abs inline">XX</div><span class="red">XX</span></span>
+ </div>
+
+ <div class="container rtl">
+ X<span class="rtl">X<div class="abs block">XX</div><br><span class="red">XX</span></span>
+ </div>
+
+ <div class="container rtl">
+ X<span class="rtl cb">X<div class="abs inline">XX</div><span class="red">XX</span></span>
+ </div>
+
+ <div class="container rtl">
+ X<span class="rtl cb">X<div class="abs block">XX</div><br><span class="red">XX</span></span>
+ </div>
+
+ <div class="container rtl">
+ <span class="cb">X<span class="rtl">X<div class="abs inline">XX</div><span class="red">XX</span></span></span>
+ </div>
+
+ <div class="container rtl">
+ <span class="cb">X<span class="rtl">X<div class="abs block">XX</div><br><span class="red">XX</span></span></span>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/multicol/static-position/vrl-in-multicol-ref.html b/testing/web-platform/tests/css/css-position/multicol/static-position/vrl-in-multicol-ref.html
new file mode 100644
index 0000000000..0e22219eab
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/multicol/static-position/vrl-in-multicol-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<style>
+ body { writing-mode: vertical-rl; }
+ .container {
+ background: green;
+ inline-size: 80px;
+ block-size: 600px;
+ }
+ .multicol {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 0;
+ block-size: 100px;
+ inline-size: 160px;
+ }
+</style>
+
+There should be no red.
+<div class="multicol">
+ <div class="container"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/multicol/static-position/vrl-ltr-ltr-in-multicol.html b/testing/web-platform/tests/css/css-position/multicol/static-position/vrl-ltr-ltr-in-multicol.html
new file mode 100644
index 0000000000..ae5059ce78
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/multicol/static-position/vrl-ltr-ltr-in-multicol.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vrl-in-multicol-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ body { writing-mode: vertical-rl; }
+ .container {
+ position: relative;
+ background: green;
+ font: 16px/1 Ahem;
+ inline-size: 80px;
+ block-size: 100px;
+ color: green;
+ }
+ .multicol {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 0;
+ block-size: 100px;
+ inline-size: 160px;
+ }
+ .red { color: red; }
+ .cb {
+ position: relative;
+ inset-block-start: 15px;
+ inset-inline-start: 20px;
+ }
+ .rtl { direction: rtl; }
+ .ltr { direction: ltr; }
+ .inline { display: inline; }
+ .abs { position: absolute; }
+</style>
+
+There should be no red.
+<div class="multicol">
+ <div class="container ltr">
+ X<span class="ltr">X<div class="abs inline">XX</div><span class="red">XX</span></span>
+ </div>
+
+ <div class="container ltr">
+ X<span class="ltr">X<div class="abs block">XX</div><br><span class="red">XX</span></span>
+ </div>
+
+ <div class="container ltr">
+ X<span class="ltr cb">X<div class="abs inline">XX</div><span class="red">XX</span></span>
+ </div>
+
+ <div class="container ltr">
+ X<span class="ltr cb">X<div class="abs block">XX</div><br><span class="red">XX</span></span>
+ </div>
+
+ <div class="container ltr">
+ <span class="cb">X<span class="ltr">X<div class="abs inline">XX</div><span class="red">XX</span></span></span>
+ </div>
+
+ <div class="container ltr">
+ <span class="cb">X<span class="ltr">X<div class="abs block">XX</div><br><span class="red">XX</span></span></span>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/multicol/static-position/vrl-ltr-rtl-in-multicol.tentative.html b/testing/web-platform/tests/css/css-position/multicol/static-position/vrl-ltr-rtl-in-multicol.tentative.html
new file mode 100644
index 0000000000..44bf087765
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/multicol/static-position/vrl-ltr-rtl-in-multicol.tentative.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vrl-in-multicol-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ body { writing-mode: vertical-rl; }
+ .container {
+ position: relative;
+ background: green;
+ font: 16px/1 Ahem;
+ inline-size: 80px;
+ block-size: 100px;
+ color: green;
+ }
+ .multicol {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 0;
+ block-size: 100px;
+ inline-size: 160px;
+ }
+ .red { color: red; }
+ .cb {
+ position: relative;
+ inset-block-start: 15px;
+ inset-inline-start: 20px;
+ }
+ .rtl { direction: rtl; }
+ .ltr { direction: ltr; }
+ .inline { display: inline; }
+ .abs { position: absolute; }
+</style>
+
+There should be no red.
+<div class="multicol">
+ <div class="container ltr">
+ X<span class="rtl">X<div class="abs inline">XX</div><span class="red">XX</span></span>
+ </div>
+
+ <div class="container ltr">
+ X<span class="rtl">X<div class="abs block">XX</div><br><span class="red">XX</span></span>
+ </div>
+
+ <div class="container ltr">
+ X<span class="rtl cb">X<div class="abs inline">XX</div><span class="red">XX</span></span>
+ </div>
+
+ <div class="container ltr">
+ X<span class="rtl cb">X<div class="abs block">XX</div><br><span class="red">XX</span></span>
+ </div>
+
+ <div class="container ltr">
+ <span class="cb">X<span class="rtl">X<div class="abs inline">XX</div><span class="red">XX</span></span></span>
+ </div>
+
+ <div class="container ltr">
+ <span class="cb">X<span class="rtl">X<div class="abs block">XX</div><br><span class="red">XX</span></span></span>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/multicol/static-position/vrl-rtl-ltr-in-multicol.tentative.html b/testing/web-platform/tests/css/css-position/multicol/static-position/vrl-rtl-ltr-in-multicol.tentative.html
new file mode 100644
index 0000000000..3cf8e6728e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/multicol/static-position/vrl-rtl-ltr-in-multicol.tentative.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vrl-in-multicol-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ body { writing-mode: vertical-rl; }
+ .container {
+ position: relative;
+ background: green;
+ font: 16px/1 Ahem;
+ inline-size: 80px;
+ block-size: 100px;
+ color: green;
+ }
+ .multicol {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 0;
+ block-size: 100px;
+ inline-size: 160px;
+ }
+ .red { color: red; }
+ .cb {
+ position: relative;
+ inset-block-start: 15px;
+ inset-inline-start: 20px;
+ }
+ .rtl { direction: rtl; }
+ .ltr { direction: ltr; }
+ .inline { display: inline; }
+ .abs { position: absolute; }
+</style>
+
+There should be no red.
+<div class="multicol">
+ <div class="container rtl">
+ X<span class="ltr">X<div class="abs inline">XX</div><span class="red">XX</span></span>
+ </div>
+
+ <div class="container rtl">
+ X<span class="ltr">X<div class="abs block">XX</div><br><span class="red">XX</span></span>
+ </div>
+
+ <div class="container rtl">
+ X<span class="ltr cb">X<div class="abs inline">XX</div><span class="red">XX</span></span>
+ </div>
+
+ <div class="container rtl">
+ X<span class="ltr cb">X<div class="abs block">XX</div><br><span class="red">XX</span></span>
+ </div>
+
+ <div class="container rtl">
+ <span class="cb">X<span class="ltr">X<div class="abs inline">XX</div><span class="red">XX</span></span></span>
+ </div>
+
+ <div class="container rtl">
+ <span class="cb">X<span class="ltr">X<div class="abs block">XX</div><br><span class="red">XX</span></span></span>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/multicol/static-position/vrl-rtl-rtl-in-multicol.html b/testing/web-platform/tests/css/css-position/multicol/static-position/vrl-rtl-rtl-in-multicol.html
new file mode 100644
index 0000000000..a13f1cf3e9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/multicol/static-position/vrl-rtl-rtl-in-multicol.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vrl-in-multicol-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ body { writing-mode: vertical-rl; }
+ .container {
+ position: relative;
+ background: green;
+ font: 16px/1 Ahem;
+ inline-size: 80px;
+ block-size: 100px;
+ color: green;
+ }
+ .multicol {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 0;
+ block-size: 100px;
+ inline-size: 160px;
+ }
+ .red { color: red; }
+ .cb {
+ position: relative;
+ inset-block-start: 15px;
+ inset-inline-start: 20px;
+ }
+ .rtl { direction: rtl; }
+ .ltr { direction: ltr; }
+ .inline { display: inline; }
+ .abs { position: absolute; }
+</style>
+
+There should be no red.
+<div class="multicol">
+ <div class="container rtl">
+ X<span class="rtl">X<div class="abs inline">XX</div><span class="red">XX</span></span>
+ </div>
+
+ <div class="container rtl">
+ X<span class="rtl">X<div class="abs block">XX</div><br><span class="red">XX</span></span>
+ </div>
+
+ <div class="container rtl">
+ X<span class="rtl cb">X<div class="abs inline">XX</div><span class="red">XX</span></span>
+ </div>
+
+ <div class="container rtl">
+ X<span class="rtl cb">X<div class="abs block">XX</div><br><span class="red">XX</span></span>
+ </div>
+
+ <div class="container rtl">
+ <span class="cb">X<span class="rtl">X<div class="abs inline">XX</div><span class="red">XX</span></span></span>
+ </div>
+
+ <div class="container rtl">
+ <span class="cb">X<span class="rtl">X<div class="abs block">XX</div><br><span class="red">XX</span></span></span>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/multicol/vlr-in-multicols-ref.html b/testing/web-platform/tests/css/css-position/multicol/vlr-in-multicols-ref.html
new file mode 100644
index 0000000000..a85eeaad64
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/multicol/vlr-in-multicols-ref.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<style>
+ body { writing-mode: vertical-lr; }
+ .container {
+ background: green;
+ inline-size: 80px;
+ block-size: 120px;
+ }
+ .multicol {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 0;
+ block-size: 60px;
+ inline-size: 160px;
+ }
+</style>
+
+There should be no red.
+<div class="multicol">
+ <div class="container"></div>
+</div>
+
+<div class="multicol">
+ <div class="container"></div>
+</div>
+
+<div class="multicol">
+ <div class="container"></div>
+</div>
+
+<div class="multicol">
+ <div class="container"></div>
+</div>
+
+<div class="multicol">
+ <div class="container"></div>
+</div>
+
+<div class="multicol">
+ <div class="container"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/multicol/vlr-ltr-ltr-in-multicols.html b/testing/web-platform/tests/css/css-position/multicol/vlr-ltr-ltr-in-multicols.html
new file mode 100644
index 0000000000..af20086994
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/multicol/vlr-ltr-ltr-in-multicols.html
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vlr-in-multicols-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ body { writing-mode: vertical-lr; }
+ .container {
+ position: relative;
+ background: green;
+ font: 20px/1 Ahem;
+ inline-size: 80px;
+ block-size: 120px;
+ color: green;
+ }
+ .multicol {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 0;
+ block-size: 60px;
+ inline-size: 160px;
+ }
+ .red { color: red; }
+ .cb { position: relative; }
+ .rtl { direction: rtl; }
+ .ltr { direction: ltr; }
+ .inline { display: inline; }
+ .abs { position: absolute; }
+ .inset-start { inset-block-start: 0; inset-inline-start: 0; }
+ .inset-end { inset-block-end: 0; inset-inline-end: 0; }
+</style>
+
+There should be no red.
+<div class="multicol">
+ <div class="container ltr">
+ <span class="red">XX</span><span class="ltr">X
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XXXX XX<span class="red">XX</span>
+ <div class="abs inline inset-start">XX</div>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container ltr">
+ <span class="red">XX</span><span class="ltr">X
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XXXX
+ <div class="abs block inset-start">XX</div>
+ <br>XX<span class="red">XX</span>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container ltr">
+ X<span class="ltr cb"><span class="red">XX</span>
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XXXX
+ <div class="abs inline inset-start">XX</div>
+ XX<span class="red">XX</span>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container ltr">
+ X<span class="ltr cb"><span class="red">XX</span>
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs block inset-start">XX</div>
+ <br><span class="red">XX</span>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container ltr">
+ <span class="cb"><span class="red">XX</span><span class="ltr">X
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs inline inset-start">XX</div>
+ X<span class="red">XX</span>
+ </span></span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container ltr">
+ <span class="cb"><span class="red">XX</span><span class="ltr">X
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs block inset-start">XX</div>
+ <br>X<span class="red">XX</span>
+ </span></span>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/multicol/vlr-ltr-rtl-in-multicols.tentative.html b/testing/web-platform/tests/css/css-position/multicol/vlr-ltr-rtl-in-multicols.tentative.html
new file mode 100644
index 0000000000..dfb075f6ce
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/multicol/vlr-ltr-rtl-in-multicols.tentative.html
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vlr-in-multicols-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ body { writing-mode: vertical-lr; }
+ .container {
+ position: relative;
+ background: green;
+ font: 20px/1 Ahem;
+ inline-size: 80px;
+ block-size: 120px;
+ color: green;
+ }
+ .multicol {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 0;
+ block-size: 60px;
+ inline-size: 160px;
+ }
+ .red { color: red; }
+ .cb { position: relative; }
+ .rtl { direction: rtl; }
+ .ltr { direction: ltr; }
+ .inline { display: inline; }
+ .abs { position: absolute; }
+ .inset-start { inset-block-start: 0; inset-inline-start: 0; }
+ .inset-end { inset-block-end: 0; inset-inline-end: 0; }
+</style>
+
+There should be no red.
+<div class="multicol">
+ <div class="container ltr">
+ XX<span class="rtl"><span class="red">XX</span>
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XXXX <span class="red">XX</span>XX
+ <div class="abs inline inset-start">XX</div>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container ltr">
+ XX<span class="rtl"><span class="red">XX</span>
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XXXX
+ <div class="abs block inset-start">XX</div>
+ <br><span class="red">XX</span>XX
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container ltr">
+ XX<span class="rtl cb"><span class="red">XX</span>
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XXXX
+ <div class="abs inline inset-start">XX</div>
+ XX<span class="red">XX</span>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container ltr">
+ XX<span class="rtl cb"><span class="red">XX</span>
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs block inset-start">XX</div>
+ <br>XX<span class="red">XX</span>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container ltr">
+ <span class="cb">X<span class="rtl"><span class="red">XX</span>
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs inline inset-start">XX</div>
+ <span class="red">XX</span>X
+ </span></span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container ltr">
+ <span class="cb">X<span class="rtl"><span class="red">XX</span>
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs block inset-start">XX</div>
+ <br><span class="red">XX</span>X
+ </span></span>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/multicol/vlr-rtl-ltr-in-multicols.tentative.html b/testing/web-platform/tests/css/css-position/multicol/vlr-rtl-ltr-in-multicols.tentative.html
new file mode 100644
index 0000000000..bbcee5685a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/multicol/vlr-rtl-ltr-in-multicols.tentative.html
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vlr-in-multicols-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ body { writing-mode: vertical-lr; }
+ .container {
+ position: relative;
+ background: green;
+ font: 20px/1 Ahem;
+ inline-size: 80px;
+ block-size: 120px;
+ color: green;
+ }
+ .multicol {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 0;
+ block-size: 60px;
+ inline-size: 160px;
+ }
+ .red { color: red; }
+ .cb { position: relative; }
+ .rtl { direction: rtl; }
+ .ltr { direction: ltr; }
+ .inline { display: inline; }
+ .abs { position: absolute; }
+ .inset-start { inset-block-start: 0; inset-inline-start: 0; }
+ .inset-end { inset-block-end: 0; inset-inline-end: 0; }
+</style>
+
+There should be no red.
+<div class="multicol">
+ <div class="container rtl">
+ <span class="red">XX</span><span class="ltr">XX
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XXXX XX<span class="red">XX</span>
+ <div class="abs inline inset-start">XX</div>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container rtl">
+ <span class="red">XX</span><span class="ltr">XX
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XXXX
+ <div class="abs block inset-start">XX</div>
+ <br>XX<span class="red">XX</span>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container rtl">
+ <span class="red">XX</span><span class="ltr cb">XX
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XXXX
+ <div class="abs inline inset-start">XX</div>
+ XX<span class="red">XX</span>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container rtl">
+ X<span class="ltr cb"><span class="red">XX</span>
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs block inset-start">XX</div>
+ <br><span class="red">XX</span>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container rtl">
+ <span class="cb"><span class="red">XX</span><span class="ltr">X
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs inline inset-start">XX</div>
+ X<span class="red">XX</span>
+ </span></span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container rtl">
+ <span class="cb"><span class="red">XX</span><span class="ltr">X
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs block inset-start">XX</div>
+ <br>X<span class="red">XX</span>
+ </span></span>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/multicol/vlr-rtl-rtl-in-multicols.html b/testing/web-platform/tests/css/css-position/multicol/vlr-rtl-rtl-in-multicols.html
new file mode 100644
index 0000000000..fefae97f35
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/multicol/vlr-rtl-rtl-in-multicols.html
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vlr-in-multicols-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ body { writing-mode: vertical-lr; }
+ .container {
+ position: relative;
+ background: green;
+ font: 20px/1 Ahem;
+ inline-size: 80px;
+ block-size: 120px;
+ color: green;
+ }
+ .multicol {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 0;
+ block-size: 60px;
+ inline-size: 160px;
+ }
+ .red { color: red; }
+ .cb { position: relative; }
+ .rtl { direction: rtl; }
+ .ltr { direction: ltr; }
+ .inline { display: inline; }
+ .abs { position: absolute; }
+ .inset-start { inset-block-start: 0; inset-inline-start: 0; }
+ .inset-end { inset-block-end: 0; inset-inline-end: 0; }
+</style>
+
+There should be no red.
+<div class="multicol">
+ <div class="container rtl">
+ X<span class="rtl"><span class="red">XX</span>
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XXXX <span class="red">XX</span>XX
+ <div class="abs inline inset-start">XX</div>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container rtl">
+ X<span class="rtl"><span class="red">XX</span>
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XXXX
+ <div class="abs block inset-start">XX</div>
+ <br><span class="red">XX</span>XX
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container rtl">
+ X<span class="rtl cb"><span class="red">XX</span>
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XXXX
+ <div class="abs inline inset-start">XX</div>
+ <span class="red">XX</span>XX
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container rtl">
+ X<span class="rtl cb"><span class="red">XX</span>
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs block inset-start">XX</div>
+ <br><span class="red">XX</span>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container rtl">
+ <span class="cb">X<span class="rtl"><span class="red">XX</span>
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs inline inset-start">XX</div>
+ <span class="red">XX</span>X
+ </span></span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container rtl">
+ <span class="cb">X<span class="rtl"><span class="red">XX</span>
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs block inset-start">XX</div>
+ <br><span class="red">XX</span>X
+ </span></span>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/multicol/vrl-in-multicols-ref.html b/testing/web-platform/tests/css/css-position/multicol/vrl-in-multicols-ref.html
new file mode 100644
index 0000000000..858cbb52c8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/multicol/vrl-in-multicols-ref.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<style>
+ body { writing-mode: vertical-rl; }
+ .container {
+ background: green;
+ inline-size: 80px;
+ block-size: 120px;
+ }
+ .multicol {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 0;
+ block-size: 60px;
+ inline-size: 160px;
+ }
+</style>
+
+There should be no red.
+<div class="multicol">
+ <div class="container"></div>
+</div>
+
+<div class="multicol">
+ <div class="container"></div>
+</div>
+
+<div class="multicol">
+ <div class="container"></div>
+</div>
+
+<div class="multicol">
+ <div class="container"></div>
+</div>
+
+<div class="multicol">
+ <div class="container"></div>
+</div>
+
+<div class="multicol">
+ <div class="container"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/multicol/vrl-ltr-ltr-in-multicols.html b/testing/web-platform/tests/css/css-position/multicol/vrl-ltr-ltr-in-multicols.html
new file mode 100644
index 0000000000..1d8390cd7c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/multicol/vrl-ltr-ltr-in-multicols.html
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vrl-in-multicols-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ body { writing-mode: vertical-rl; }
+ .container {
+ position: relative;
+ background: green;
+ font: 20px/1 Ahem;
+ inline-size: 80px;
+ block-size: 120px;
+ color: green;
+ }
+ .multicol {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 0;
+ block-size: 60px;
+ inline-size: 160px;
+ }
+ .red { color: red; }
+ .cb { position: relative; }
+ .rtl { direction: rtl; }
+ .ltr { direction: ltr; }
+ .inline { display: inline; }
+ .abs { position: absolute; }
+ .inset-start { inset-block-start: 0; inset-inline-start: 0; }
+ .inset-end { inset-block-end: 0; inset-inline-end: 0; }
+</style>
+
+There should be no red.
+<div class="multicol">
+ <div class="container ltr">
+ <span class="red">XX</span><span class="ltr">X
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XXXX XX<span class="red">XX</span>
+ <div class="abs inline inset-start">XX</div>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container ltr">
+ <span class="red">XX</span><span class="ltr">X
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XXXX
+ <div class="abs block inset-start">XX</div>
+ <br>XX<span class="red">XX</span>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container ltr">
+ X<span class="ltr cb"><span class="red">XX</span>
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XXXX
+ <div class="abs inline inset-start">XX</div>
+ XX<span class="red">XX</span>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container ltr">
+ X<span class="ltr cb"><span class="red">XX</span>
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs block inset-start">XX</div>
+ <br><span class="red">XX</span>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container ltr">
+ <span class="cb"><span class="red">XX</span><span class="ltr">X
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs inline inset-start">XX</div>
+ X<span class="red">XX</span>
+ </span></span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container ltr">
+ <span class="cb"><span class="red">XX</span><span class="ltr">X
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs block inset-start">XX</div>
+ <br>X<span class="red">XX</span>
+ </span></span>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/multicol/vrl-ltr-rtl-in-multicols.tentative.html b/testing/web-platform/tests/css/css-position/multicol/vrl-ltr-rtl-in-multicols.tentative.html
new file mode 100644
index 0000000000..9806e9c932
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/multicol/vrl-ltr-rtl-in-multicols.tentative.html
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vrl-in-multicols-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ body { writing-mode: vertical-rl; }
+ .container {
+ position: relative;
+ background: green;
+ font: 20px/1 Ahem;
+ inline-size: 80px;
+ block-size: 120px;
+ color: green;
+ }
+ .multicol {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 0;
+ block-size: 60px;
+ inline-size: 160px;
+ }
+ .red { color: red; }
+ .cb { position: relative; }
+ .rtl { direction: rtl; }
+ .ltr { direction: ltr; }
+ .inline { display: inline; }
+ .abs { position: absolute; }
+ .inset-start { inset-block-start: 0; inset-inline-start: 0; }
+ .inset-end { inset-block-end: 0; inset-inline-end: 0; }
+</style>
+
+There should be no red.
+<div class="multicol">
+ <div class="container ltr">
+ XX<span class="rtl"><span class="red">XX</span>
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XXXX <span class="red">XX</span>XX
+ <div class="abs inline inset-start">XX</div>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container ltr">
+ XX<span class="rtl"><span class="red">XX</span>
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XXXX
+ <div class="abs block inset-start">XX</div>
+ <br><span class="red">XX</span>XX
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container ltr">
+ XX<span class="rtl cb"><span class="red">XX</span>
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XXXX
+ <div class="abs inline inset-start">XX</div>
+ XX<span class="red">XX</span>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container ltr">
+ XX<span class="rtl cb"><span class="red">XX</span>
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs block inset-start">XX</div>
+ <br>XX<span class="red">XX</span>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container ltr">
+ <span class="cb">X<span class="rtl"><span class="red">XX</span>
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs inline inset-start">XX</div>
+ <span class="red">XX</span>X
+ </span></span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container ltr">
+ <span class="cb">X<span class="rtl"><span class="red">XX</span>
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs block inset-start">XX</div>
+ <br><span class="red">XX</span>X
+ </span></span>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/multicol/vrl-rtl-ltr-in-multicols.tentative.html b/testing/web-platform/tests/css/css-position/multicol/vrl-rtl-ltr-in-multicols.tentative.html
new file mode 100644
index 0000000000..091f678158
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/multicol/vrl-rtl-ltr-in-multicols.tentative.html
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vrl-in-multicols-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ body { writing-mode: vertical-rl; }
+ .container {
+ position: relative;
+ background: green;
+ font: 20px/1 Ahem;
+ inline-size: 80px;
+ block-size: 120px;
+ color: green;
+ }
+ .multicol {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 0;
+ block-size: 60px;
+ inline-size: 160px;
+ }
+ .red { color: red; }
+ .cb { position: relative; }
+ .rtl { direction: rtl; }
+ .ltr { direction: ltr; }
+ .inline { display: inline; }
+ .abs { position: absolute; }
+ .inset-start { inset-block-start: 0; inset-inline-start: 0; }
+ .inset-end { inset-block-end: 0; inset-inline-end: 0; }
+</style>
+
+There should be no red.
+<div class="multicol">
+ <div class="container rtl">
+ <span class="red">XX</span><span class="ltr">XX
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XXXX XX<span class="red">XX</span>
+ <div class="abs inline inset-start">XX</div>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container rtl">
+ <span class="red">XX</span><span class="ltr">XX
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XXXX
+ <div class="abs block inset-start">XX</div>
+ <br>XX<span class="red">XX</span>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container rtl">
+ <span class="red">XX</span><span class="ltr cb">XX
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XXXX
+ <div class="abs inline inset-start">XX</div>
+ XX<span class="red">XX</span>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container rtl">
+ X<span class="ltr cb"><span class="red">XX</span>
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs block inset-start">XX</div>
+ <br><span class="red">XX</span>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container rtl">
+ <span class="cb"><span class="red">XX</span><span class="ltr">X
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs inline inset-start">XX</div>
+ X<span class="red">XX</span>
+ </span></span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container rtl">
+ <span class="cb"><span class="red">XX</span><span class="ltr">X
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs block inset-start">XX</div>
+ <br>X<span class="red">XX</span>
+ </span></span>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/multicol/vrl-rtl-rtl-in-multicols.html b/testing/web-platform/tests/css/css-position/multicol/vrl-rtl-rtl-in-multicols.html
new file mode 100644
index 0000000000..b402d08fae
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/multicol/vrl-rtl-rtl-in-multicols.html
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vrl-in-multicols-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ body { writing-mode: vertical-rl; }
+ .container {
+ position: relative;
+ background: green;
+ font: 20px/1 Ahem;
+ inline-size: 80px;
+ block-size: 120px;
+ color: green;
+ }
+ .multicol {
+ column-count: 2;
+ column-fill: auto;
+ column-gap: 0;
+ block-size: 60px;
+ inline-size: 160px;
+ }
+ .red { color: red; }
+ .cb { position: relative; }
+ .rtl { direction: rtl; }
+ .ltr { direction: ltr; }
+ .inline { display: inline; }
+ .abs { position: absolute; }
+ .inset-start { inset-block-start: 0; inset-inline-start: 0; }
+ .inset-end { inset-block-end: 0; inset-inline-end: 0; }
+</style>
+
+There should be no red.
+<div class="multicol">
+ <div class="container rtl">
+ X<span class="rtl"><span class="red">XX</span>
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XXXX <span class="red">XX</span>XX
+ <div class="abs inline inset-start">XX</div>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container rtl">
+ X<span class="rtl"><span class="red">XX</span>
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XXXX
+ <div class="abs block inset-start">XX</div>
+ <br><span class="red">XX</span>XX
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container rtl">
+ X<span class="rtl cb"><span class="red">XX</span>
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XXXX
+ <div class="abs inline inset-start">XX</div>
+ <span class="red">XX</span>XX
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container rtl">
+ X<span class="rtl cb"><span class="red">XX</span>
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs block inset-start">XX</div>
+ <br><span class="red">XX</span>
+ </span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container rtl">
+ <span class="cb">X<span class="rtl"><span class="red">XX</span>
+ <div class="abs inline inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs inline inset-start">XX</div>
+ <span class="red">XX</span>X
+ </span></span>
+ </div>
+</div>
+
+<div class="multicol">
+ <div class="container rtl">
+ <span class="cb">X<span class="rtl"><span class="red">XX</span>
+ <div class="abs block inset-end">XX</div>
+ XXXX XXXX XXXX XX
+ <div class="abs block inset-start">XX</div>
+ <br><span class="red">XX</span>X
+ </span></span>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/nested-positions-crash.html b/testing/web-platform/tests/css/css-position/nested-positions-crash.html
new file mode 100644
index 0000000000..dbc272fa09
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/nested-positions-crash.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/1098840">
+<title>Verifies changing 'display' nested positions is not problematic</title>
+<div style="position:absolute; display:table;">
+ <div style="position:fixed;"></div>
+</div>
+<span></span>
+<div id="boom" style="display:none;"></div>
+<script>
+ document.body.offsetTop;
+ boom.style.display = "block";
+</script>
diff --git a/testing/web-platform/tests/css/css-position/overlay/animation/overlay-interpolation.html b/testing/web-platform/tests/css/css-position/overlay/animation/overlay-interpolation.html
new file mode 100644
index 0000000000..a3034b88c1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/overlay/animation/overlay-interpolation.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://drafts.csswg.org/css-position-4/#overlay">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+const alwaysAuto = [
+ {at: -1, expect: 'auto'},
+ {at: 0, expect: 'auto'},
+ {at: 0.1, expect: 'auto'},
+ {at: 0.9, expect: 'auto'},
+ {at: 1, expect: 'auto'},
+ {at: 1.5, expect: 'auto'},
+];
+const alwaysNone = [
+ {at: -1, expect: 'none'},
+ {at: 0, expect: 'none'},
+ {at: 0.1, expect: 'none'},
+ {at: 0.9, expect: 'none'},
+ {at: 1, expect: 'none'},
+ {at: 1.5, expect: 'none'},
+];
+
+test_interpolation({
+ property: 'overlay',
+ from: 'auto',
+ to: 'none',
+ // transition:all is not supposed to allow overlay to be transitioned.
+ 'CSS Transitions with transition: all': alwaysNone,
+}, [
+ {at: -1, expect: 'auto'},
+ {at: 0, expect: 'auto'},
+ {at: 0.1, expect: 'auto'},
+ {at: 0.9, expect: 'auto'},
+ {at: 1, expect: 'none'},
+ {at: 1.5, expect: 'none'},
+]);
+
+test_interpolation({
+ property: 'overlay',
+ from: 'none',
+ to: 'auto',
+ // transition:all is not supposed to allow overlay to be transitioned.
+ 'CSS Transitions with transition: all': alwaysAuto,
+}, [
+ {at: -1, expect: 'none'},
+ {at: 0, expect: 'none'},
+ {at: 0.1, expect: 'auto'},
+ {at: 0.9, expect: 'auto'},
+ {at: 1, expect: 'auto'},
+ {at: 1.5, expect: 'auto'},
+]);
+
+test_interpolation({
+ property: 'overlay',
+ from: 'auto',
+ to: 'auto'
+}, [
+ {at: -1, expect: 'auto'},
+ {at: 0, expect: 'auto'},
+ {at: 0.5, expect: 'auto'},
+ {at: 1, expect: 'auto'},
+ {at: 1.5, expect: 'auto'},
+]);
+
+test_interpolation({
+ property: 'overlay',
+ from: 'none',
+ to: 'none'
+}, [
+ {at: -1, expect: 'none'},
+ {at: 0, expect: 'none'},
+ {at: 0.5, expect: 'none'},
+ {at: 1, expect: 'none'},
+ {at: 1.5, expect: 'none'},
+]);
+</script>
diff --git a/testing/web-platform/tests/css/css-position/overlay/green-ref.html b/testing/web-platform/tests/css/css-position/overlay/green-ref.html
new file mode 100644
index 0000000000..bef7405e96
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/overlay/green-ref.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<title>CSS Test Reference</title>
+<body style="background-color:green"></body>
diff --git a/testing/web-platform/tests/css/css-position/overlay/overlay-computed.html b/testing/web-platform/tests/css/css-position/overlay/overlay-computed.html
new file mode 100644
index 0000000000..f1a0a315de
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/overlay/overlay-computed.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title>CSS Positioned Layout Module Test: getComputedStyle().overlay</title>
+<link rel="help" href="https://drafts.csswg.org/css-position-4/#overlay">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<div id="target"></div>
+<script>
+ test_computed_value("overlay", "none", "none");
+ // 'auto' also computes to 'none' due to this UA style while the element is
+ // not in the top layer:
+ //
+ // * { overlay: none !important }
+ test_computed_value("overlay", "auto", "none");
+ test_computed_value("overlay", "inherit", "none");
+ test_computed_value("overlay", "initial", "none");
+ test_computed_value("overlay", "revert", "none");
+ test_computed_value("overlay", "unset", "none");
+</script>
diff --git a/testing/web-platform/tests/css/css-position/overlay/overlay-invalid.html b/testing/web-platform/tests/css/css-position/overlay/overlay-invalid.html
new file mode 100644
index 0000000000..e84d0c8a6b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/overlay/overlay-invalid.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<title>CSS Positioned Layout Module Test: parsing overlay with invalid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-position-4/#overlay">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<script>
+ // overlay: none | auto
+ test_invalid_value("overlay", "browser");
+ test_invalid_value("overlay", "normal");
+ test_invalid_value("overlay", "none auto");
+ test_invalid_value("overlay", "none, auto");
+ test_invalid_value("overlay", "\'auto\'");
+ test_invalid_value("overlay", "\'none\'");
+</script>
diff --git a/testing/web-platform/tests/css/css-position/overlay/overlay-popover-backdrop-crash.html b/testing/web-platform/tests/css/css-position/overlay/overlay-popover-backdrop-crash.html
new file mode 100644
index 0000000000..f59fc5db4a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/overlay/overlay-popover-backdrop-crash.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>CSS Position Test: Chrome crash for ::backdrop transitioning overlay for popover</title>
+<link rel="help" href="https://crbug.com/1446479">
+<script src="/common/reftest-wait.js"></script>
+<style>
+ #popover {
+ transition: overlay 60s step-end;
+ display: block;
+ }
+ #popover::backdrop {
+ background: rgba(0, 0, 0, 0.2);
+ }
+</style>
+<p>PASS if no crash.</p>
+<div id="popover" popover></div>
+<script>
+ requestAnimationFrame(() => {
+ popover.showPopover();
+ requestAnimationFrame(() => {
+ popover.hidePopover();
+ takeScreenshot();
+ });
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-position/overlay/overlay-transition-backdrop-entry.html b/testing/web-platform/tests/css/css-position/overlay/overlay-transition-backdrop-entry.html
new file mode 100644
index 0000000000..8737dc58f9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/overlay/overlay-transition-backdrop-entry.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<title>CSS Position Test: overlay transition with ::backdrop during entry animation</title>
+<link rel="help" href="https://drafts.csswg.org/css-position-4/#overlay">
+<link rel="match" href="green-ref.html">
+<link rel="author" href="mailto:jarhar@chromium.org">
+<style>
+ body {
+ background-color: green;
+ }
+ [popover] {
+ display: block;
+ visibility: hidden;
+ transition-delay: 2s;
+ transition-property: overlay;
+ transition-duration: 2s;
+ transition-behavior: allow-discrete;
+ }
+ [popover]::backdrop {
+ background-color: blue;
+ }
+</style>
+<div popover id="foo"></div>
+<script>
+ foo.offsetTop;
+ foo.showPopover();
+</script>
diff --git a/testing/web-platform/tests/css/css-position/overlay/overlay-transition-backdrop.html b/testing/web-platform/tests/css/css-position/overlay/overlay-transition-backdrop.html
new file mode 100644
index 0000000000..898b6b2e0f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/overlay/overlay-transition-backdrop.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<title>CSS Position Test: overlay transition with ::backdrop</title>
+<link rel="help" href="https://drafts.csswg.org/css-position-4/#overlay">
+<link rel="match" href="green-ref.html">
+<link rel="author" href="mailto:jarhar@chromium.org">
+<style>
+ [popover] {
+ display: block;
+ visibility: hidden;
+ transition: overlay 60s step-end;
+ transition-behavior: allow-discrete;
+ }
+ [popover]::backdrop {
+ visibility: visible;
+ background-color: green;
+ }
+</style>
+<div popover id="foo"></div>
+<script>
+ foo.showPopover();
+ foo.hidePopover();
+</script>
diff --git a/testing/web-platform/tests/css/css-position/overlay/overlay-transition-dialog-ref.html b/testing/web-platform/tests/css/css-position/overlay/overlay-transition-dialog-ref.html
new file mode 100644
index 0000000000..b0b8d52e78
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/overlay/overlay-transition-dialog-ref.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<dialog>dialog</dialog>
+<script>
+document.querySelector('dialog').showModal();
+document.activeElement.blur();
+</script>
diff --git a/testing/web-platform/tests/css/css-position/overlay/overlay-transition-dialog.html b/testing/web-platform/tests/css/css-position/overlay/overlay-transition-dialog.html
new file mode 100644
index 0000000000..0e1297cce7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/overlay/overlay-transition-dialog.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://drafts.csswg.org/css-position-4/#overlay">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1451910">
+<link rel=help href="https://github.com/whatwg/html/pull/9387">
+<link rel=match href="overlay-transition-dialog-ref.html">
+
+<dialog>dialog</dialog>
+
+<style>
+dialog.animate {
+ transition: overlay 2s allow-discrete, display 2s allow-discrete;
+}
+</style>
+
+<script>
+const dialog = document.querySelector('dialog');
+dialog.showModal();
+dialog.classList.add('animate');
+dialog.close();
+requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ document.documentElement.classList.remove('reftest-wait');
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-position/overlay/overlay-transition-finished.html b/testing/web-platform/tests/css/css-position/overlay/overlay-transition-finished.html
new file mode 100644
index 0000000000..7e22cb3cf6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/overlay/overlay-transition-finished.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>CSS Positioned Layout Module Test: 'overlay' rendering on top after transition finished</title>
+<link rel="help" href="https://drafts.csswg.org/css-position-4/#overlay">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/popover.html">
+<link rel="match" href="green-ref.html">
+<script src="/common/reftest-wait.js"></script>
+<style>
+ #transition-in, #red {
+ /* Force display:block both popover open or closed to not rely on
+ @starting-style or display transitions. */
+ display: block;
+ border: none;
+ width: 100vw;
+ height: 100vh;
+ }
+ #red {
+ position: fixed;
+ background-color: red;
+ }
+ #transition-in {
+ transition: overlay 0.1s step-end;
+ transition-behavior: allow-discrete;
+ background-color: green;
+ }
+</style>
+<div id="transition-in" popover></div>
+<div id="red"></div>
+<script>
+ let transition_in = document.querySelector("#transition-in");
+ transition_in.addEventListener("transitionend", () => takeScreenshot());
+ // Force style update to have before-change style for overlay transition.
+ transition_in.offsetTop;
+ transition_in.showPopover();
+ if (getComputedStyle(transition_in).overlay != "none") {
+ // Transition didn't start, force a fail condition.
+ transition_in.style.backgroundColor = "pink";
+ takeScreenshot();
+ }
+</script>
diff --git a/testing/web-platform/tests/css/css-position/overlay/overlay-transition-in-rendering.html b/testing/web-platform/tests/css/css-position/overlay/overlay-transition-in-rendering.html
new file mode 100644
index 0000000000..0ada33c33c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/overlay/overlay-transition-in-rendering.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<title>CSS Positioned Layout Module Test: 'overlay' transitioning in not rendered in top layer</title>
+<link rel="help" href="https://drafts.csswg.org/css-position-4/#overlay">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/popover.html">
+<link rel="match" href="green-ref.html">
+<style>
+ #transition-in, #green {
+ /* Force display:block both popover open or closed to not rely on
+ @starting-style or display transitions. */
+ display: block;
+ border: none;
+ width: 100vw;
+ height: 100vh;
+ }
+ #green {
+ background-color: green;
+ }
+ #transition-in {
+ transition: overlay 60s step-end;
+ transition-behavior: allow-discrete;
+ background-color: red;
+ }
+</style>
+<div id="green" popover="manual"></div>
+<div id="transition-in" popover="manual"></div>
+<script>
+ document.querySelector("#green").showPopover();
+ document.querySelector("#transition-in").showPopover();
+</script>
diff --git a/testing/web-platform/tests/css/css-position/overlay/overlay-transition-out-rendering.html b/testing/web-platform/tests/css/css-position/overlay/overlay-transition-out-rendering.html
new file mode 100644
index 0000000000..abb01faef7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/overlay/overlay-transition-out-rendering.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>CSS Positioned Layout Module Test: 'overlay' transitioning out still rendered in top layer</title>
+<link rel="help" href="https://drafts.csswg.org/css-position-4/#overlay">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/popover.html">
+<link rel="match" href="green-ref.html">
+<style>
+ #green, #red {
+ /* Force display:block both popover open or closed to not rely on
+ @starting-style or display transitions. */
+ display: block;
+ border: none;
+ width: 100vw;
+ height: 100vh;
+ }
+ #red {
+ background-color: red;
+ }
+ #green {
+ background-color: green;
+ }
+ #green.transition-enabled {
+ transition: overlay 60s step-end;
+ transition-behavior: allow-discrete;
+ }
+</style>
+<div id="red" popover="manual"></div>
+<div id="green" popover="manual"></div>
+<script>
+ red.showPopover();
+ green.showPopover();
+ document.body.offsetTop;
+ green.className = "transition-enabled";
+ green.hidePopover();
+</script>
diff --git a/testing/web-platform/tests/css/css-position/overlay/overlay-transition-property.html b/testing/web-platform/tests/css/css-position/overlay/overlay-transition-property.html
new file mode 100644
index 0000000000..dddb0c89e1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/overlay/overlay-transition-property.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<title>CSS Positioned Layout Module Test: 'overlay' is a valid transition-property value</title>
+<link rel="help" href="https://drafts.csswg.org/css-position-4/#overlay">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<div id="target"></div>
+<script>
+ test_valid_value("transition-property", "overlay");
+ test_valid_value("transition", "overlay 2s");
+
+ test_computed_value("transition-property", "overlay");
+ test_computed_value("transition", "overlay 1s");
+</script>
diff --git a/testing/web-platform/tests/css/css-position/overlay/overlay-transition.html b/testing/web-platform/tests/css/css-position/overlay/overlay-transition.html
new file mode 100644
index 0000000000..efe402373f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/overlay/overlay-transition.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<title>CSS Positioned Layout Module Test: 'overlay' is transitioned in and out of 'auto'</title>
+<link rel="help" href="https://drafts.csswg.org/css-position-4/#overlay">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/popover.html">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ #transition-in, #transition-out {
+ /* Force display:block both popover open or closed to not rely on
+ @starting-style or display transitions. */
+ display: block;
+ }
+ .enable-transitions :is(#transition-in, #transition-out) {
+ transition: overlay 60s step-end;
+ transition-behavior: allow-discrete;
+ }
+</style>
+<div id="container">
+ <div id="transition-in" popover></div>
+ <div id="transition-out" popover></div>
+</div>
+<script>
+ let transition_in = document.querySelector("#transition-in");
+ let transition_out = document.querySelector("#transition-out");
+
+ test(() => {
+ transition_out.showPopover();
+ assert_equals(getComputedStyle(transition_in).overlay, "none");
+ assert_equals(getComputedStyle(transition_out).overlay, "auto");
+ }, "Open the popover to be closed and verify computed overlay for both popovers");
+
+ container.className = "enable-transitions";
+
+ test(() => {
+ assert_true(transition_out.matches(':popover-open'));
+ assert_false(transition_in.matches(':popover-open'));
+ transition_in.showPopover();
+ assert_true(transition_in.matches(':popover-open'));
+ assert_false(transition_out.matches(':popover-open'));
+ assert_equals(getComputedStyle(transition_in).overlay, "none",
+ 'Transition in should be delayed');
+ assert_equals(getComputedStyle(transition_out).overlay, "auto",
+ 'Transition out should be delayed');
+ }, "Transition overlays");
+</script>
diff --git a/testing/web-platform/tests/css/css-position/overlay/overlay-user-agent-rules.html b/testing/web-platform/tests/css/css-position/overlay/overlay-user-agent-rules.html
new file mode 100644
index 0000000000..427eb8f7e4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/overlay/overlay-user-agent-rules.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/whatwg/html/pull/9093">
+<link rel=help href="https://drafts.csswg.org/css-position-4/#overlay">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<title>CSS Position Test: User agent style for overlay</title>
+
+<style>
+div {
+ overlay: auto;
+}
+</style>
+
+<body>
+<script>
+test(() => {
+ const div = document.createElement('div');
+ document.body.appendChild(div);
+ div.style.overlay = 'auto';
+ assert_equals(getComputedStyle(div).overlay, 'none');
+}, 'HTML elements should have overlay:none !important from the user-agent.');
+
+test(() => {
+ const svg = document.createElement('svg');
+ document.body.appendChild(svg);
+ svg.style.overlay = 'auto';
+ assert_equals(getComputedStyle(svg).overlay, 'none');
+}, 'SVG elements should have overlay:none !important from the user-agent.');
+
+test(() => {
+ const nullNamespace = document.createElementNS(null, 'div');
+ document.body.appendChild(nullNamespace);
+ assert_equals(getComputedStyle(nullNamespace).overlay, 'none');
+}, 'Null namespace elements should have overlay:none !important from the user-agent.');
+
+test(() => {
+ const weirdNamespace = document.createElementNS('hello world', 'div');
+ document.body.appendChild(weirdNamespace);
+ assert_equals(getComputedStyle(weirdNamespace).overlay, 'none');
+}, 'Arbitrary namespace elements should have overlay:none !important from the user-agent.');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/overlay/overlay-valid.html b/testing/web-platform/tests/css/css-position/overlay/overlay-valid.html
new file mode 100644
index 0000000000..8d808ac6dc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/overlay/overlay-valid.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<title>CSS Positioned Layout Module Test: parsing overlay with valid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-position-4/#overlay">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<script>
+ // overlay: none | auto
+ test_valid_value("overlay", "none");
+ test_valid_value("overlay", "auto");
+ test_valid_value("overlay", "inherit");
+ test_valid_value("overlay", "initial");
+ test_valid_value("overlay", "revert");
+ test_valid_value("overlay", "unset");
+</script>
diff --git a/testing/web-platform/tests/css/css-position/parsing/bottom-computed.html b/testing/web-platform/tests/css/css-position/parsing/bottom-computed.html
new file mode 100644
index 0000000000..baeef5daa5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/parsing/bottom-computed.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Positioned Layout Module Level 3: getComputedStyle().bottom</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#propdef-bottom">
+<meta name="assert" content="bottom lengths are made absolute.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<style>
+ #target {
+ font-size: 40px;
+ }
+</style>
+<script>
+test_computed_value("bottom", "auto");
+
+test_computed_value("bottom", "calc(10px + 0.5em)", "30px");
+test_computed_value("bottom", "calc(10px - 0.5em)", "-10px");
+test_computed_value("bottom", "-40%");
+test_computed_value("bottom", "calc(50% + 60px)");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/parsing/bottom-invalid.html b/testing/web-platform/tests/css/css-position/parsing/bottom-invalid.html
new file mode 100644
index 0000000000..6ed6fdd6d4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/parsing/bottom-invalid.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Positioned Layout Module Level 3: parsing bottom with invalid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#propdef-bottom">
+<meta name="assert" content="bottom supports only the grammar 'auto | <length-percentage>'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value("bottom", "min-content");
+
+test_invalid_value("bottom", "60");
+test_invalid_value("bottom", "10px 20%");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/parsing/bottom-valid.html b/testing/web-platform/tests/css/css-position/parsing/bottom-valid.html
new file mode 100644
index 0000000000..7a20bd722b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/parsing/bottom-valid.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Positioned Layout Module Level 3: parsing bottom with valid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#propdef-bottom">
+<meta name="assert" content="bottom supports the full grammar 'auto | <length-percentage>'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value("bottom", "auto");
+
+test_valid_value("bottom", "-10px");
+test_valid_value("bottom", "-20%");
+test_valid_value("bottom", "calc(2em + 3ex)");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/parsing/inset-computed.html b/testing/web-platform/tests/css/css-position/parsing/inset-computed.html
new file mode 100644
index 0000000000..2a52785e32
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/parsing/inset-computed.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Positioned Layout Module: getComputedStyle() for inset properties</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#insets">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<style>
+ #target {
+ font-size: 40px;
+ }
+</style>
+<script>
+ const values = [
+ // [input, serialized(optional)]
+ ["auto"],
+ ["calc(10px + 0.5em)", "30px"],
+ ["calc(10px - 0.5em)", "-10px"],
+ ["-40%"],
+ ["calc(50% + 60px)"]
+ ];
+ function test_inset_longhand(longhand_property) {
+ for (let value of values) {
+ if (value[1] === undefined)
+ test_computed_value(longhand_property, value[0]);
+ else
+ test_computed_value(longhand_property, value[0], value[1]);
+ }
+ }
+
+ test_inset_longhand("inset-block-start");
+ test_inset_longhand("inset-block-end");
+ test_inset_longhand("inset-inline-start");
+ test_inset_longhand("inset-inline-end");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/parsing/inset-invalid.html b/testing/web-platform/tests/css/css-position/parsing/inset-invalid.html
new file mode 100644
index 0000000000..a96d625382
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/parsing/inset-invalid.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Positioned Layout Module: parsing inset with invalid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#insets">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+ const single_values = [
+ "0deg",
+ "calc(20deg)",
+ "10"
+ ];
+ const double_values = [
+ "inherit auto",
+ "inherit inherit"
+ ];
+ function test_inset_longhand(longhand_property) {
+ for (let value of single_values)
+ test_invalid_value(longhand_property, value);
+ }
+ function test_inset_shorthand(shorthand_property) {
+ for (let value of single_values)
+ test_invalid_value(shorthand_property, value);
+ for (let value of double_values)
+ test_invalid_value(shorthand_property, value);
+ }
+
+ test_inset_longhand("inset-block-start");
+ test_inset_longhand("inset-block-end");
+ test_inset_longhand("inset-inline-start");
+ test_inset_longhand("inset-inline-end");
+
+ test_inset_shorthand("inset-block");
+ test_inset_shorthand("inset-inline");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/parsing/inset-valid.html b/testing/web-platform/tests/css/css-position/parsing/inset-valid.html
new file mode 100644
index 0000000000..0faab98737
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/parsing/inset-valid.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Positioned Layout Module: parsing inset with valid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#insets">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+ const single_values = [
+ // [input, serialized(optional)]
+ ["0", "0px"],
+ ["auto"],
+ ["10%"],
+ ["1rem"],
+ ["-10px"],
+ ["-20%"],
+ ["calc(2em + 3ex)"],
+ ];
+ const double_values = [
+ // [input, serialized(optional)]
+ ["auto auto", "auto"],
+ ["100px 100px", "100px"],
+ ["10% -5px"],
+ ["1rem calc(0px)"]
+ ];
+ function test_inset_longhand(longhand_property) {
+ for (let value of single_values) {
+ if (value[1] === undefined)
+ test_valid_value(longhand_property, value[0]);
+ else
+ test_valid_value(longhand_property, value[0], value[1]);
+ }
+ }
+ function test_inset_shorthand(shorthand_property) {
+ for (let value of single_values) {
+ if (value[1] === undefined)
+ test_valid_value(shorthand_property, value[0]);
+ else
+ test_valid_value(shorthand_property, value[0], value[1]);
+ }
+ for (let value of double_values) {
+ if (value[1] === undefined)
+ test_valid_value(shorthand_property, value[0]);
+ else
+ test_valid_value(shorthand_property, value[0], value[1]);
+ }
+ }
+
+ test_inset_longhand("inset-block-start");
+ test_inset_longhand("inset-block-end");
+ test_inset_longhand("inset-inline-start");
+ test_inset_longhand("inset-inline-end");
+
+ test_inset_shorthand("inset-block");
+ test_inset_shorthand("inset-inline");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/parsing/left-computed.html b/testing/web-platform/tests/css/css-position/parsing/left-computed.html
new file mode 100644
index 0000000000..9c8430ab10
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/parsing/left-computed.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Positioned Layout Module Level 3: getComputedStyle().left</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#propdef-left">
+<meta name="assert" content="left lengths are made absolute.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<style>
+ #target {
+ font-size: 40px;
+ }
+</style>
+<script>
+test_computed_value("left", "auto");
+
+test_computed_value("left", "calc(10px + 0.5em)", "30px");
+test_computed_value("left", "calc(10px - 0.5em)", "-10px");
+test_computed_value("left", "-40%");
+test_computed_value("left", "calc(50% + 60px)");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/parsing/left-invalid.html b/testing/web-platform/tests/css/css-position/parsing/left-invalid.html
new file mode 100644
index 0000000000..d4308e400d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/parsing/left-invalid.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Positioned Layout Module Level 3: parsing left with invalid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#propdef-left">
+<meta name="assert" content="left supports only the grammar 'auto | <length-percentage>'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value("left", "min-content");
+
+test_invalid_value("left", "60");
+test_invalid_value("left", "10px 20%");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/parsing/left-valid.html b/testing/web-platform/tests/css/css-position/parsing/left-valid.html
new file mode 100644
index 0000000000..2d5e364aa9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/parsing/left-valid.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Positioned Layout Module Level 3: parsing left with valid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#propdef-left">
+<meta name="assert" content="left supports the full grammar 'auto | <length-percentage>'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value("left", "auto");
+
+test_valid_value("left", "-10px");
+test_valid_value("left", "-20%");
+test_valid_value("left", "calc(2em + 3ex)");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/parsing/position-computed.html b/testing/web-platform/tests/css/css-position/parsing/position-computed.html
new file mode 100644
index 0000000000..50badd3c15
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/parsing/position-computed.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Positioned Layout Module Level 3: getComputedStyle().position</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#propdef-position">
+<meta name="assert" content="position computed value is as specified.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("position", "static");
+test_computed_value("position", "relative");
+test_computed_value("position", "absolute");
+test_computed_value("position", "sticky");
+test_computed_value("position", "fixed");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/parsing/position-invalid.html b/testing/web-platform/tests/css/css-position/parsing/position-invalid.html
new file mode 100644
index 0000000000..441cb036d1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/parsing/position-invalid.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Positioned Layout Module Level 3: parsing position with invalid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#propdef-position">
+<meta name="assert" content="position supports only the grammar 'static | relative | absolute | sticky | fixed'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value("position", "auto");
+test_invalid_value("position", "static relative");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/parsing/position-valid.html b/testing/web-platform/tests/css/css-position/parsing/position-valid.html
new file mode 100644
index 0000000000..67e08bfc8b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/parsing/position-valid.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Positioned Layout Module Level 3: parsing position with valid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#propdef-position">
+<meta name="assert" content="position supports the full grammar 'static | relative | absolute | sticky | fixed'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value("position", "static");
+test_valid_value("position", "relative");
+test_valid_value("position", "absolute");
+test_valid_value("position", "sticky");
+test_valid_value("position", "fixed");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/parsing/right-computed.html b/testing/web-platform/tests/css/css-position/parsing/right-computed.html
new file mode 100644
index 0000000000..29034c14e1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/parsing/right-computed.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Positioned Layout Module Level 3: getComputedStyle().right</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#propdef-right">
+<meta name="assert" content="right lengths are made absolute.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<style>
+ #target {
+ font-size: 40px;
+ }
+</style>
+<script>
+test_computed_value("right", "auto");
+
+test_computed_value("right", "calc(10px + 0.5em)", "30px");
+test_computed_value("right", "calc(10px - 0.5em)", "-10px");
+test_computed_value("right", "-40%");
+test_computed_value("right", "calc(50% + 60px)");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/parsing/right-invalid.html b/testing/web-platform/tests/css/css-position/parsing/right-invalid.html
new file mode 100644
index 0000000000..23be4a0ced
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/parsing/right-invalid.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Positioned Layout Module Level 3: parsing right with invalid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#propdef-right">
+<meta name="assert" content="right supports only the grammar 'auto | <length-percentage>'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value("right", "min-content");
+
+test_invalid_value("right", "60");
+test_invalid_value("right", "10px 20%");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/parsing/right-valid.html b/testing/web-platform/tests/css/css-position/parsing/right-valid.html
new file mode 100644
index 0000000000..5ddaa4d5f9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/parsing/right-valid.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Positioned Layout Module Level 3: parsing right with valid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#propdef-right">
+<meta name="assert" content="right supports the full grammar 'auto | <length-percentage>'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value("right", "auto");
+
+test_valid_value("right", "-10px");
+test_valid_value("right", "-20%");
+test_valid_value("right", "calc(2em + 3ex)");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/parsing/top-computed.html b/testing/web-platform/tests/css/css-position/parsing/top-computed.html
new file mode 100644
index 0000000000..faf89495ad
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/parsing/top-computed.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Positioned Layout Module Level 3: getComputedStyle().top</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#propdef-top">
+<meta name="assert" content="top lengths are made absolute.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<style>
+ #target {
+ font-size: 40px;
+ }
+</style>
+<script>
+test_computed_value("top", "auto");
+
+test_computed_value("top", "calc(10px + 0.5em)", "30px");
+test_computed_value("top", "calc(10px - 0.5em)", "-10px");
+test_computed_value("top", "-40%");
+test_computed_value("top", "calc(50% + 60px)");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/parsing/top-invalid.html b/testing/web-platform/tests/css/css-position/parsing/top-invalid.html
new file mode 100644
index 0000000000..47907fea9f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/parsing/top-invalid.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Positioned Layout Module Level 3: parsing top with invalid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#propdef-top">
+<meta name="assert" content="top supports only the grammar 'auto | <length-percentage>'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value("top", "min-content");
+
+test_invalid_value("top", "60");
+test_invalid_value("top", "10px 20%");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/parsing/top-valid.html b/testing/web-platform/tests/css/css-position/parsing/top-valid.html
new file mode 100644
index 0000000000..212daaf162
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/parsing/top-valid.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Positioned Layout Module Level 3: parsing top with valid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#propdef-top">
+<meta name="assert" content="top supports the full grammar 'auto | <length-percentage>'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value("top", "auto");
+
+test_valid_value("top", "-10px");
+test_valid_value("top", "-20%");
+test_valid_value("top", "calc(2em + 3ex)");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/parsing/z-index-computed.html b/testing/web-platform/tests/css/css-position/parsing/z-index-computed.html
new file mode 100644
index 0000000000..3c53f94417
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/parsing/z-index-computed.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Positioned Layout Module Level 3: getComputedStyle().zIndex</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#propdef-z-index">
+<meta name="assert" content="z-index computed value is the keyword auto or an integer.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("z-index", "auto");
+test_computed_value("z-index", "-1");
+test_computed_value("z-index", "calc(3 - 2)", "1");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/parsing/z-index-invalid.html b/testing/web-platform/tests/css/css-position/parsing/z-index-invalid.html
new file mode 100644
index 0000000000..d89720ab14
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/parsing/z-index-invalid.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Positioned Layout Module Level 3: parsing z-index with invalid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#propdef-z-index">
+<meta name="assert" content="z-index supports only the grammar 'auto | <integer>'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value("z-index", "none");
+test_invalid_value("z-index", "10px");
+test_invalid_value("z-index", "0.5");
+test_invalid_value("z-index", "auto 123");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/parsing/z-index-positioned-computed.html b/testing/web-platform/tests/css/css-position/parsing/z-index-positioned-computed.html
new file mode 100644
index 0000000000..6f19f36f89
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/parsing/z-index-positioned-computed.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Positioned Layout Module Level 3: getComputedStyle().zIndex</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#propdef-z-index">
+<meta name="assert" content="z-index computed value is the keyword auto or an integer.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<style>
+ #target {
+ position: absolute;
+ }
+</style>
+<script>
+test_computed_value("z-index", "auto");
+test_computed_value("z-index", "-1");
+test_computed_value("z-index", "calc(3 - 2)", "1");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/parsing/z-index-valid.html b/testing/web-platform/tests/css/css-position/parsing/z-index-valid.html
new file mode 100644
index 0000000000..3d1ffa0150
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/parsing/z-index-valid.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Positioned Layout Module Level 3: parsing z-index with valid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#propdef-z-index">
+<meta name="assert" content="z-index supports the full grammar 'auto | <integer>'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value("z-index", "auto");
+
+test_valid_value("z-index", "-789");
+test_valid_value("z-index", "0");
+test_valid_value("z-index", "123");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-abspos-table-dynamic.html b/testing/web-platform/tests/css/css-position/position-absolute-abspos-table-dynamic.html
new file mode 100644
index 0000000000..2b158a86f6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-abspos-table-dynamic.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<title>CSS Position: dynamic abspos table height changes</title>
+<link rel="author" title="mailto:atotic@google.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#abs-non-replaced-height">
+<meta name="assert" content="Height changes for abspos table.">
+<style>
+
+#container {
+ width: 400px;
+ height: 300px;
+ background: green;
+ position: relative;
+}
+#target {
+ display: table;
+ background: red;
+ position: absolute;
+ top: 0;
+ width: 50%;
+ height: 100px;
+}
+</style>
+<!-- There should be no red on this page -->
+<div id="container">
+ <div id="target"></div>
+</div>
+<script>
+document.body.offsetTop;
+let target = document.querySelector("#target");
+target.style.height = "auto";
+test(() => {
+ assert_equals(window.getComputedStyle(target).height, "0px");
+}, '#target height changed');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-center-001.html b/testing/web-platform/tests/css/css-position/position-absolute-center-001.html
new file mode 100644
index 0000000000..13af3f0e9f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-center-001.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/4659">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#abspos-sizing">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="The available space for a box with center alignment is double the distance between the center of the static position rectangle and the closest edge of the containing block in the relevant axis.">
+<style>
+#containing-block {
+ position: relative;
+ width: 100px;
+ height: 100px;
+ background: red;
+ display: flex;
+}
+
+#containing-block > div {
+ flex-grow: 1;
+}
+
+#inner-flex {
+ display: flex;
+ justify-content: center;
+}
+
+span {
+ display: inline-block;
+ inline-size: 50px;
+ block-size: 10px;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="containing-block" style="flex-direction: row;">
+ <div id="inner-flex" style="margin: 10px; height: 100px;">
+ <div style="position: absolute; top: 0; height: 100px; background: green;">
+ <span></span>
+ <span></span>
+ </div>
+ </div>
+ <div style="height: 100px; background: green;"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-center-002.html b/testing/web-platform/tests/css/css-position/position-absolute-center-002.html
new file mode 100644
index 0000000000..825143521a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-center-002.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/4659">
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#abspos-sizing">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="The available space for a box with center alignment is double the distance between the center of the static position rectangle and the closest edge of the containing block in the relevant axis.">
+<style>
+#containing-block {
+ position: relative;
+ width: 100px;
+ height: 100px;
+ background: red;
+ display: flex;
+}
+
+#containing-block > div {
+ flex-grow: 1;
+}
+
+#inner-flex {
+ display: flex;
+ align-items: center;
+}
+
+span {
+ display: inline-block;
+ inline-size: 50px;
+ block-size: 10px;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="containing-block" style="flex-direction: column;">
+ <div id="inner-flex" style="margin: 10px; width: 100px;">
+ <div style="position: absolute; left: 0; width: 100px; background: green; writing-mode: vertical-rl;">
+ <span></span>
+ <span></span>
+ </div>
+ </div>
+ <div style="width: 100px; background: green;"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-center-003.html b/testing/web-platform/tests/css/css-position/position-absolute-center-003.html
new file mode 100644
index 0000000000..187fae6fab
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-center-003.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/1081872">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="A positioned absolute child with center alignment should be centered based on its margin-box.">
+<style>
+.s100 {
+ width: 100px;
+ height: 100px;
+ box-sizing: border-box;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="s100" style="position: relative;">
+ <div class="s100" style="position: absolute; background: red; border: solid green; border-width: 30px 20px 20px 30px;"></div>
+ <div class="s100" style="display: flex; align-items: center; justify-content: center;">
+ <div style="position: absolute; width: 50px; height: 50px; margin-left: 10px; margin-top: 10px; background: green;"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-center-004.html b/testing/web-platform/tests/css/css-position/position-absolute-center-004.html
new file mode 100644
index 0000000000..b4922ef77e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-center-004.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/1081872">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="A positioned absolute child with center alignment should be centered based on its margin-box.">
+<style>
+.s100 {
+ width: 100px;
+ height: 100px;
+ box-sizing: border-box;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class="s100" style="position: relative;">
+ <div class="s100" style="position: absolute; background: red; border: solid green; border-width: 20px 30px 30px 20px;"></div>
+ <div class="s100" style="display: flex; align-items: center; justify-content: center;">
+ <div style="position: absolute; width: 50px; height: 50px; margin-right: 10px; margin-bottom: 10px; background: green;"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-center-006.html b/testing/web-platform/tests/css/css-position/position-absolute-center-006.html
new file mode 100644
index 0000000000..cd7fb56626
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-center-006.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/1236657">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="A table should be centered with auto margins and zero insets.">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="position: relative; width: 200px; height: 100px; margin-left: -50px;">
+ <div style="display: table; position: absolute; background: green; appearance: none; padding: 0; border: none; left: 0; right: 0; margin: auto; height: 100px;">
+ <div style="width: 100px; height: 100px;"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-center-007.html b/testing/web-platform/tests/css/css-position/position-absolute-center-007.html
new file mode 100644
index 0000000000..690f3bedf6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-center-007.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/1236657">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="A table should be centered with auto margins and zero insets.">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="position: relative; width: 100px; height: 200px; margin-top: -50px;">
+ <div style="display: table; position: absolute; background: green; appearance: none; padding: 0; border: none; top: 0; bottom: 0; margin: auto; width: 100px;">
+ <div style="width: 100px; height: 100px;"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-chrome-bug-001.html b/testing/web-platform/tests/css/css-position/position-absolute-chrome-bug-001.html
new file mode 100644
index 0000000000..3e8899a940
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-chrome-bug-001.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<html>
+<head>
+ <link rel="help" href="https://www.w3.org/TR/css-position-3/#def-cb">
+ <link rel="help" href="https://crbug.com/970171">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+<style>
+ #container {
+ position: relative;
+ border: 1px solid black;
+ }
+ .narrow {
+ width: 200px;
+ height: 300px;
+ }
+ .wide {
+ width: 300px;
+ height: 200px;
+ }
+ #target {
+ background: green;
+ position: absolute;
+ width: 50px;
+ height: 30px;
+ left: 50%;
+ top: 50%;
+ margin-left: -25px;
+ margin-top: -15px;
+ }
+</style>
+</head>
+<body>
+<div id="container" class="narrow">
+ <button id="target"></button>
+</div>
+<script>
+ test( t => {
+ let container = document.querySelector("#container");
+ let target = document.querySelector("#target");
+ document.body.offsetTop;
+ // start off narrow
+ let narrow_left = target.offsetLeft;
+ let narrow_top = target.offsetTop;
+ // make it wide
+ container.classList.toggle("narrow");
+ container.classList.toggle("wide");
+ document.body.offsetTop;
+ // make it narrow again
+ container.classList.toggle("narrow");
+ container.classList.toggle("wide");
+ document.body.offsetTop;
+ assert_equals(target.offsetLeft, narrow_left);
+ assert_equals(target.offsetTop, narrow_top);
+ }, "absolute positioned button with percentage top gets positioned");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-chrome-bug-002.html b/testing/web-platform/tests/css/css-position/position-absolute-chrome-bug-002.html
new file mode 100644
index 0000000000..5fef5205f9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-chrome-bug-002.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<link rel="author" href="mailto:atotic@google.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="help" href="https://crbug.com/970166">
+<meta name="assert" content="simplified layout calculates correct abspos position with floats">
+<style>
+
+#container {
+ position: relative;
+ background: gray;
+}
+#container::after {
+ content: '';
+ display: table;
+ clear:both;
+}
+#target {
+ position: absolute;
+ right: 0;
+ background: green;
+}
+</style>
+<div id="container">
+ <div style="float:left">floatleft</div>
+ <div id="target">
+ <div>text</div>
+ <div id="toggle">toggle</div>
+ </div>
+</div>
+<script>
+test(() => {
+ document.body.offsetTop;
+ let el = document.querySelector("#toggle");
+ el.style.display = "none";
+ document.body.offsetTop;
+ assert_equals(document.querySelector("#target").offsetTop, 0);
+}, '#target position is recalculated correctly.');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-container-dynamic-002.html b/testing/web-platform/tests/css/css-position/position-absolute-container-dynamic-002.html
new file mode 100644
index 0000000000..91d862835e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-container-dynamic-002.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<title>CSS Position Absolute: dynamic changes to containing block height</title>
+<link rel="author" href="mailto:atotic@google.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=933054">
+<meta name="assert" content="Chrome regression: abspos descendant responds to containing block size change through line items">
+<style>
+
+#container {
+ position: relative;
+}
+#intermediate {
+ overflow: hidden;
+ width:200px;
+ height:200px;
+ background:red;
+}
+#block {
+ height:200px;
+ background:green;
+}
+#target {
+ position: absolute;
+ width: 200px;
+ height: 100px;
+ background:green;
+}
+</style>
+<!-- Test for crbug.com/933054
+ Relayout optimizations cause OOF descendant not to be
+ repositioned
+-->
+<div id="container">
+ <div id="intermediate">
+ <div id="block"></div>
+ <div id="target"></div>
+ </div>
+</div>
+
+<script>
+document.body.offsetTop;
+test(() => {
+ document.getElementById("block").style.height = "100px";
+ assert_equals(document.querySelector("#target").offsetTop, 100);
+}, '#target static position responded to parent relayout');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-container-dynamic.html b/testing/web-platform/tests/css/css-position/position-absolute-container-dynamic.html
new file mode 100644
index 0000000000..711d31766d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-container-dynamic.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<title>CSS Position Absolute: dynamic changes to containing block width</title>
+<link rel="author" href="mailto:atotic@google.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#abs-non-replaced-width">
+<meta name="assert" content="abspos descendant responds to containing block size change">
+<style>
+
+#container {
+ position: relative;
+ width: 50px;
+ height: 100px;
+ background: red;
+}
+#target {
+ position: absolute;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: green;
+}
+</style>
+<div id="container">
+ <div style="display:flex;">
+ <div id="target"></div>
+ </div>
+</div>
+<script>
+document.body.offsetTop;
+test(() => {
+ document.getElementById("container").style.width = "100px";
+ assert_equals(document.querySelector("#target").offsetWidth, 100);
+}, '#target used container width when computing size');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-001.html b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-001.html
new file mode 100644
index 0000000000..592e5d22e7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-001.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<html>
+<head>
+ <title>Chrome crash with inline </title>
+ <link rel="help" href="https://www.w3.org/TR/css-position-3/#def-cb">
+ <link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=928224">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script>test(()=>{})</script>
+<style>
+ a {
+ position: relative;
+ }
+ a:before {
+ content: "foo";
+ position: absolute;
+ background: green;
+ }
+</style>
+</head>
+<body>
+ <div>
+ <li>
+ <a href="dummy">success if does not crash</a>
+ </li>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-002.html b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-002.html
new file mode 100644
index 0000000000..e7ed1daba5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-002.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>CSS Position Absolute: Chrome crash</title>
+<link rel="author" href="mailto:atotic@google.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=938224">
+<meta name="assert" content="absolute position in LI container does not crash">
+<style>
+ #container {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ }
+ #abs {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ }
+</style>
+<li id="container">
+ <ul>
+ <li>
+ <div id="abs">abs</div>
+ </li>
+ </ul>
+</li>
+<script>
+test(() => {
+}, 'test passes if it does not crash');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-003.html b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-003.html
new file mode 100644
index 0000000000..c443e836e5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-003.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<title>CSS Position Absolute: Chrome crash</title>
+<link rel="author" href="mailto:atotic@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=935805">
+<meta name="assert" content="Nested abs/fixed/flex do not crash">
+<style>
+ #flex {
+ display: flex;
+ }
+ .abs {
+ position: absolute;
+ }
+ #fixed {
+ position: fixed;
+ }
+</style>
+<div class="abs">
+ <div id="flex">
+ <div class="abs">
+ <div id="fixed"></div>
+ </div>
+ </div>
+</div>
+<script>
+test(() => {
+}, 'test passes if it does not crash');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-004.html b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-004.html
new file mode 100644
index 0000000000..cc6de63e00
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-004.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<title>CSS Position Absolute: Chrome crash</title>
+<link rel="author" href="mailto:atotic@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=946986">
+<meta name="assert" content="Nested abs/fixed/flex do not crash">
+<style>
+ body { overflow: scroll;}
+ .container {
+ position: relative;
+ contain: paint;
+ }
+ .flex {
+ display: flex;
+ }
+ .fixed {
+ position: fixed;
+ }
+ .abs {
+ position: absolute;
+ }
+</style>
+<!-- LayoutNG currently does not support display:flex.
+ Propagation of descendants across flex boundaries is error prone -->
+<div id="one" class="container" style="">
+ <div class="flex">
+ <div class="abs">
+ <div class="flex">
+ <div id="fixed1" class="fixed">
+ <div id="fixed2" class="fixed"></div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+<script>
+test(() => {
+}, 'test passes if it does not crash');
+</script>
+
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-005.html b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-005.html
new file mode 100644
index 0000000000..e1b469d46c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-005.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<title>CSS Position Absolute: Chrome crash</title>
+<link rel="author" href="mailto:atotic@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=949222">
+<meta name="assert" content="Dynamic containing block change does not crash">
+<style>
+ .container {
+ position: relative;
+ }
+ .abs {
+ position: absolute;
+ width: 50px;
+ height: 50px;
+ background: green;
+ }
+ @keyframes slidein {
+ from { transform: scaleX(0); }
+ to { transform: scaleX(1); }
+ }
+ .animate {
+ animation: slidein 0.1s linear;
+ }
+ .boundary {
+ overflow: hidden;
+ width: 100px;
+ height: 100px;
+ }
+</style>
+<!-- LayoutNG currently does not support display:flex.
+ Propagation of descendants across flex boundaries is error prone -->
+<div id="one" class="container" style="">
+ <div class="boundary">
+ <div class="boundary">
+ <div class="boundary">
+ <div id="intermediate">
+ <div class="abs"></div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+<script>
+let t = async_test("Test passes if it does not crash");
+let el = document.querySelector("#intermediate");
+el.addEventListener("animationend", _ => {
+ t.step(function() {
+ document.body.offsetTop;
+ assert_true(true, "test did not crash");
+ t.done();
+ })
+});
+el.classList.add("animate");
+</script>
+
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-006.html b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-006.html
new file mode 100644
index 0000000000..94b2469b0e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-006.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<title>CSS Position Absolute: Chrome crash</title>
+<link rel="author" href="mailto:atotic@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=952644">
+<meta name="assert" content="abspos iframe with zoom gets laid out">
+<style>
+ .boundary {
+ overflow: hidden;
+ width: 100px;
+ height: 100px;
+ }
+ .abs {
+ position: absolute;
+ background: green;
+ zoom: 2;
+ }
+</style>
+<!-- Containing block with zoom causes zoomed abspos iframe
+not to be laid out-->
+<div class="boundary">
+ <div id="parent">
+ </div>
+</div>
+<script>
+ document.body.offsetTop;
+ let abs = document.createElement("iframe");
+ abs.classList.add("abs");
+ document.querySelector("#parent").appendChild(abs);
+ test(() => {
+ }, 'test passes if it does not crash');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-007.html b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-007.html
new file mode 100644
index 0000000000..9c24210c25
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-007.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<title>CSS Position Absolute: Chrome crash</title>
+<link rel="author" href="mailto:atotic@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="help" href="https://crbug.com/945696">
+<meta name="assert" content="Absolute descendant inside multiple nested split inlines does not crash.">
+<style>
+ body {
+ overflow: hidden;
+ margin: 0px;
+ font-size: 24px;
+ }
+ #block-container {
+ position: relative;
+ }
+ #css-container {
+ position: relative;
+ font-size: 12px;
+ }
+ #anonymous-parent {
+ background-color: #FFFF7F;
+ }
+ #anonymous-split {
+ background-color: #FFD997;
+ }
+ #css-container {
+ background-color: #BEE0FF;
+ }
+ #abs {
+ background-color: rgba(0, 255, 0, 0.5);
+ position:absolute;
+ top: 0px;
+ left: 0px;
+ }
+ #fullabs {
+ background-color: rgba(0, 255, 0, 0.5);
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+ }
+</style>
+<div id="block-container">
+ <span id="anonymous-parent">
+ parent <br>start
+ <span id="anonymous-split">
+ split start
+ <div id="splitter" >splitter</div>
+ split middle
+ <span id="css-container">
+ css-container start
+ <div id="abs">ABS</div>
+ <div id="fullabs">FULLABS</div>
+ css container end
+ </span>
+ split end
+ </span>
+ parent end
+ </span>
+</div>
+<script>
+document.body.offsetTop;
+ test(() => {
+ }, 'test passes if it does not crash');
+</script>
+
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-008.html b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-008.html
new file mode 100644
index 0000000000..3d1c90930c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-008.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="author" href="mailto:atotic@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="help" href="https://crbug.com/967977">
+<meta name="assert" content="zero width inline abspos container with borders does not cause a crash">
+<style>
+</style>
+<span style="border-bottom:1px solid; filter:blur(2px);">
+ <div style="position:absolute"></div>
+</span>
+<script>
+document.body.offsetTop;
+ test(() => {
+ }, 'test passes if it does not crash');
+</script>
+
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-009.html b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-009.html
new file mode 100644
index 0000000000..23df49cfaa
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-009.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="help" href="https://crbug.com/974760">
+<meta name="assert" content="fixed children inside inline container do not crash">
+<style>
+#container {
+ position: relative;
+ overflow: auto;
+ width: 200px;
+ height: 200px;
+}
+#inline-fixed-container {
+ filter:url("");
+}
+#fixed-container {
+ position: fixed;
+}
+#target {
+ position: fixed;
+}
+</style>
+<div id="container">
+ <span id="inline-fixed-container">
+ <div id="fixed-container">
+ <div id="target"></div>
+ </div>
+ </span>
+</div>
+<script>
+test(() => {
+ document.body.offsetTop;
+ document.querySelector("#target").appendChild(
+ document.createTextNode("foo"));
+ document.body.offsetTop;
+}, 'this test passes if it does not crash');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-010.html b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-010.html
new file mode 100644
index 0000000000..91b439a342
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-010.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="help" href="https://crbug.com/976397">
+<div style="width: 100px; position: relative;">
+ <div style="float: left; width: 110px; height: 50px;">
+ <div style="display: flex;">
+ <div style="position: absolute; width: 50px; height: 50px;"></div>
+ </div>
+ </div>
+</div>
+<script>
+test(() => { }, 'test passes if it does not crash');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-011.html b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-011.html
new file mode 100644
index 0000000000..fd3d63e0cf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-011.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="help" href="https://crbug.com/977930">
+<style>
+body {
+ margin: 20px;
+}
+.container {
+ position: relative;
+}
+#inline-container-absolute {
+ position: relative;
+ background: rgba(0,255,0,0.3);
+}
+#inline-container-fixed {
+ filter: blur(2px);
+ background: rgba(0,255,0,0.3);
+}
+.outofflow {
+ position: absolute;
+ width: 20px;
+ height: 20px;
+ background: green;
+ top:0;
+ left:0;
+}
+.splitter {
+ width: 100px;
+ height: 20px;
+ background: gray;
+}
+</style>
+<div class="container">
+ <div>
+ absolute
+ <span id="inline-container-absolute" >
+ container
+ <div class="outofflow" style="position:absolute">A</div>
+ container
+ <div class="splitter">splitter</div>
+ container
+ </span>
+ </div>
+</div>
+<div class="container">
+ <div>
+ fixed
+ <span id="inline-container-fixed" >
+ container
+ <div class="outofflow" style="position:fixed">F</div>
+ container
+ <div class="splitter">splitter</div>
+ container
+ </span>
+ </div>
+</div>
+<script>
+test(_ => {
+ document.body.offsetTop;
+ document.querySelector("#inline-container-absolute").style.position = 'static';
+}, 'test passes if changing abspos inline container to static does not crash');
+test(_ => {
+ document.body.offsetTop;
+ document.querySelector("#inline-container-fixed").style.filter = 'none';
+}, 'test passes if changing fixed inline container to static does not crash');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-012.html b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-012.html
new file mode 100644
index 0000000000..f012ff5726
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-012.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<link rel="help" href="https://crbug.com/996085">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>test(()=>{})</script>
+<style>
+ #container {
+ width: 600px;
+ position: relative;
+ }
+ #target {
+ position: absolute;
+ left: 0px;
+ right: 33554000px;
+ width: 10px;
+ margin-left: 33554432px;
+ margin-right: 33554432px;
+ height: 20px;
+ }
+</style>
+<body>
+ <div id="container">
+ <div id="target"></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-013.html b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-013.html
new file mode 100644
index 0000000000..8f0daf4bfe
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-crash-chrome-013.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="help" href="https://crbug.com/1021676">
+<div id="tfoot" style="display: table-footer-group; transform: scale(2);">
+ <div id="oof" style="position: absolute;">text</div>
+</div>
+<script>
+test(() => {
+ document.body.offsetTop;
+
+ // Make the ICB the containing-block.
+ document.getElementById('tfoot').style.transform = '';
+ document.body.offsetTop;
+
+ document.getElementById('oof').innerText = '';
+ document.body.offsetTop;
+}, 'test passes if it does not crash');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-dynamic-auto-overflow.html b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-auto-overflow.html
new file mode 100644
index 0000000000..142af95a34
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-auto-overflow.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1225548">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="position: fixed; background: red; max-height: 150px; overflow-y: auto;">
+ <div id="target" style="width: 100px; background: green;"></div>
+</div>
+<script>
+document.body.offsetTop;
+const target = document.getElementById('target');
+target.style.height = '200px';
+document.body.offsetTop;
+target.style.height = '100px';
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-dynamic-containing-block.html b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-containing-block.html
new file mode 100644
index 0000000000..3968f68584
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-containing-block.html
@@ -0,0 +1,140 @@
+<!DOCTYPE html>
+<title>CSS Position: position:absolute dynamic containing block</title>
+<link rel="author" title="mailto:atotic@google.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="help" href="https://drafts.csswg.org/css-position-3/#def-cb">
+<meta name="assert" content="Tests changes in containing block for out-of-flow positioned descendants.">
+<style>
+
+#outer {
+ width: 400px;
+ height: 300px;
+ outline: black solid 1px;
+}
+#intermediate {
+ width: 300px;
+ height: 200px;
+ outline: gray solid 1px;
+}
+#target {
+ background: green;
+}
+.abs {
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+}
+.fixed {
+ position: fixed;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+}
+.abs-container {
+ position: relative;
+}
+.fixed-container {
+ will-change: transform;
+}
+div {
+ padding: 5px;
+}
+</style>
+<!-- This tests potential caching of out-of-flow positioned descendants. -->
+<div id="outer">
+ <div>
+ <div id="intermediate">
+ <div>
+ <div id="target">TTT</div>
+ <div id="noLayout1"></div>
+ </div>
+ <div id="noLayout2"></div>
+ </div>
+ </div>
+</div>
+<script>
+ let outer = document.querySelector("#outer");
+ let intermediate = document.querySelector("#intermediate");
+ let target = document.querySelector("#target");
+ let padding = 5;
+
+ function cleanup() {
+ outer.className = "";
+ intermediate.className = "";
+ target.className = "";
+ document.body.offsetTop;
+ }
+
+ test( t => {
+ t.add_cleanup(cleanup);
+ outer.classList.add("abs-container");
+ target.classList.add("abs");
+ assert_equals(target.offsetHeight, outer.offsetHeight);
+ intermediate.classList.add("abs-container");
+ assert_equals(target.offsetHeight, intermediate.offsetHeight);
+ }, "abs containing block moves from outer to intermediate" );
+ test( t => {
+ t.add_cleanup(cleanup);
+ target.classList.add("abs");
+ intermediate.classList.add("abs-container");
+ assert_equals(target.offsetHeight, intermediate.offsetHeight);
+ outer.classList.add("abs-container");
+ assert_equals(target.offsetHeight, intermediate.offsetHeight);
+ intermediate.classList.remove("abs-container");
+ assert_equals(target.offsetHeight, outer.offsetHeight);
+ }, "abs containing block moves from intermediate to outer" );
+ test( t => {
+ t.add_cleanup(cleanup);
+ target.classList.add("abs");
+ outer.classList.add("abs-container");
+ assert_equals(target.offsetHeight, outer.offsetHeight);
+ target.classList.remove("abs");
+ assert_equals(target.offsetWidth, intermediate.offsetWidth - 4 * padding);
+ }, "target is no longer absolute");
+ test( t => {
+ t.add_cleanup(cleanup);
+ outer.classList.add("abs-container");
+ assert_equals(target.offsetWidth, intermediate.offsetWidth - 4 * padding);
+ target.classList.add("abs");
+ assert_equals(target.offsetHeight, outer.offsetHeight);
+ }, "target becomes absolute");
+
+ // Repeat same tests with fixed
+ test( t => {
+ t.add_cleanup(cleanup);
+ outer.classList.add("fixed-container");
+ target.classList.add("fixed");
+ assert_equals(target.offsetHeight, outer.offsetHeight);
+ intermediate.classList.add("fixed-container");
+ assert_equals(target.offsetHeight, intermediate.offsetHeight);
+ }, "fixed containing block moves from outer to intermediate" );
+ test( t => {
+ t.add_cleanup(cleanup);
+ target.classList.add("fixed");
+ intermediate.classList.add("fixed-container");
+ assert_equals(target.offsetHeight, intermediate.offsetHeight);
+ outer.classList.add("fixed-container");
+ assert_equals(target.offsetHeight, intermediate.offsetHeight);
+ intermediate.classList.remove("fixed-container");
+ assert_equals(target.offsetHeight, outer.offsetHeight);
+ }, "fixed containing block moves from intermediate to outer" );
+ test( t => {
+ t.add_cleanup(cleanup);
+ target.classList.add("fixed");
+ outer.classList.add("fixed-container");
+ assert_equals(target.offsetHeight, outer.offsetHeight);
+ target.classList.remove("fixed");
+ assert_equals(target.offsetWidth, intermediate.offsetWidth - 4 * padding);
+ }, "target is no longer fixed");
+ test( t => {
+ t.add_cleanup(cleanup);
+ outer.classList.add("fixed-container");
+ assert_equals(target.offsetWidth, intermediate.offsetWidth - 4 * padding);
+ target.classList.add("fixed");
+ assert_equals(target.offsetHeight, outer.offsetHeight);
+ }, "target becomes fixed");
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-dynamic-list-marker.html b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-list-marker.html
new file mode 100644
index 0000000000..2e233e882e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-list-marker.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<link rel="help" href="https://www.w3.org/TR/css-position-3/" />
+<meta name="assert" content="This test checks that a dynamic change in constraints calculates the static position correctly."/>
+<script src="/common/reftest-wait.js"></script>
+<style>
+ul {
+ margin: 0;
+ padding: 0;
+ width: 100px;
+ height: 100px;
+ background: red;
+}
+
+#target {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ background: green;
+}
+::marker { color: white; }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<ul>
+ <li style="position: relative;">
+ <div style="height: 50px;"></div>
+ <div id=target></div>
+ </li>
+</ul>
+<script>
+document.body.offsetTop;
+const target = document.getElementById('target');
+target.style.top = '0px';
+document.body.offsetTop;
+takeScreenshot();
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-dynamic-overflow-001.html b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-overflow-001.html
new file mode 100644
index 0000000000..c07919b90f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-overflow-001.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<link rel="help" href="https://www.w3.org/TR/css-position-3/" />
+<meta name="assert" content="This test checks that scrollbars dissappear when an absolute positioned element no longer triggers overflow."/>
+<script src="/common/reftest-wait.js"></script>
+<style>
+#container {
+ position: relative;
+ background: red;
+
+ box-sizing: border-box;
+ width: 100px;
+ max-height: 100px;
+ overflow: auto;
+}
+
+#target {
+ position: absolute;
+ width: 100px;
+ height: 200px;
+}
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id="container">
+ <div id="target"></div>
+ <div style="height: 100px; background: green;"></div>
+</div>
+<script>
+document.body.offsetTop;
+const target = document.getElementById('target');
+target.style.width = '50px';
+target.style.height = '50px';
+document.body.offsetTop;
+takeScreenshot();
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-dynamic-overflow-002.html b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-overflow-002.html
new file mode 100644
index 0000000000..0c3d36275b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-overflow-002.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<link rel="help" href="https://www.w3.org/TR/css-position-3/" />
+<meta name="assert" content="This test checks that scrollbars dissappear when an absolute positioned element no longer triggers overflow."/>
+<script src="/common/reftest-wait.js"></script>
+<style>
+#scrollable {
+ width: 100px;
+ overflow: auto;
+}
+
+#container {
+ width: 100px;
+ height: 50px;
+ position: relative;
+ background: green;
+}
+
+#target {
+ position: absolute;
+ width: 50px;
+ height: 20px;
+ left: 200px;
+}
+
+#green {
+ width: 100px;
+ height: 50px;
+ background: green;
+}
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id="scrollable">
+ <div id="container">
+ <div id="target"></div>
+ </div>
+</div>
+<div id="green"></div>
+<script>
+document.body.offsetTop;
+const target = document.getElementById('target');
+target.style.left = 'initial';
+document.body.offsetTop;
+takeScreenshot();
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-dynamic-relayout-001.html b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-relayout-001.html
new file mode 100644
index 0000000000..1bde15551e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-relayout-001.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<link rel="help" href="https://www.w3.org/TR/css-position-3/" />
+<meta name="assert" content="This test checks that a dynamic change in constraints does not crash the renderer."/>
+<script src="/common/reftest-wait.js"></script>
+<p>Test passes if there is a filled green square.</p>
+<div style="display: flex; width: 100px; height: 100px; overflow: hidden; position: relative;"> <!-- relayout boundary -->
+ <div style="position: relative;">
+ <div style="display: flex; position: relative; width: 100px; height: 50px; overflow: hidden;"> <!-- relayout boundary -->
+ <div id="target1" style="position: absolute; width: 10px; height: 50px; background: green;"></div>
+ </div>
+ <div id="target2" style="position: absolute; width: 10px; height: 50px; background: green;"></div>
+ </div>
+</div>
+<script>
+document.body.offsetTop;
+target2.style.width = '100px';
+target1.style.width = '100px';
+document.body.offsetTop;
+takeScreenshot();
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-dynamic-relayout-002.html b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-relayout-002.html
new file mode 100644
index 0000000000..4dc2dc0f80
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-relayout-002.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<link rel="help" href="https://www.w3.org/TR/css-position-3/" />
+<meta name="assert" content="This test checks that a dynamic change padding-box location, but no change in available-size positions correctly an absolute child correctly."/>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="target" style="position: relative; background: red; margin: 25px; width: 50px; height: 50px;">
+ <div style="position: absolute; top: 0; left: 0; width: 50px; height: 50px; background: green;"></div>
+</div>
+<script>
+ document.body.offsetTop;
+ const target = document.getElementById('target');
+ target.style.border = '25px solid green';
+ target.style.margin = '0';
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-dynamic-relayout-003.html b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-relayout-003.html
new file mode 100644
index 0000000000..8b7556b1f3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-relayout-003.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<link rel="help" href="https://www.w3.org/TR/css-position-3/" />
+<meta name="assert" content="This test checks that a dynamic OOF-positioned change doesn't cause children to paint differently." />
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="display: flex; position: relative; width: 100px; height: 100px;">
+ <div style="order: 2; margin-left: -100px; width: 100px; background: green;"></div>
+ <div style="order: 1; width: 100px; background: red;"></div>
+ <div id="target" style="position: absolute;"></div>
+</div>
+<script>
+ document.body.offsetTop;
+ document.getElementById('target').style.top = '10px';
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-dynamic-relayout-004.html b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-relayout-004.html
new file mode 100644
index 0000000000..b94a8cdbff
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-relayout-004.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1493929">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="width:100px; height:100px; background:red;">
+ <div style="float:left; width:100px;">
+ <div id="target1" style="height:10px; background:green;"></div>
+ </div>
+ <div>
+ <div style="float:left; position:relative; width:100px; height:50px; background:green;">
+ <div id="target2" style="position:absolute; width:10px; height:10px;"></div>
+ </div>
+ </div>
+</div>
+<script>
+document.body.offsetTop;
+target2.style.width = '20px';
+document.body.offsetTop;
+target1.style.height = '50px';
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-flex.html b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-flex.html
new file mode 100644
index 0000000000..37e6fed351
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-flex.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<link rel="help" href="https://www.w3.org/TR/css-position-3/" />
+<meta name="assert" content="This test checks that a dynamic change in constraints calculates the static position correctly for flex children."/>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="display: flex; position: relative; width: 100px; height: 100px; background: red; align-items: flex-end;">
+ <div id="target" style="position: absolute; width: 100px; height: 100px; background: green; bottom: 100px;"></div>
+</div>
+<script>
+ document.body.offsetTop;
+ document.getElementById('target').style.bottom = 'initial';
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-floats-001.html b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-floats-001.html
new file mode 100644
index 0000000000..a63df41089
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-floats-001.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<link rel="help" href="https://www.w3.org/TR/css-position-3/" />
+<meta name="assert" content="This test checks that a dynamic change in constraints calculates the static position correctly."/>
+<script src="/common/reftest-wait.js"></script>
+<style>
+#container {
+ position: relative;
+ background: red;
+
+ box-sizing: border-box;
+ border: solid green 10px;
+ width: 100px;
+ height: 100px;
+}
+
+#float {
+ float: left;
+ background: green;
+
+ width: 40px;
+ height: 80px;
+}
+
+#target {
+ position: absolute;
+ background: green;
+ display: inline;
+
+ width: 40px;
+ height: 80px;
+ top: -10px;
+ left: -10px;
+}
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id="container">
+ <div id="float"></div>
+ <div id="target"></div>
+</div>
+<script>
+document.body.offsetTop;
+const target = document.getElementById('target');
+target.style.top = 'initial';
+target.style.left = 'initial';
+document.body.offsetTop;
+takeScreenshot();
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-floats-002.html b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-floats-002.html
new file mode 100644
index 0000000000..49e3807224
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-floats-002.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<link rel="help" href="https://www.w3.org/TR/css-position-3/" />
+<meta name="assert" content="This test checks that a dynamic change in constraints calculates the static position correctly."/>
+<script src="/common/reftest-wait.js"></script>
+<style>
+#container {
+ position: relative;
+ background: red;
+
+ box-sizing: border-box;
+ border: solid green 10px;
+ width: 100px;
+ height: 100px;
+}
+
+#float {
+ float: left;
+ background: green;
+
+ width: 40px;
+ height: 80px;
+}
+
+#block {
+ background: green;
+ height: 40px;
+}
+
+#target {
+ position: absolute;
+ background: green;
+ display: inline;
+
+ width: 40px;
+ height: 40px;
+ top: -10px;
+ left: -10px;
+}
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id="container">
+ <div id="float"></div>
+ <div id="block"></div>
+ <div id="target"></div>
+</div>
+<script>
+document.body.offsetTop;
+const target = document.getElementById('target');
+target.style.top = 'initial';
+target.style.left = 'initial';
+document.body.offsetTop;
+takeScreenshot();
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-floats-003.html b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-floats-003.html
new file mode 100644
index 0000000000..fa7cc695c3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-floats-003.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<link rel="help" href="https://www.w3.org/TR/css-position-3/" />
+<meta name="assert" content="This test checks that a dynamic change in constraints calculates the static position correctly."/>
+<script src="/common/reftest-wait.js"></script>
+<style>
+#container {
+ position: relative;
+ background: red;
+
+ box-sizing: border-box;
+ border: solid green 10px;
+ width: 100px;
+ height: 100px;
+}
+
+#float {
+ float: left;
+ background: green;
+
+ width: 40px;
+ height: 80px;
+}
+
+#block {
+ background: green;
+ height: 40px;
+}
+
+#target {
+ position: absolute;
+ background: green;
+ display: inline;
+
+ width: 40px;
+ height: 40px;
+ top: -10px;
+ left: -10px;
+}
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id="container">
+ <div id="block">
+ <div id="float"></div>
+ </div>
+ <div id="target"></div>
+</div>
+<script>
+document.body.offsetTop;
+const target = document.getElementById('target');
+target.style.top = 'initial';
+target.style.left = 'initial';
+document.body.offsetTop;
+takeScreenshot();
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-floats-004.html b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-floats-004.html
new file mode 100644
index 0000000000..3ccd1462fd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-floats-004.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<link rel="help" href="https://www.w3.org/TR/css-position-3/" />
+<meta name="assert" content="This test checks that a dynamic change in constraints calculates the static position correctly."/>
+<script src="/common/reftest-wait.js"></script>
+<style>
+#container {
+ position: relative;
+ background: red;
+ direction: rtl;
+
+ box-sizing: border-box;
+ border: solid green 10px;
+ width: 100px;
+ height: 100px;
+}
+
+#float {
+ float: right;
+ background: green;
+
+ width: 40px;
+ height: 80px;
+}
+
+#target {
+ position: absolute;
+ background: green;
+ display: inline;
+
+ width: 40px;
+ height: 80px;
+ top: -10px;
+ left: -10px;
+}
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id="container">
+ <div id="float"></div>
+ <div id="target"></div>
+</div>
+<script>
+document.body.offsetTop;
+const target = document.getElementById('target');
+target.style.top = 'initial';
+target.style.left = 'initial';
+document.body.offsetTop;
+takeScreenshot();
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-inline.html b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-inline.html
new file mode 100644
index 0000000000..c0f9ac0718
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-inline.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<link rel="help" href="https://www.w3.org/TR/css-position-3/" />
+<meta name="assert" content="This test checks that the static-position of an absolute positioned element changes, if the display value changes from inline to block." />
+<p>Test passes if there is a filled green square.</p>
+<div style="position: relative; line-height: 0;">
+ <div style="width: 100px; height: 50px; display: inline-block; background: green;"></div>
+ <div id="target" style="width: 100px; height: 50px; display: inline; position: absolute; background: green;"></div>
+</div>
+<script>
+document.body.offsetTop;
+document.getElementById('target').style.display = 'block';
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-margin-001.html b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-margin-001.html
new file mode 100644
index 0000000000..78b0ced9df
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-margin-001.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<link rel="help" href="https://www.w3.org/TR/css-position-3/" />
+<meta name="assert" content="This test checks that a dynamic change in constraints calculates the static position correctly."/>
+<script src="/common/reftest-wait.js"></script>
+<style>
+#container {
+ position: relative;
+ background: red;
+
+ box-sizing: border-box;
+ border: solid green 10px;
+ width: 100px;
+ height: 100px;
+}
+
+#block {
+ background: green;
+ height: 40px;
+ margin-bottom: 20px;
+}
+
+#target {
+ position: absolute;
+ background: green;
+
+ width: 80px;
+ height: 20px;
+ top: -10px;
+ left: -10px;
+}
+
+#cover {
+ position: absolute;
+ background: green;
+
+ width: 80px;
+ height: 20px;
+ top: 40px;
+ left: 0px;
+}
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id="container">
+ <div id="block"></div>
+ <div id="target"></div>
+ <div id="cover"></div>
+</div>
+<script>
+document.body.offsetTop;
+const target = document.getElementById('target');
+target.style.top = 'initial';
+target.style.left = 'initial';
+document.body.offsetTop;
+takeScreenshot();
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-margin-002.html b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-margin-002.html
new file mode 100644
index 0000000000..98b18efcf9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-margin-002.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<link rel="help" href="https://www.w3.org/TR/css-position-3/" />
+<meta name="assert" content="This test checks that a dynamic change in constraints calculates the static position correctly."/>
+<script src="/common/reftest-wait.js"></script>
+<style>
+#container {
+ position: relative;
+ background: red;
+
+ box-sizing: border-box;
+ border: solid green 10px;
+ width: 100px;
+ height: 100px;
+}
+
+#block {
+ background: green;
+ height: 40px;
+ margin-bottom: 20px;
+}
+
+#target {
+ position: absolute;
+ background: green;
+
+ width: 80px;
+ height: 20px;
+ top: -10px;
+ left: -10px;
+}
+
+#cover {
+ position: absolute;
+ background: green;
+
+ width: 80px;
+ height: 20px;
+ top: 40px;
+ left: 0px;
+}
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id="container">
+ <div>
+ <div id="block"></div>
+ </div>
+ <div id="target"></div>
+ <div id="cover"></div>
+</div>
+<script>
+document.body.offsetTop;
+const target = document.getElementById('target');
+target.style.top = 'initial';
+target.style.left = 'initial';
+document.body.offsetTop;
+takeScreenshot();
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-table-cell.html b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-table-cell.html
new file mode 100644
index 0000000000..3a28b205f2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position-table-cell.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<link rel="help" href="https://www.w3.org/TR/css-position-3/" />
+<meta name="assert" content="This test checks that a dynamic change in constraints calculates the static position correctly for table-cells."/>
+<style>
+#table-cell {
+ position: relative;
+ display: table-cell;
+ vertical-align: middle;
+
+ width: 100px;
+ height: 100px;
+ background: red;
+}
+
+#target {
+ position: absolute;
+ translate: 0 -50px;
+
+ width: 100px;
+ height: 100px;
+ background: green;
+}
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="table-cell">
+ <div id="target" style="top: 0;"></div>
+</div>
+<script>
+document.body.offsetTop;
+document.getElementById('target').style.top = 'auto';
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position.html b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position.html
new file mode 100644
index 0000000000..35d5f65055
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-dynamic-static-position.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<link rel="help" href="https://www.w3.org/TR/css-position-3/" />
+<meta name="assert" content="This test checks that a dynamic change in constraints calculates the static position correctly."/>
+<script src="/common/reftest-wait.js"></script>
+<style>
+#container {
+ position: relative;
+ background: red;
+
+ box-sizing: border-box;
+ border: solid green 10px;
+ width: 100px;
+ height: 100px;
+}
+
+#target {
+ position: absolute;
+ background: green;
+
+ width: 80px;
+ height: 80px;
+ top: -10px;
+ left: -10px;
+}
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id="container">
+ <div id="target"></div>
+</div>
+<script>
+document.body.offsetTop;
+const target = document.getElementById('target');
+target.style.top = 'initial';
+target.style.left = 'initial';
+document.body.offsetTop;
+takeScreenshot();
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-fieldset.html b/testing/web-platform/tests/css/css-position/position-absolute-fieldset.html
new file mode 100644
index 0000000000..b212e627ae
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-fieldset.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/CSS22/visudet.html#abs-non-replaced-width">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="position:relative; width:100px; height:100px; background:red;">
+ <fieldset style="position:absolute; left:0; top:0; right:0; bottom:0; margin:0; border:none; background:green;"></fieldset>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-fit-content.html b/testing/web-platform/tests/css/css-position/position-absolute-fit-content.html
new file mode 100644
index 0000000000..a84cc04381
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-fit-content.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3973">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1135207">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1232439">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="position: relative; width: 100px; height: 200px;">
+ <div style="position: absolute; top: 0; bottom: 0; left: 0; right: 0; max-height: fit-content; background: green;">
+ <div style="height: 100px;"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-iframe-print-001.sub.html b/testing/web-platform/tests/css/css-position/position-absolute-iframe-print-001.sub.html
new file mode 100644
index 0000000000..853ad9e9fc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-iframe-print-001.sub.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<title>an abs-pos iframe in the first page but its hypothetical position is in the second page</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#valdef-position-absolute">
+<link rel="match" href="position-absolute-iframe-print-ref.html">
+<!-- Allow some text antialias pixels to be different. -->
+<meta name="fuzzy" content="0-255;0-20">
+<style>
+ body {
+ margin: 0
+ }
+ iframe {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ top: 0;
+ left: 0;
+ }
+</style>
+<div style="height:200vh;"></div>
+<iframe frameborder=0 scrolling=no
+ src="//{{hosts[alt][www]}}:{{ports[http][0]}}{{location[path]}}/../resources/position-absolute-iframe-child.html"></iframe>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-iframe-print-002.sub.html b/testing/web-platform/tests/css/css-position/position-absolute-iframe-print-002.sub.html
new file mode 100644
index 0000000000..b47616d1c1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-iframe-print-002.sub.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<title>an abs-pos iframe in the first page but its hypothetical position is in the second page</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#valdef-position-absolute">
+<link rel="match" href="position-absolute-iframe-print-ref.html">
+<!-- Allow some text antialias pixels to be different. -->
+<meta name="fuzzy" content="0-255;0-20">
+<style>
+ body {
+ margin: 0;
+ }
+ iframe {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ top: 0;
+ left: 0;
+ }
+</style>
+<div style="height:200vh;"></div>
+<iframe frameborder=0 scrolling=no
+ src="//{{hosts[alt][www]}}:{{ports[http][0]}}{{location[path]}}/../resources/position-absolute-iframe-child-002.sub.html"></iframe>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-iframe-print-ref.html b/testing/web-platform/tests/css/css-position/position-absolute-iframe-print-ref.html
new file mode 100644
index 0000000000..d89bb93cf9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-iframe-print-ref.html
@@ -0,0 +1,6 @@
+<!doctype html>
+<style>
+ body { margin: 0 }
+</style>
+<div style="position:absolute; top:0; left:0;">This text should be visible in the first page</div>
+<div style="height:200vh;"></div>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-in-inline-001.html b/testing/web-platform/tests/css/css-position/position-absolute-in-inline-001.html
new file mode 100644
index 0000000000..204260ee67
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-in-inline-001.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<html>
+<head>
+ <title>Absolute inside inline container location should be correct</title>
+ <link rel="author" href="mailto:atotic@chromium.org">
+ <link rel="help" href="https://www.w3.org/TR/css-position-3/#def-cb">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+</head>
+<!-- There should be a green square below -->
+<body style="margin:0">
+ <span id="container" style="position:relative;">
+ <div style="width:100px; height:100px; background:red;"></div>
+ <div id="target" style="position:absolute; left:0; top:0; width:100px; height:100px; background:green;"></div>
+ </span>
+ <script>
+ test(_ => {
+ let bounds = document.querySelector("#target").getBoundingClientRect();
+ let container_bounds = document.querySelector("#container").getBoundingClientRect();
+ assert_equals(bounds.x, container_bounds.x);
+ assert_equals(bounds.y, container_bounds.y);
+ }, "absolute inside inline container location should be correct.");
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-in-inline-002.html b/testing/web-platform/tests/css/css-position/position-absolute-in-inline-002.html
new file mode 100644
index 0000000000..8ec3838fc7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-in-inline-002.html
@@ -0,0 +1,51 @@
+<!doctype html>
+
+<link rel="author" href="mailto:atotic@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#def-cb">
+<meta name="assert" content="split inline containing blocks are handled correctly.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ body {
+ margin: 0;
+ }
+ #container-span {
+ position: relative;
+ outline: solid 1px gray;
+ }
+ #split {
+ width: 10px;
+ height: 10px;
+ }
+ #target {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0,255,0,0.3);
+ }
+</style>
+<!-- There should be a green rectangle spanning two "container span" lines below -->
+<span id="outer-span">
+outer span
+ <span id="container-span">
+ container span start
+ <div id="split"></div>
+ <div id="target"></div>
+ container span end
+ </span>
+outer span end
+</span>
+<script>
+ test(_ => {
+ let abs_bounds = document.querySelector("#target").getClientRects();
+ let container_bounds = document.querySelector("#container-span").getClientRects();
+ assert_equals(abs_bounds.length, 1);
+ assert_equals(container_bounds.length, 3);
+ assert_equals(abs_bounds[0].left, container_bounds[0].left, "left matches container");
+ assert_equals(abs_bounds[0].top, container_bounds[0].top, "top matches container");
+ assert_equals(abs_bounds[0].right, container_bounds[2].right, "right matches container");
+ assert_equals(abs_bounds[0].bottom, container_bounds[2].bottom, "bottom matches container");
+ }, "absolute inside inline container location should be correct.");
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-in-inline-003.html b/testing/web-platform/tests/css/css-position/position-absolute-in-inline-003.html
new file mode 100644
index 0000000000..25fb2bb6da
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-in-inline-003.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>
+ Out-of-flow positioned element with inline containing block.
+</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#def-cb">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ #container {
+ font: 20px/1 Ahem;
+ color: white;
+ }
+ .abs {
+ position: absolute;
+ background-color: green;
+ height: 100px;
+ width: 100px;
+ top: -60px;
+ }
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="container" style="height: 100px; width: 100px; background-color: red;">
+ <div style="height: 60px;"></div>
+ B
+ <span style="position: relative;">
+ <div></div>
+ AA
+ <div class="abs"></div>
+ </span>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-in-inline-004.html b/testing/web-platform/tests/css/css-position/position-absolute-in-inline-004.html
new file mode 100644
index 0000000000..d5b2530643
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-in-inline-004.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<title>
+ Out-of-flow positioned element with inline containing block.
+</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#abspos-breaking">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ #container {
+ height: 100px;
+ width: 100px;
+ font: 20px/1 Ahem;
+ color: white;
+ background-color: red;
+ }
+ .abs {
+ position: absolute;
+ background-color: green;
+ height: 100px;
+ width: 50px;
+ top: -50px;
+ }
+</style>
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="container">
+ <div style="height: 50px;"></div>
+ BBBB
+ <span style="position: relative;">
+ <div class="abs" style="left: -30px;"></div>
+ AA A AA AAAA
+ <div class="abs" style="left: -80px;"></div>
+ </span>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-in-inline-crash.html b/testing/web-platform/tests/css/css-position/position-absolute-in-inline-crash.html
new file mode 100644
index 0000000000..e7b2ef49c7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-in-inline-crash.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<html>
+<head>
+ <title>Should not crash with split inline abspos container, and flex ancestor</title>
+ <link rel="help" href="https://www.w3.org/TR/css-position-3/#def-cb">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script>test(()=>{})</script>
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+</head>
+<!-- There should be a green square below -->
+<body style="font-family: Ahem;font-size: 20px;">
+<div id="container">
+ <span id="split" style="position:relative;color:green">
+ AAA
+ <div style="display:flex">
+ <a>
+ <span id="target" style="position:absolute;color:green;top:20px">XXX</span></a>
+ </div>
+ ZZZ
+ </span>
+</div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-large-negative-inset-ref.html b/testing/web-platform/tests/css/css-position/position-absolute-large-negative-inset-ref.html
new file mode 100644
index 0000000000..e04afce6eb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-large-negative-inset-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<style>
+ div {
+ background:green;
+ width:50px;
+ height:50px;
+ }
+</style>
+<div></div>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-large-negative-inset.html b/testing/web-platform/tests/css/css-position/position-absolute-large-negative-inset.html
new file mode 100644
index 0000000000..ed17ea91d5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-large-negative-inset.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+ <title>CSS Position: Large negative box inset properties</title>
+ <link rel="help" href="https://drafts.csswg.org/css-position-3/#insets">
+ <link rel="match" href="position-absolute-large-negative-inset-ref.html">
+ <meta name="assert" content="This test verifies a box with very large negative insets within an element with will-change: transform does not affect the rendering of the element."/>
+
+ <style>
+ html {
+ will-change: transform;
+ }
+
+ span {
+ position: absolute;
+ left: -99999999999px;
+ }
+
+ div {
+ background:green;
+ width:50px;
+ height:50px;
+ }
+ </style>
+ <div></div>
+ <span>negative inset text</span>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-margin-auto-001.html b/testing/web-platform/tests/css/css-position/position-absolute-margin-auto-001.html
new file mode 100644
index 0000000000..9ec1c3f011
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-margin-auto-001.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>Tests the calculation of negative auto margins of absolutely positioned element</title>
+<link rel="help" href="https://drafts.csswg.org/css-position/#abspos-margins">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1492323">
+<link rel="author" href="mailto:xiaochengh@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.cb {
+ position: relative;
+ width: 400px;
+ height: 400px;
+ outline: 1px dashed black;
+}
+
+.target {
+ writing-mode: vertical-lr;
+ position: absolute;
+ background: green;
+ width: calc(100% - 100px);
+ height: calc(100% - 100px);
+ inset: 100px;
+ margin: auto;
+}
+</style>
+
+<body onload="checkLayout('.target')">
+ <div class="cb">
+ <div class="target"
+ data-expected-margin-top="-50" data-expected-margin-bottom="-50"
+ data-expected-margin-left="0" data-expected-margin-right="-100"></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-multicol-001.html b/testing/web-platform/tests/css/css-position/position-absolute-multicol-001.html
new file mode 100644
index 0000000000..08132188ce
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-multicol-001.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>CSS Positioned Layout Test: Absolute positioned element inside multicol</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-position/#valdef-position-absolute">
+<link rel="match" href="/css/reference/pass_if_pass_below.html">
+<meta name=assert content="Checks that an absolute positioned element inside multicol is rendered, when a previous absolute positioned element has been rendered already.">
+<p>Test passes if there is the word "PASS" below.</p>
+<div style="position: relative;">
+ <div style="position: absolute;">
+ </div>
+ <div style="column-count: 2;">
+ <div style="position: absolute;">PASS</div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-padding-percentage.html b/testing/web-platform/tests/css/css-position/position-absolute-padding-percentage.html
new file mode 100644
index 0000000000..2d43639f19
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-padding-percentage.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<title>CSS Position Absolute: css-position-3</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="help" href="https://drafts.csswg.org/css-position-3/#absolute-positioning-containing-block">
+<link rel="help" href="https://drafts.csswg.org/css-box-4/#padding-physical">
+<meta name="assert" content="abspos resolves padding %-ge sizes correctly.">
+<style>
+#outer-horizontal-padding {
+ position: relative;
+ padding: 10px;
+ width: 30px;
+ height: 80px;
+ background: green;
+}
+#inner-horizontal-padding {
+ position: absolute;
+ left: 50px;
+ height: 100px;
+ top: 0px;
+ padding-left: 50%;
+ padding-right: 50%;
+ background: green;
+}
+#outer-vertical-padding {
+ position: relative;
+ padding: 10px;
+ width: 30px;
+ height: 80px;
+ background: green;
+}
+#inner-vertical-padding {
+ position: absolute;
+ left: 50px;
+ width: 50px;
+ top: 0px;
+ padding-top: 100%;
+ padding-bottom: 100%;
+ background: green;
+}
+</style>
+<div id="outer-horizontal-padding">
+ <div id="inner-horizontal-padding"></div>
+</div>
+<div id="outer-vertical-padding">
+ <div id="inner-vertical-padding"></div>
+</div>
+<script>
+document.body.offsetTop;
+test(() => {
+ let target = document.querySelector("#inner-horizontal-padding");
+ assert_equals(target.offsetWidth, 50);
+}, 'absolute positioned element should resolve padding left+right against container padding-box width' );
+
+test(() => {
+ let target = document.querySelector("#inner-vertical-padding");
+ assert_equals(target.offsetHeight, 100);
+}, 'absolute positioned element should resolve padding top+bottom against container padding-box width' );
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-percentage-height.html b/testing/web-platform/tests/css/css-position/position-absolute-percentage-height.html
new file mode 100644
index 0000000000..8b2e5c0f72
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-percentage-height.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<title>CSS Position Absolute: css-position-3</title>
+<link rel="author" href="mailto:atotic@google.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/">
+<meta name="assert" content="abspos resolves %-ge sizes correctly.">
+<style>
+
+#container {
+ position: relative;
+}
+
+#image-wrapper {
+ display: flex;
+ position: absolute;
+ height: 100%;
+ background: green;
+}
+
+#content-wrapper {
+ margin-left: 30%;
+}
+
+#target {
+ display: block;
+ min-height: 100%;
+ opacity: 0.5;
+}
+</style>
+<!-- IMG height is 100% of image wrapper height.
+ IMG width is 100% of image wrapper width.
+ IMG width equals IMG height -->
+<div id="container">
+ <div id="image-wrapper">
+ <!-- 1x1 green pixel -->
+ <img id="target" src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M/wHwAEBgIApD5fRAAAAABJRU5ErkJggg==">
+ </div>
+ <div id="content-wrapper">
+ Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
+ </div>
+</div>
+<script>
+document.body.offsetTop;
+test(() => {
+ let target = document.querySelector("#target");
+ assert_equals(target.offsetWidth, target.offsetHeight);
+ assert_equals(target.offsetWidth, document.querySelector("#image-wrapper").offsetWidth);
+ assert_equals(target.offsetHeight, document.querySelector("#content-wrapper").offsetHeight);
+}, '#target height matches containing block height, and target parent width matches #target width' );
+
+test(() => {
+ document.body.style.marginLeft = "300px";
+ let target = document.querySelector("#target");
+ assert_equals(target.offsetWidth, target.offsetHeight);
+ assert_equals(target.offsetWidth, document.querySelector("#image-wrapper").offsetWidth);
+ assert_equals(target.offsetHeight, document.querySelector("#content-wrapper").offsetHeight);
+}, '#target height matches containing block height, and target parent width matches #target width after resize');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-replaced-intrinsic-size.tentative.html b/testing/web-platform/tests/css/css-position/position-absolute-replaced-intrinsic-size.tentative.html
new file mode 100644
index 0000000000..4e2ecb63ab
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-replaced-intrinsic-size.tentative.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<link rel="help" href="https://www.w3.org/TR/CSS22/visudet.html#abs-replaced-width">
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<p>Test passes if there is a filled green square.</p>
+<div style="position: relative;">
+ <img style="position: absolute; height: 100px; min-width: max-content; background: green;" src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 50 50'><rect width='100%' height='100%' fill='green'/></svg>">
+</div>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-replaced-minmax.html b/testing/web-platform/tests/css/css-position/position-absolute-replaced-minmax.html
new file mode 100644
index 0000000000..5a76277092
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-replaced-minmax.html
@@ -0,0 +1,355 @@
+<!DOCTYPE html>
+<title>CSS Position: absolute position, replaced elements, and minmax</title>
+<link rel="author" title="mailto:atotic@google.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="help" href="https://www.w3.org/TR/CSS2/visudet.html#min-max-widths">
+<meta name="assert" content="Min/max width and height interact properly with abspos replaced elements">
+<style>
+.container {
+ position: relative;
+ display: inline-block;
+ width: 400px;
+ height: 200px;
+ border: 1px solid black;
+}
+.target {
+ position: absolute;
+ padding: 10px;
+ bottom: 0;
+ right: 0;
+ border-width: 3px 7px 9px 11px;
+ border-color: yellow;
+ border-style: solid;
+ margin: 1px 3px 7px 9px;
+}
+</style>
+<!-- test all combinations of minmax from section 10.4 table at
+ https://www.w3.org/TR/CSS2/visudet.html#min-max-widths -->
+
+<!-- IFRAME tests -->
+<!-- iframe: intrinsic size is 300x150, no aspect ratio -->
+<div class="container">
+ <iframe class="target"
+ data-expected-width="338" data-expected-height="182" data-offset-y="11" data-offset-x="59"
+ >
+ </iframe>
+</div>
+<!-- spec 1: w > max-width -->
+<div class="container">
+ <iframe class="target" style="max-width:100px"
+ data-expected-width="138" data-expected-height="182" data-offset-y="11" data-offset-x="259"
+ >
+ </iframe>
+</div>
+<!-- spec 2: w < min-width -->
+<div class="container">
+ <iframe class="target" style="min-width: 350px"
+ data-expected-width="388" data-expected-height="182" data-offset-y="11" data-offset-x="9"
+ >
+ </iframe>
+</div>
+<!-- spec 3: h > max-height -->
+<div class="container">
+ <iframe class="target" style="max-height: 150px"
+ data-expected-width="338" data-expected-height="182" data-offset-y="11" data-offset-x="59"
+ >
+ </iframe>
+</div>
+<!-- spec 4: h < min-height -->
+<div class="container">
+ <iframe class="target" style="min-height: 165px"
+ data-expected-width="338" data-expected-height="197" data-offset-y="-4" data-offset-x="59"
+ >
+ </iframe>
+</div>
+<!-- spec 5: (w > max-width) and (h > max-height), where (max-width/w ≤ max-height/h) -->
+<div class="container">
+ <iframe class="target" style="max-width: 240px; max-height: 135px"
+ data-expected-width="278" data-expected-height="167" data-offset-y="26" data-offset-x="119"
+ >
+ </iframe>
+</div>
+<!-- spec 6: (w > max-width) and (h > max-height), where (max-width/w > max-height/h) -->
+<div class="container">
+ <iframe class="target" style="max-width: 270px; max-height: 120px"
+ data-expected-width="308" data-expected-height="152" data-offset-y="41" data-offset-x="89"
+ >
+ </iframe>
+</div>
+<!-- spec 7: (w < min-width) and (h < min-height), where (min-width/w ≤ min-height/h) -->
+<div class="container">
+ <iframe class="target" style="min-width: 360px; min-height: 165px"
+ data-expected-width="398" data-expected-height="197" data-offset-y="-4" data-offset-x="-1"
+ >
+ </iframe>
+</div>
+<!-- spec 8: (w < min-width) and (h < min-height), where (min-width/w > min-height/h) -->
+<div class="container">
+ <iframe class="target" style="min-width: 330px; min-height: 180px"
+ data-expected-width="368" data-expected-height="212" data-offset-y="-19" data-offset-x="29"
+ >
+ </iframe>
+</div>
+<!-- spec 9: (w < min-width) and (h > max-height) -->
+<div class="container">
+ <iframe class="target" style="min-width: 330px; max-height: 135px"
+ data-expected-width="368" data-expected-height="167" data-offset-y="26" data-offset-x="29"
+ >
+ </iframe>
+</div>
+<!-- spec 10: (w > max-width) and (h < min-height) -->
+<div class="container">
+ <iframe class="target" style="max-width: 240px; min-height: 165px"
+ data-expected-width="278" data-expected-height="197" data-offset-y="-4" data-offset-x="119"
+ >
+ </iframe>
+</div>
+
+<!-- IMG png tests -->
+<!-- image dimensions: 200x150. images has intrinic size and aspect ratio -->
+<div class="container">
+ <img class="target png"
+ data-expected-width="238" data-expected-height="182" data-offset-y="11" data-offset-x="159"
+ >
+</div>
+<!-- spec 1: w > max-width -->
+<div class="container">
+ <img class="target png" style="max-width: 180px"
+ data-expected-width="218" data-expected-height="167" data-offset-y="26" data-offset-x="179"
+ >
+</div>
+<!-- spec 2: w < min-width -->
+<div class="container">
+ <img class="target png" style="min-width: 220px"
+ data-expected-width="258" data-expected-height="197" data-offset-y="-4" data-offset-x="139"
+ >
+</div>
+
+<!-- spec 3: h > max-height -->
+<div class="container">
+ <img class="target png" style="max-height: 135px"
+ data-expected-width="218" data-expected-height="167" data-offset-y="26" data-offset-x="179"
+ >
+</div>
+<!-- spec 4: h < min-height -->
+<div class="container">
+ <img class="target png" style="min-height: 165px"
+ data-expected-width="258" data-expected-height="197" data-offset-y="-4" data-offset-x="139"
+ >
+</div>
+<!-- spec 5: (w > max-width) and (h > max-height), where (max-width/w ≤ max-height/h) -->
+<div class="container">
+ <img class="target png" style="max-width: 160px; max-height: 135px"
+ data-expected-width="198" data-expected-height="152" data-offset-y="41" data-offset-x="199"
+ >
+</div>
+<!-- spec 6: (w > max-width) and (h > max-height), where (max-width/w > max-height/h) -->
+<div class="container">
+ <img class="target png" style="max-width: 180px; max-height: 120px"
+ data-expected-width="198" data-expected-height="152" data-offset-y="41" data-offset-x="199"
+ >
+</div>
+<!-- spec 7: (w < min-width) and (h < min-height), where (min-width/w ≤ min-height/h) -->
+<div class="container">
+ <img class="target png" style="min-width: 240px;min-height: 165px"
+ data-expected-width="278" data-expected-height="212" data-offset-y="-19" data-offset-x="119"
+ >
+</div>
+<!-- spec 8: (w < min-width) and (h < min-height), where (min-width/w > min-height/h) -->
+<div class="container">
+ <img class="target png" style="min-width: 220px;min-height: 180px"
+ data-expected-width="278" data-expected-height="212" data-offset-y="-19" data-offset-x="119"
+ >
+</div>
+<!-- spec 9: (w < min-width) and (h > max-height) -->
+<div class="container">
+ <img class="target png" style="min-width: 220px; max-height: 130px"
+ data-expected-width="258" data-expected-height="162" data-offset-y="31" data-offset-x="139"
+ >
+</div>
+<!-- spec 10: (w > max-width) and (h < min-height) -->
+<div class="container">
+ <img class="target png" style="max-width: 180px; min-height: 165px"
+ data-expected-width="218" data-expected-height="197" data-offset-y="-4" data-offset-x="179"
+ >
+</div>
+<!-- IMG SVG tests -->
+<!-- image dimensions: 200x150. images has no intrinic size and no aspect ratio -->
+<div class="container">
+ <img class="target svg"
+ data-expected-width="338" data-expected-height="182" data-offset-y="11" data-offset-x="59"
+ >
+</div>
+<!-- spec 1: w > max-width -->
+<div class="container">
+ <img class="target svg" style="max-width: 180px"
+ data-expected-width="218" data-expected-height="182" data-offset-y="11" data-offset-x="179"
+ >
+</div>
+<!-- spec 2: w < min-width -->
+<div class="container">
+ <img class="target svg" style="min-width: 220px"
+ data-expected-width="338" data-expected-height="182" data-offset-y="11" data-offset-x="59"
+ >
+</div>
+
+<!-- spec 3: h > max-height -->
+<div class="container">
+ <img class="target svg" style="max-height: 135px"
+ data-expected-width="338" data-expected-height="167" data-offset-y="26" data-offset-x="59"
+ >
+</div>
+<!-- spec 4: h < min-height -->
+<div class="container">
+ <img class="target svg" style="min-height: 165px"
+ data-expected-width="338" data-expected-height="197" data-offset-y="-4" data-offset-x="59"
+ >
+</div>
+<!-- spec 5: (w > max-width) and (h > max-height), where (max-width/w ≤ max-height/h) -->
+<div class="container">
+ <img class="target svg" style="max-width: 160px; max-height: 135px"
+ data-expected-width="198" data-expected-height="167" data-offset-y="26" data-offset-x="199"
+ >
+</div>
+<!-- spec 6: (w > max-width) and (h > max-height), where (max-width/w > max-height/h) -->
+<div class="container">
+ <img class="target svg" style="max-width: 180px; max-height: 120px"
+ data-expected-width="218" data-expected-height="152" data-offset-y="41" data-offset-x="179"
+ >
+</div>
+<!-- spec 7: (w < min-width) and (h < min-height), where (min-width/w ≤ min-height/h) -->
+<div class="container">
+ <img class="target svg" style="min-width: 240px;min-height: 165px"
+ data-expected-width="338" data-expected-height="197" data-offset-y="-4" data-offset-x="59"
+ >
+</div>
+<!-- spec 8: (w < min-width) and (h < min-height), where (min-width/w > min-height/h) -->
+<div class="container">
+ <img class="target svg" style="min-width: 220px;min-height: 180px"
+ data-expected-width="338" data-expected-height="212" data-offset-y="-19" data-offset-x="59"
+ >
+</div>
+<!-- spec 9: (w < min-width) and (h > max-height) -->
+<div class="container">
+ <img class="target svg" style="min-width: 220px; max-height: 130px"
+ data-expected-width="338" data-expected-height="162" data-offset-y="31" data-offset-x="59"
+ >
+</div>
+<!-- spec 10: (w > max-width) and (h < min-height) -->
+<div class="container">
+ <img class="target svg" style="max-width: 180px; min-height: 165px"
+ data-expected-width="218" data-expected-height="197" data-offset-y="-4" data-offset-x="179"
+ >
+</div>
+<!-- SVG tests -->
+<!-- SVGs are special: any combination of intrinsic_size and aspect_ratio
+ can happen. -->
+<!-- Just viewbox. Has intrinsic aspect ratio, but no width/height -->
+<div class="container">
+ <img class="target" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' %3E%3Crect width='100%' height='100%' style='fill:rgb(0,255,0);'/%3E%3C/svg%3E" style=""
+ data-expected-width="338" data-expected-height="182" data-offset-y="11" data-offset-x="59"
+ >
+</div>
+<!-- Just viewbox. Has aspect_ratio, but no intrinsic size
+ inline_width defaults to container width -->
+<div class="container">
+ <img class="target" src="data:image/svg+xml,%3Csvg viewBox='0 0 100 10' xmlns='http://www.w3.org/2000/svg' %3E%3Crect width='100%' height='100%' style='fill:rgb(0,255,0);'/%3E%3C/svg%3E"
+ data-expected-width="388" data-expected-height="67" data-offset-y="126" data-offset-x="9"
+ >
+</div>
+<!-- Just viewbox. Has aspect_ratio, but no intrinsic size
+ inline_width is constrained by left/right, height computed proportionally -->
+<div class="container">
+ <img class="target" style="left:100px;right:100px;" src="data:image/svg+xml,%3Csvg viewBox='0 0 100 10' xmlns='http://www.w3.org/2000/svg' %3E%3Crect width='100%' height='100%' style='fill:rgb(0,255,0);'/%3E%3C/svg%3E"
+ data-expected-width="188" data-expected-height="47" data-offset-y="146" data-offset-x="109"
+ >
+</div>
+<!-- Same as previous test, but with max-width:fit-content. crbug.com/1010798
+ -->
+<div class="container">
+ <img class="target" style="left:100px;right:100px;max-width:fit-content" src="data:image/svg+xml,%3Csvg viewBox='0 0 100 10' xmlns='http://www.w3.org/2000/svg' %3E%3Crect width='100%' height='100%' style='fill:rgb(0,255,0);'/%3E%3C/svg%3E"
+ data-expected-width="188" data-expected-height="47" data-offset-y="146" data-offset-x="109"
+ >
+</div>
+<!-- Viewbox + svg width. Has aspect_ratio and width. Height is scaled -->
+<div class="container">
+ <img class="target" src="data:image/svg+xml,%3Csvg viewBox='0 0 100 10' width='100px' xmlns='http://www.w3.org/2000/svg' %3E%3Crect width='100%' height='100%' style='fill:rgb(0,255,0);'/%3E%3C/svg%3E"
+ data-expected-width="138" data-expected-height="42" data-offset-y="151" data-offset-x="259"
+ >
+</div>
+<!-- Viewbox + svg height. Has aspect_ratio and height. Width is scaled -->
+<div class="container">
+ <img class="target" src="data:image/svg+xml,%3Csvg viewBox='0 0 100 10' height='20px' xmlns='http://www.w3.org/2000/svg' %3E%3Crect width='100%' height='100%' style='fill:rgb(0,255,0);'/%3E%3C/svg%3E"
+ data-expected-width="238" data-expected-height="52" data-offset-y="141" data-offset-x="159"
+ >
+</div>
+<!-- Viewbox + css height. Has aspect_ratio and height. Width is scaled -->
+<div class="container">
+ <img class="target" style="height:20px" src="data:image/svg+xml,%3Csvg viewBox='0 0 100 10' xmlns='http://www.w3.org/2000/svg' %3E%3Crect width='100%' height='100%' style='fill:rgb(0,255,0);'/%3E%3C/svg%3E"
+ data-expected-width="238" data-expected-height="52" data-offset-y="141" data-offset-x="159"
+ >
+</div>
+<!-- Viewbox + css width. Has aspect_ratio and width. Height is scaled -->
+<div class="container">
+ <img class="target" style="width:238px" src="data:image/svg+xml,%3Csvg viewBox='0 0 100 10' xmlns='http://www.w3.org/2000/svg' %3E%3Crect width='100%' height='100%' style='fill:rgb(0,255,0);'/%3E%3C/svg%3E"
+ data-expected-width="276" data-expected-height="56" data-offset-y="137" data-offset-x="121"
+ >
+</div>
+<script>
+ // initialize png images with 200x150 green png
+ let pngSrc="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACWAQMAAAChElVaAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABlBMVEUAgAD///8UPy9PAAAAAWJLR0QB/wIt3gAAAAd0SU1FB+MBDwkdA1Cz/EMAAAAbSURBVEjH7cGBAAAAAMOg+VPf4ARVAQAAAM8ADzwAAeM8wQsAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTktMDEtMTVUMTc6Mjk6MDMtMDg6MDCYDy9IAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE5LTAxLTE1VDE3OjI5OjAzLTA4OjAw6VKX9AAAAABJRU5ErkJggg=="
+;
+ let images = document.querySelectorAll("img.png");
+ for (let i=0; i<images.length; ++i) {
+ images[i].src = pngSrc;
+ }
+
+ // SVG with no intrinsic width/height
+ let svgSrc="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' %3E%3Crect width='100%' height='100%' style='fill:rgb(0,255,0);'/%3E%3C/svg%3E ";
+ images = document.querySelectorAll("img.svg");
+ for (let i=0; i<images.length; ++i) {
+ images[i].src = svgSrc;
+ }
+
+ function makeTest(el) {
+ return function() {
+ if (!el.getAttribute("data-expected-width")) {
+ // This code is used to generate reference data for the tests.
+ let text = `data-expected-width="${el.offsetWidth}" data-expected-height="${el.offsetHeight}" data-offset-y="${el.offsetTop}" data-offset-x="${el.offsetLeft}"`;
+ el.parentElement.innerText = text;
+ return;
+ }
+ assert_equals(el.offsetWidth + "", el.getAttribute("data-expected-width"), "incorrect offsetWidth");
+ assert_equals(el.offsetHeight + "", el.getAttribute("data-expected-height"), "incorrect offsetHeight");
+ assert_equals(el.offsetTop + "", el.getAttribute("data-offset-y"), "incorrect offsetTop");
+ assert_equals(el.offsetLeft + "", el.getAttribute("data-offset-x"), "incorrect offsetLeft");
+ }
+ };
+
+
+ let testNameIndex = 1;
+ function getTestName(el) {
+ let svg = el.classList.contains("svg") ? " svg" : "";
+ return "minmax replaced " + el.nodeName + svg + " " + testNameIndex++;
+ };
+
+ function testAfterImageLoads(img, test) {
+ let asyncTest = async_test(getTestName(img));
+ img.addEventListener("load", _ => {
+ asyncTest.step(test);
+ asyncTest.done();
+ });
+ };
+
+ let testElements = document.querySelectorAll(".target");
+
+ for (let i=0; i<testElements.length; ++i) {
+ let myTest = makeTest(testElements[i]);
+ if (testElements[i].nodeName == "IMG" && !testElements[i].complete) {
+ testAfterImageLoads(testElements[i], myTest);
+ } else {
+ test(myTest, getTestName(testElements[i]));
+ }
+ }
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-replaced-no-intrinsic-size.tentative.html b/testing/web-platform/tests/css/css-position/position-absolute-replaced-no-intrinsic-size.tentative.html
new file mode 100644
index 0000000000..5dfa0c75d6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-replaced-no-intrinsic-size.tentative.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<link rel="help" href="https://www.w3.org/TR/CSS22/visudet.html#abs-replaced-width">
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<p>Test passes if there is a filled green square.</p>
+<div style="position: relative; width: 200; height: 200px; margin-top: -50px;">
+ <img style="position: absolute; top: 0; bottom: 0; height: max-content; margin: auto; width: 100px; background: green;" src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 50 50'><rect width='100%' height='100%' fill='green'/></svg>">
+</div>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-replaced-with-display-table.html b/testing/web-platform/tests/css/css-position/position-absolute-replaced-with-display-table.html
new file mode 100644
index 0000000000..9a966b9315
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-replaced-with-display-table.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1138851">
+<p>Test passes if there is a filled green square.</p>
+<div style="position: relative;">
+ <canvas width="200" style="background: green; width: 100px; height: 100px; position: absolute; display: table;"></canvas>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-root-element-flex.html b/testing/web-platform/tests/css/css-position/position-absolute-root-element-flex.html
new file mode 100644
index 0000000000..ed1e4903d8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-root-element-flex.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="UTF-8">
+ <title>CSS Position: Box inset properties & position:absolute flex container as the root element</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"/>
+ <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+ <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+ <link rel="help" href="https://drafts.csswg.org/css-position-3/#insets">
+ <link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1584890">
+ <link rel="match" href="position-absolute-root-element-ref.html">
+ <meta name="assert" content="This test verifies the box inset properties on a position:absolute flex container root element.">
+
+ <style>
+ html {
+ display: flex;
+ position: absolute;
+ left: 10px;
+ right: 20px;
+ top: 30px;
+ bottom: 40px;
+ border: 5px dashed black;
+ box-sizing: border-box;
+ }
+ </style>
+
+ The black border should encompass the whole viewport,
+ with a bit of space on each side.
+ <br><br>
+ It shouldn't just shrinkwrap this text's height.
+</html>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-root-element-grid.html b/testing/web-platform/tests/css/css-position/position-absolute-root-element-grid.html
new file mode 100644
index 0000000000..1a813b3a23
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-root-element-grid.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="UTF-8">
+ <title>CSS Position: Box inset properties & position:absolute grid container as the root element</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"/>
+ <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+ <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+ <link rel="help" href="https://drafts.csswg.org/css-position-3/#insets">
+ <link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1584890">
+ <link rel="match" href="position-absolute-root-element-ref.html">
+ <meta name="assert" content="This test verifies the box inset properties on a position:absolute grid container root element.">
+
+ <style>
+ html {
+ display: grid;
+ position: absolute;
+ left: 10px;
+ right: 20px;
+ top: 30px;
+ bottom: 40px;
+ border: 5px dashed black;
+ box-sizing: border-box;
+ }
+ </style>
+
+ The black border should encompass the whole viewport,
+ with a bit of space on each side.
+ <br><br>
+ It shouldn't just shrinkwrap this text's height.
+</html>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-root-element-ref.html b/testing/web-platform/tests/css/css-position/position-absolute-root-element-ref.html
new file mode 100644
index 0000000000..d4649f2d5a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-root-element-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="UTF-8">
+ <title>CSS Position Reference: Box inset properties & position:absolute root element</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"/>
+ <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+ <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+
+ <style>
+ html {
+ display: block;
+ position: absolute;
+ left: 10px;
+ right: 20px;
+ top: 30px;
+ bottom: 40px;
+ border: 5px dashed black;
+ box-sizing: border-box;
+ }
+ </style>
+
+ The black border should encompass the whole viewport,
+ with a bit of space on each side.
+ <br><br>
+ It shouldn't just shrinkwrap this text's height.
+</html>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-button-ref.html b/testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-button-ref.html
new file mode 100644
index 0000000000..296b87ba61
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-button-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<style>
+.cb {
+ position: relative;
+ border: 3px solid black;
+ height: 100px;
+ width: 150px;
+ display: inline-block;
+ vertical-align: top;
+ margin: 5px;
+}
+.abs {
+ margin: 0;
+ position: absolute;
+ box-sizing: border-box;
+ top: 3px;
+ left: 3px;
+ outline: 2px solid lime;
+ width: calc(100% - 6px);
+ height: calc(100% - 6px);
+}
+</style>
+<div class="cb"><button class="abs">button</button></div>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-button.html b/testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-button.html
new file mode 100644
index 0000000000..fbcdbec51b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-button.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/6789">
+<link rel="match" href="position-absolute-semi-replaced-stretch-button-ref.html">
+<title>Semi-replaced elements should stretch with an auto main size, and explicit insets in that direction.</title>
+<style>
+.cb {
+ position: relative;
+ border: 3px solid black;
+ height: 100px;
+ width: 150px;
+ display: inline-block;
+ vertical-align: top;
+ margin: 5px;
+}
+.abs {
+ margin: 0;
+ position: absolute;
+ box-sizing: border-box;
+ top: 3px;
+ right: 3px;
+ bottom: 3px;
+ left: 3px;
+ outline: 2px solid lime;
+ width: auto;
+ height: auto;
+}
+</style>
+<div class="cb"><button class="abs">button</button></div>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-input-ref.html b/testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-input-ref.html
new file mode 100644
index 0000000000..554173c632
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-input-ref.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<style>
+.cb {
+ position: relative;
+ border: 3px solid black;
+ height: 100px;
+ width: 150px;
+ display: inline-block;
+ vertical-align: top;
+ margin: 5px;
+}
+.wide {
+ width: 350px;
+}
+.abs {
+ margin: 0;
+ position: absolute;
+ box-sizing: border-box;
+ top: 3px;
+ left: 3px;
+ outline: 2px solid lime;
+ width: calc(100% - 6px);
+ height: calc(100% - 6px);
+}
+</style>
+<div class="cb"><input type="button" class="abs" value="input-btn"></div>
+<div class="cb"><input type="submit" class="abs"></div>
+<div class="cb"><input type="reset" class="abs"></div>
+<div class="cb"><input type="color" class="abs"></div>
+<div class="cb wide"><input type="text" class="abs" value="text"></div>
+<div class="cb wide"><input type="password" class="abs" value="pass"></div>
+<div class="cb wide"><input type="date" class="abs" value="text"></div>
+<div class="cb wide"><input type="file" class="abs"></div>
+<div class="cb wide"><input type="range" class="abs"></div>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-input.html b/testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-input.html
new file mode 100644
index 0000000000..6080f63c10
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-input.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/6789">
+<link rel="match" href="position-absolute-semi-replaced-stretch-input-ref.html">
+<title>Semi-replaced elements should stretch with an auto main size, and explicit insets in that direction.</title>
+<style>
+.cb {
+ position: relative;
+ border: 3px solid black;
+ height: 100px;
+ width: 150px;
+ display: inline-block;
+ vertical-align: top;
+ margin: 5px;
+}
+.wide {
+ /* Some of the form controls are wider than others
+ and need a wider CB in order to see if they're
+ stretching or shrinking. */
+ width: 350px;
+}
+.abs {
+ margin: 0;
+ position: absolute;
+ box-sizing: border-box;
+ top: 3px;
+ right: 3px;
+ bottom: 3px;
+ left: 3px;
+ outline: 2px solid lime;
+ width: auto;
+ height: auto;
+}
+</style>
+<div class="cb"><input type="button" class="abs" value="input-btn"></div>
+<div class="cb"><input type="submit" class="abs"></div>
+<div class="cb"><input type="reset" class="abs"></div>
+<div class="cb"><input type="color" class="abs"></div>
+<div class="cb wide"><input type="text" class="abs" value="text"></div>
+<div class="cb wide"><input type="password" class="abs" value="pass"></div>
+<div class="cb wide"><input type="date" class="abs" value="text"></div>
+<div class="cb wide"><input type="file" class="abs"></div>
+<div class="cb wide"><input type="range" class="abs"></div>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-other-ref.html b/testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-other-ref.html
new file mode 100644
index 0000000000..e334bc0f63
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-other-ref.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<style>
+.cb {
+ position: relative;
+ border: 3px solid black;
+ height: 100px;
+ width: 150px;
+ display: inline-block;
+ vertical-align: top;
+ margin: 5px;
+}
+.wide {
+ width: 350px;
+}
+.abs {
+ margin: 0;
+ position: absolute;
+ box-sizing: border-box;
+ top: 3px;
+ left: 3px;
+ outline: 2px solid lime;
+ width: calc(100% - 6px);
+ height: calc(100% - 6px);
+}
+</style>
+<div class="cb"><select class="abs"><option>select</option></select></div>
+<div class="cb"><output class="abs">output</output></div>
+<div class="cb"><label class="abs">label</output></div>
+<div class="cb"><fieldset class="abs">fieldset</fieldset></div>
+<div class="cb wide"><textarea class="abs">textarea</textarea></div>
+<div class="cb wide"><progress value="0.4" class="abs"></div>
+<div class="cb wide"><meter value="0.4" class="abs"></div>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-other.html b/testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-other.html
new file mode 100644
index 0000000000..21fc2c84e3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-semi-replaced-stretch-other.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/6789">
+<link rel="match" href="position-absolute-semi-replaced-stretch-other-ref.html">
+<title>Semi-replaced elements should stretch with an auto main size, and explicit insets in that direction.</title>
+<style>
+.cb {
+ position: relative;
+ border: 3px solid black;
+ height: 100px;
+ width: 150px;
+ display: inline-block;
+ vertical-align: top;
+ margin: 5px;
+}
+.wide {
+ /* Some of the form controls are wider than others
+ and need a wider CB in order to see if they're
+ stretching or shrinking. */
+ width: 350px;
+}
+.abs {
+ margin: 0;
+ position: absolute;
+ box-sizing: border-box;
+ top: 3px;
+ right: 3px;
+ bottom: 3px;
+ left: 3px;
+ outline: 2px solid lime;
+ width: auto;
+ height: auto;
+}
+</style>
+<div class="cb"><select class="abs"><option>select</option></select></div>
+<div class="cb"><output class="abs">output</output></div>
+<div class="cb"><label class="abs">label</output></div>
+<div class="cb"><fieldset class="abs">fieldset</fieldset></div>
+<div class="cb wide"><textarea class="abs">textarea</textarea></div>
+<div class="cb wide"><progress value="0.4" class="abs"></div>
+<div class="cb wide"><meter value="0.4" class="abs"></div>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-table-001.html b/testing/web-platform/tests/css/css-position/position-absolute-table-001.html
new file mode 100644
index 0000000000..c467ac4800
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-table-001.html
@@ -0,0 +1,112 @@
+<!DOCTYPE html>
+<title>CSS Position Absolute: table width/height</title>
+<link rel="author" href="mailto:atotic@google.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#abs-non-replaced-width">
+<meta name="assert" content="Table css width/height are different. Make sure absolute position respects the differences.">
+<style>
+
+.container {
+ margin-bottom: 8px;
+ position: relative;
+ width: 300px;
+ height: 220px;
+ background: gray;
+}
+table {
+ position: absolute;
+ border: 10px solid green;
+ width: 100px;
+ height: 100px;
+ background: yellow;
+ right: 0;
+ bottom: 0;
+ padding: 10px;
+ border-spacing: 0 0;
+}
+.contentbox {
+ box-sizing: content-box;
+ width: 60px;
+ height: 60px;
+}
+td {
+ padding: 0;
+}
+
+</style>
+<p>Table css width/height are interpreted differently: they are the minimum width. Absolute positioning code should respect this.</p>
+<div class="container">
+ <table id="one">
+ <td>t1</td>
+ </table>
+</div>
+<div class="container">
+ <table id="two">
+ <td><div style="width:160px;height:160px;background:orange">div makes cell larger.</div></td>
+ </table>
+</div>
+<div class="container">
+ <table id="one-border" style="box-sizing: border-box">
+ <td>t1</td>
+ </table>
+</div>
+<div class="container">
+ <table id="two-border" style="box-sizing: border-box">
+ <td><div style="width:160px;height:160px;background:orange">div makes cell larger.</div></td>
+ </table>
+</div>
+<div class="container">
+ <table id="one-content" class="contentbox">
+ <td>t1</td>
+ </table>
+</div>
+<div class="container">
+ <table id="two-content" class="contentbox">
+ <td><div style="width:160px;height:160px;background:orange">div makes cell larger.</div></td>
+ </table>
+</div>
+<script>
+test(() => {
+ let t = document.getElementById("one");
+ assert_equals(t.offsetWidth, 100);
+ assert_equals(t.offsetHeight, 100);
+ assert_equals(t.parentNode.offsetHeight, t.offsetTop + t.offsetHeight, "bottom position is 0");
+ assert_equals(t.parentNode.offsetWidth, t.offsetLeft + t.offsetWidth, "right position is 0");
+}, 'table size is interpreted as border-box width by default');
+test(() => {
+ let t = document.getElementById("two");
+ assert_equals(t.offsetWidth, 200);
+ assert_equals(t.offsetHeight, 200);
+ assert_equals(t.parentNode.offsetWidth, t.offsetLeft + t.offsetWidth, "right position is 0");
+ assert_equals(t.parentNode.offsetHeight, t.offsetTop + t.offsetHeight, "bottom position is 0");
+}, 'table size is interpreted as minimum width');
+test(() => {
+ let t = document.getElementById("one-border");
+ assert_equals(t.offsetWidth, 100);
+ assert_equals(t.offsetHeight, 100);
+ assert_equals(t.parentNode.offsetHeight, t.offsetTop + t.offsetHeight, "bottom position is 0");
+ assert_equals(t.parentNode.offsetWidth, t.offsetLeft + t.offsetWidth, "right position is 0");
+}, 'table size border-box');
+test(() => {
+ let t = document.getElementById("two-border");
+ assert_equals(t.offsetWidth, 200);
+ assert_equals(t.offsetHeight, 200);
+ assert_equals(t.parentNode.offsetWidth, t.offsetLeft + t.offsetWidth, "right position is 0");
+ assert_equals(t.parentNode.offsetHeight, t.offsetTop + t.offsetHeight, "bottom position is 0");
+}, 'table size border-box interpreted as minimum width');
+test(() => {
+ let t = document.getElementById("one-content");
+ assert_equals(t.offsetWidth, 100);
+ assert_equals(t.offsetHeight, 100);
+ assert_equals(t.parentNode.offsetHeight, t.offsetTop + t.offsetHeight, "bottom position is 0");
+ assert_equals(t.parentNode.offsetWidth, t.offsetLeft + t.offsetWidth, "right position is 0");
+}, 'table size content-box');
+test(() => {
+ let t = document.getElementById("two-content");
+ assert_equals(t.offsetWidth, 200);
+ assert_equals(t.offsetHeight, 200);
+ assert_equals(t.parentNode.offsetWidth, t.offsetLeft + t.offsetWidth, "right position is 0");
+ assert_equals(t.parentNode.offsetHeight, t.offsetTop + t.offsetHeight, "bottom position is 0");
+}, 'table size content-box interpreted as minimum width');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-under-non-containing-stacking-context-ref.html b/testing/web-platform/tests/css/css-position/position-absolute-under-non-containing-stacking-context-ref.html
new file mode 100644
index 0000000000..ceade7bafe
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-under-non-containing-stacking-context-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<div id="scroller" style="width: 200px; height: 200px; overflow: auto">
+ <div style="height: 0; opacity: 0.5; margin: 250px">
+ <div style="width: 100px; height: 100px; background: green"></div>
+ </div>
+</div>
+<script>
+scroller.scrollTo(200, 200);
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-absolute-under-non-containing-stacking-context.html b/testing/web-platform/tests/css/css-position/position-absolute-under-non-containing-stacking-context.html
new file mode 100644
index 0000000000..444f125767
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-absolute-under-non-containing-stacking-context.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://crbug.com/1273431">
+<link rel="match" href="position-absolute-under-non-containing-stacking-context-ref.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+<div id="scroller" style="width:200px; height: 200px; overflow: auto; position: relative">
+ <div style="height: 0; overflow: hidden; opacity: 0.5; margin: 250px">
+ <div style="width: 100px; height: 100px; position: absolute; background: green"></div>
+ </div>
+</div>
+<script>
+waitForAtLeastOneFrame().then(() => {
+ scroller.scrollTo(200, 200);
+ takeScreenshot();
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-change-ref.html b/testing/web-platform/tests/css/css-position/position-change-ref.html
new file mode 100644
index 0000000000..de797dec14
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-change-ref.html
@@ -0,0 +1,9 @@
+<!doctype HTML>
+<title>CSS Test Reference</title>
+<div style="position: relative; background: red; width: 100px; height: 100px; overflow: hidden;">
+ <div style="overflow-y: scroll; width: 400px; height: 400px;">
+ <div style="height: 100px; width: 100px; background: green;"></div>
+ <!-- forces scrolling -->
+ <div style="height: 700px;"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/position-change.html b/testing/web-platform/tests/css/css-position/position-change.html
new file mode 100644
index 0000000000..c5b5069eb9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-change.html
@@ -0,0 +1,25 @@
+<!doctype HTML>
+<html class="reftest-wait">
+ <title>CSS Test: Test for re-paint after position change</title>
+ <link rel="author" title="Philip Rogers" href="mailto:pdr@chromium.org" />
+ <link rel="help" href="https://www.w3.org/TR/CSS2/zindex.html">
+ <link rel="match" href="position-change-ref.html">
+ <script src="/common/reftest-wait.js"></script>
+
+ <div style="position: relative; background: red; width: 100px; height: 100px; overflow: hidden;">
+ <div id="target" style="overflow-y: scroll; width: 400px; height: 400px; position: relative;">
+ <div style="height: 100px; width: 100px; background: green;"></div>
+ <!-- forces scrolling -->
+ <div style="height: 700px;"></div>
+ </div>
+ </div>
+
+ <script>
+ onload = function() {
+ requestAnimationFrame(() => requestAnimationFrame(() => {
+ target.style.position = "";
+ takeScreenshot();
+ }));
+ }
+ </script>
+</html
diff --git a/testing/web-platform/tests/css/css-position/position-fixed-at-bottom-right-on-viewport.html b/testing/web-platform/tests/css/css-position/position-fixed-at-bottom-right-on-viewport.html
new file mode 100644
index 0000000000..9184db028e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-fixed-at-bottom-right-on-viewport.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name="viewport" content="width=device-width">
+<link rel="help" href="https://drafts.csswg.org/css-position/#fixed-pos">
+<meta name="assert" content="This test checks that `bottom` and `right` returned by getComputedStyle for position:fixed elements attached to right bottom of the layout viewport expaned to the minimum-scale size">
+<title></title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<style>
+html, body {
+ margin: 0;
+ width: 100%;
+ height: 100%;
+}
+#target {
+ position: fixed;
+ bottom: 0;
+ right: 0;
+ background: green;
+ width: 100px;
+ height: 100px;
+}
+</style>
+<div style="width: 200%; height: 200%;"></div>
+<div id="target"></div>
+<script>
+test(() => {
+ assert_equals(getComputedStyle(target).bottom, "0px");
+ assert_equals(getComputedStyle(target).right, "0px");
+}, "position:fixed ");
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-fixed-dynamic-transformed-sibling-ref.html b/testing/web-platform/tests/css/css-position/position-fixed-dynamic-transformed-sibling-ref.html
new file mode 100644
index 0000000000..a51b0a0b10
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-fixed-dynamic-transformed-sibling-ref.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name="viewport" content="width=device-width">
+<style>
+ body {
+ margin: 0;
+ }
+ .fixed {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 50px;
+ background-color: blue;
+ }
+</style>
+<div class="fixed"></div>
diff --git a/testing/web-platform/tests/css/css-position/position-fixed-dynamic-transformed-sibling.html b/testing/web-platform/tests/css/css-position/position-fixed-dynamic-transformed-sibling.html
new file mode 100644
index 0000000000..50c464812d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-fixed-dynamic-transformed-sibling.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name="viewport" content="width=device-width">
+<link rel="match" href="position-fixed-dynamic-transformed-sibling-ref.html">
+<link rel="help" href="https://drafts.csswg.org/css-position/#fixed-pos">
+<link rel="help" href="https://bugzil.la/1797703">
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<style>
+ body {
+ margin: 0;
+ }
+ .spacer {
+ height: 100px;
+ }
+ .transformed {
+ transform: translateX(0);
+ }
+ .fixed {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 50px;
+ background-color: blue;
+ }
+ #target {
+ position: relative;
+ }
+</style>
+<div class="spacer"></div>
+<div id="target" style="display: none">
+ <div class="transformed"></div>
+ <div class="fixed"></div>
+</div>
+<script>
+ let target = document.getElementById("target");
+ document.body.getBoundingClientRect();
+ target.style.display = "";
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-fixed-overflow-print-ref.html b/testing/web-platform/tests/css/css-position/position-fixed-overflow-print-ref.html
new file mode 100644
index 0000000000..0fb21d47f5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-fixed-overflow-print-ref.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<title>Test reference</title>
+<style>
+ body { margin: 0 }
+
+ #outer, #inner {
+ background-color: purple;
+ width: 50%;
+ height: 100vh;
+ }
+
+ #inner {
+ position: absolute;
+ background-color: blue;
+ top: 0;
+ left: 50%;
+ }
+</style>
+<div id="outer">
+ <div id="inner"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/position-fixed-overflow-print.html b/testing/web-platform/tests/css/css-position/position-fixed-overflow-print.html
new file mode 100644
index 0000000000..cf5cf2ea53
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-fixed-overflow-print.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<title>position: fixed doesn't overflow the margin area</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1714513">
+<link rel="help" href="https://drafts.csswg.org/css-position/#abspos-insets">
+<link rel="match" href="position-fixed-overflow-print-ref.html">
+<style>
+ body { margin: 0 }
+
+ #outer, #inner {
+ background-color: purple;
+ width: 100vw;
+ height: 100vh;
+ }
+
+ #inner {
+ position: fixed;
+ background-color: blue;
+ top: 0;
+ left: 50%;
+ }
+</style>
+<div id="outer">
+ <div id="inner"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/position-fixed-root-element-flex.html b/testing/web-platform/tests/css/css-position/position-fixed-root-element-flex.html
new file mode 100644
index 0000000000..69c95da519
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-fixed-root-element-flex.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="UTF-8">
+ <title>CSS Position: Box inset properties & position:fixed flex container as the root element</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"/>
+ <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+ <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+ <link rel="help" href="https://drafts.csswg.org/css-position-3/#insets">
+ <link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1584890">
+ <link rel="match" href="position-fixed-root-element-ref.html">
+ <meta name="assert" content="This test verifies the box inset properties on a position:fixed flex container root element.">
+
+ <style>
+ html {
+ display: flex;
+ position: fixed;
+ left: 10px;
+ right: 20px;
+ top: 30px;
+ bottom: 40px;
+ border: 5px dashed black;
+ box-sizing: border-box;
+ }
+ </style>
+
+ The black border should encompass the whole viewport,
+ with a bit of space on each side.
+ <br><br>
+ It shouldn't just shrinkwrap this text's height.
+</html>
diff --git a/testing/web-platform/tests/css/css-position/position-fixed-root-element-grid.html b/testing/web-platform/tests/css/css-position/position-fixed-root-element-grid.html
new file mode 100644
index 0000000000..4deebf405c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-fixed-root-element-grid.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="UTF-8">
+ <title>CSS Position: Box inset properties & position:fixed grid container as the root element</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"/>
+ <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+ <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+ <link rel="help" href="https://drafts.csswg.org/css-position-3/#insets">
+ <link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1584890">
+ <link rel="match" href="position-fixed-root-element-ref.html">
+ <meta name="assert" content="This test verifies the box inset properties on a position:fixed grid container root element.">
+
+ <style>
+ html {
+ display: grid;
+ position: fixed;
+ left: 10px;
+ right: 20px;
+ top: 30px;
+ bottom: 40px;
+ border: 5px dashed black;
+ box-sizing: border-box;
+ }
+ </style>
+
+ The black border should encompass the whole viewport,
+ with a bit of space on each side.
+ <br><br>
+ It shouldn't just shrinkwrap this text's height.
+</html>
diff --git a/testing/web-platform/tests/css/css-position/position-fixed-root-element-ref.html b/testing/web-platform/tests/css/css-position/position-fixed-root-element-ref.html
new file mode 100644
index 0000000000..96dfe200fb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-fixed-root-element-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="UTF-8">
+ <title>CSS Position Reference: Box inset properties & position:fixed root element</title>
+ <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com"/>
+ <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+ <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+
+ <style>
+ html {
+ display: block;
+ position: fixed;
+ left: 10px;
+ right: 20px;
+ top: 30px;
+ bottom: 40px;
+ border: 5px dashed black;
+ box-sizing: border-box;
+ }
+ </style>
+
+ The black border should encompass the whole viewport,
+ with a bit of space on each side.
+ <br><br>
+ It shouldn't just shrinkwrap this text's height.
+</html>
diff --git a/testing/web-platform/tests/css/css-position/position-fixed-scroll-nested-fixed-ref.html b/testing/web-platform/tests/css/css-position/position-fixed-scroll-nested-fixed-ref.html
new file mode 100644
index 0000000000..024bf032d7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-fixed-scroll-nested-fixed-ref.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<div style="width: 200px; height: 100px; background: green"></div>
+<div style="height: 4900px"></div>
diff --git a/testing/web-platform/tests/css/css-position/position-fixed-scroll-nested-fixed.html b/testing/web-platform/tests/css/css-position/position-fixed-scroll-nested-fixed.html
new file mode 100644
index 0000000000..64586a207e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-fixed-scroll-nested-fixed.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<title>CSS Position: Nested position:fixed in a scrollable position:fixed</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#fixed-position">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=956203">
+<link rel="match" href="position-fixed-scroll-nested-fixed-ref.html">
+<meta name="assert" content="The nested position:fixed element should be above its parent, as if it was a sibling.">
+<div id="outer" style="position: fixed; width: 100px; height: 100px; overflow: auto; background: red">
+ <div style="position: fixed; width: 200px; height: 100px; background: green"></div>
+ <div style="height: 500px"></div>
+</div>
+<div style="height: 5000px"></div>
+<script>
+outer.scrollTop = 200;
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-fixed-scroll-overlap-ref.html b/testing/web-platform/tests/css/css-position/position-fixed-scroll-overlap-ref.html
new file mode 100644
index 0000000000..b9535e04e8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-fixed-scroll-overlap-ref.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<div style="width: 100px; height: 8000px; background: green"></div>
diff --git a/testing/web-platform/tests/css/css-position/position-fixed-scroll-overlap.html b/testing/web-platform/tests/css/css-position/position-fixed-scroll-overlap.html
new file mode 100644
index 0000000000..3bfcf83761
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-fixed-scroll-overlap.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://drafts.csswg.org/css-position/#fixed-pos">
+<link rel="help" href="https://crbug.com/1274414">
+<link rel="match" href="position-fixed-scroll-overlap-ref.html">
+<meta name="assert" content="The red fixed-position element should be always invisible
+ (covered by the green elements), regardless of viewport scroll offset">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+<style>
+.section {
+ width: 100px;
+ height: 2000px;
+ background: green;
+ position: relative;
+ z-index: 2;
+}
+</style>
+<svg style="width: 100px; height: 1000px; position: fixed">
+ <rect width="200" height="2000" fill="red"/>
+</svg>
+<div class="section"></div>
+<div class="section"></div>
+<div class="section"></div>
+<div class="section"></div>
+<script>
+ waitForAtLeastOneFrame().then(() => {
+ window.scrollTo(0, 4000);
+ waitForAtLeastOneFrame().then(() => {
+ window.scrollTo(0, 0);
+ takeScreenshot();
+ });
+ });
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/position-fixed-video-controls-print.html b/testing/web-platform/tests/css/css-position/position-fixed-video-controls-print.html
new file mode 100644
index 0000000000..685762c377
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-fixed-video-controls-print.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<link rel=help href="https://bugzilla.mozilla.org/show_bug.cgi?id=1764224">
+<!-- Really a crashtest but since we can't really have print crashtests, we assert that we print something -->
+<link rel="mismatch" href="/css/reference/blank.html">
+<q style="page-break-after: left"></q>
+<pre>a</pre>
+<audio style="position: fixed" controls="controls">a</audio>
diff --git a/testing/web-platform/tests/css/css-position/position-relative-001.html b/testing/web-platform/tests/css/css-position/position-relative-001.html
new file mode 100644
index 0000000000..7ec9e4f767
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-001.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/1058690">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="A percent inset resolves against the available size.">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="width: 100px; height: 100px; background: red;">
+ <span style="position: relative; top: 100%; left: 100%;">
+ <div style="width: 100px; height: 100px; background: green; position: relative; top: -100px; left: -100px;"></div>
+ </span>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/position-relative-002.html b/testing/web-platform/tests/css/css-position/position-relative-002.html
new file mode 100644
index 0000000000..7e176be987
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-002.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/1058690">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="A percent inset resolves against the available size.">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="width: 100px; height: 100px; background: red;">
+ <span style="position: relative; top: 100px; left: 100px;">
+ <div style="width: 100px; height: 100px; background: green; position: relative; top: -100%; left: -100%;"></div>
+ </span>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/position-relative-003.html b/testing/web-platform/tests/css/css-position/position-relative-003.html
new file mode 100644
index 0000000000..7a0040c40b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-003.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/1058690">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="A percent inset resolves against the available size.">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="width: 100px; height: 100px; background: red;">
+ <span style="position: relative; top: 100%; left: 100%;">
+ <span style="position: relative; top: -100px; left: -100px;">
+ <div style="width: 100px; height: 100px; background: green; position: fixed;"></div>
+ </span>
+ </span>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/position-relative-004.html b/testing/web-platform/tests/css/css-position/position-relative-004.html
new file mode 100644
index 0000000000..aac4520f72
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-004.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/1058690">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="A percent inset resolves against the available size when it dynamically changes.">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="target" style="contain: paint; width: 100px; background: red; line-height: 0;">
+ <span style="position: relative; top: -100%;">
+ <span style="position: relative; top: 100px;">
+ <div style="position: fixed; width: 100px; height: 100px; background: green;"></div>
+ </span>
+ </span>
+</div>
+<script>
+document.body.offsetTop;
+document.getElementById('target').style.height = '100px';
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-relative-005.html b/testing/web-platform/tests/css/css-position/position-relative-005.html
new file mode 100644
index 0000000000..f1ad084674
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-005.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/1058690">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="A percent inset resolves against the available size when it dynamically changes.">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="target" style="width: 100px; background: red; line-height: 0;">
+ <span style="position: relative; top: -100%;">
+ <span style="position: relative; top: 100px;">
+ <div style="position: absolute; width: 100px; height: 100px; background: green;"></div>
+ </span>
+ </span>
+</div>
+<script>
+document.body.offsetTop;
+document.getElementById('target').style.height = '100px';
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-relative-006.html b/testing/web-platform/tests/css/css-position/position-relative-006.html
new file mode 100644
index 0000000000..545edc990b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-006.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta name="assert" content="This ensures that a relative-positioned element inset doesn't resolve against an indefinite size.">
+<link rel="help" href="https://drafts.csswg.org/css-position-3/#relpos-insets">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="width: 100px; min-height: 100px; background: red;">
+ <div style="width: 100px; height: 100px; background: green; top: -10000%; position: relative;"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/position-relative-007.html b/testing/web-platform/tests/css/css-position/position-relative-007.html
new file mode 100644
index 0000000000..2425514f30
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-007.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta name="assert" content="This ensures that a relative-positioned element inset doesn't resolve against an indefinite size.">
+<link rel="help" href="https://drafts.csswg.org/css-position-3/#relpos-insets">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="width: 100px; min-height: 100px; background: red;">
+ <div style="width: 100px; height: 100px; background: green; top: calc(10px + 10%); position: relative;"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/position-relative-008.html b/testing/web-platform/tests/css/css-position/position-relative-008.html
new file mode 100644
index 0000000000..e2c7c02bbd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-008.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1227884">
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="top: 100% doesn't resolve if the parent doesn't have a height specified.">
+<p>Test passes if there is a filled green square.</p>
+<table style="border-spacing: 0; background: red;">
+ <tbody>
+ <tr style="position: relative; top: 100%;">
+ <td style="padding: 0;">
+ <div style="width: 100px; height: 100px; background: green;"></div>
+ </td>
+ </tr>
+ </tbody>
+</table>
diff --git a/testing/web-platform/tests/css/css-position/position-relative-009.html b/testing/web-platform/tests/css/css-position/position-relative-009.html
new file mode 100644
index 0000000000..5f4093d75a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-009.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1227884">
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="top: 100% doesn't resolve if the parent doesn't have a height specified.">
+<p>Test passes if there is a filled green square.</p>
+<table style="border-spacing: 0; background: red;">
+ <tbody style="position: relative; top: 100%;">
+ <tr>
+ <td style="padding: 0;">
+ <div style="width: 100px; height: 100px; background: green;"></div>
+ </td>
+ </tr>
+ </tbody>
+</table>
diff --git a/testing/web-platform/tests/css/css-position/position-relative-010.html b/testing/web-platform/tests/css/css-position/position-relative-010.html
new file mode 100644
index 0000000000..4069735799
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-010.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1227884">
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="top: 100% doesn't resolve if the parent doesn't have a height specified.">
+<p>Test passes if there is a filled green square.</p>
+<table style="border-spacing: 0; background: red;">
+ <tbody>
+ <tr>
+ <td style="position: relative; top: 100%; padding: 0;">
+ <div style="width: 100px; height: 100px; background: green;"></div>
+ </td>
+ </tr>
+ </tbody>
+</table>
diff --git a/testing/web-platform/tests/css/css-position/position-relative-011.html b/testing/web-platform/tests/css/css-position/position-relative-011.html
new file mode 100644
index 0000000000..aaf7492a8b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-011.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1227884">
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="top: 100% doesn't resolves against the specified parent height (not the used height).">
+<p>Test passes if there is a filled green square.</p>
+<table style="border-spacing: 0; background: red;">
+ <tbody style="height: 10px;">
+ <tr style="position: relative; top: 100%;">
+ <td style="padding: 0;">
+ <div style="position: relative; top: -10px; width: 100px; height: 100px; background: green;"></div>
+ </td>
+ </tr>
+ </tbody>
+</table>
diff --git a/testing/web-platform/tests/css/css-position/position-relative-012.html b/testing/web-platform/tests/css/css-position/position-relative-012.html
new file mode 100644
index 0000000000..c2debe1af9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-012.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1227884">
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="top: 100% doesn't resolves against the specified parent height (not the used height).">
+<p>Test passes if there is a filled green square.</p>
+<table style="border-spacing: 0; background: red; height: 10px;">
+ <tbody style="position: relative; top: 100%;">
+ <tr>
+ <td style="padding: 0;">
+ <div style="position: relative; top: -10px; width: 100px; height: 100px; background: green;"></div>
+ </td>
+ </tr>
+ </tbody>
+</table>
diff --git a/testing/web-platform/tests/css/css-position/position-relative-013.html b/testing/web-platform/tests/css/css-position/position-relative-013.html
new file mode 100644
index 0000000000..94888b158f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-013.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1227884">
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="top: 100% doesn't resolves against the specified parent height (not the used height).">
+<p>Test passes if there is a filled green square.</p>
+<table style="border-spacing: 0; background: red;">
+ <tbody>
+ <tr style="height: 10px;">
+ <td style="position: relative; top: 100%; padding: 0;">
+ <div style="position: relative; top: -10px; width: 100px; height: 100px; background: green;"></div>
+ </td>
+ </tr>
+ </tbody>
+</table>
diff --git a/testing/web-platform/tests/css/css-position/position-relative-014.html b/testing/web-platform/tests/css/css-position/position-relative-014.html
new file mode 100644
index 0000000000..88edec0255
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-014.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1463425">
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<style>
+.box {
+ display: inline-block;
+ background-color: green;
+ width: 100px;
+ height: 50px;
+}
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div style="width: 100px; background: red; line-height: 0;">
+ <div id="target" style="position: relative; left: -100px;" class="box"></div>
+ <div class="box"></div>
+</div>
+<script>
+document.body.offsetTop;
+const target = document.getElementById('target');
+target.style.left = '0px';
+</script>
diff --git a/testing/web-platform/tests/css/css-position/position-relative-table-caption.html b/testing/web-platform/tests/css/css-position/position-relative-table-caption.html
new file mode 100644
index 0000000000..20ff628880
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-table-caption.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<title>position:relative should work on table captions</title>
+<link rel="match" href="position-relative-table-top-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#rel-pos" />
+<meta name="assert" content="This test checks that the position:relative top constraint behaves correctly for &lt;caption&gt; elements">
+<style>
+table {
+ border-collapse:collapse;
+}
+
+caption {
+ width: 50px;
+ height: 50px;
+ position: relative;
+ top: 100px;
+ background-color: green;
+}
+
+.group {
+ position: relative;
+ display: inline-block;
+ height: 200px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 0;
+ top: 100px;
+ height: 50px;
+ width: 50px;
+}
+</style>
+
+<div class="group">
+ <div class="indicator"></div>
+ <table>
+ <caption></caption>
+ </table>
+</div>
+
+<div>You should see a green box above. No red should be visible.</div>
+
diff --git a/testing/web-platform/tests/css/css-position/position-relative-table-left-ref.html b/testing/web-platform/tests/css/css-position/position-relative-table-left-ref.html
new file mode 100644
index 0000000000..7c1193b800
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-table-left-ref.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<title>Reference for position:relative top constraint should behave correctly for table part elements</title>
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: green;
+ left: 100px;
+ height: 50px;
+ width: 50px;
+}
+
+</style>
+
+<div class="group">
+ <div>
+ <div class="indicator"></div>
+ </div>
+</div>
+
+<div>You should see a green box above. No red should be visible.</div>
+
diff --git a/testing/web-platform/tests/css/css-position/position-relative-table-tbody-left-absolute-child.html b/testing/web-platform/tests/css/css-position/position-relative-table-tbody-left-absolute-child.html
new file mode 100644
index 0000000000..98e759a8c0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-table-tbody-left-absolute-child.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<title>position:relative top constraint should behave correctly for &lt;tr&gt; elements</title>
+<link rel="match" href="position-relative-table-left-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#rel-pos" />
+<meta name="assert" content="This test checks that the position:relative top constraint behaves correctly for &lt;tbody&gt; elements" />
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 100px;
+ height: 50px;
+ width: 50px;
+}
+
+.relative {
+ position: relative;
+ left: 50px;
+ background-color: green;
+}
+
+.absolute {
+ position: absolute;
+ left: 50px;
+ background-color: green;
+}
+</style>
+
+<div class="group">
+ <div>
+ <div class="indicator"></div>
+ <table>
+ <tbody class="relative">
+ <tr><td><div class="absolute"></div></td></tr>
+ </tbody>
+ </table>
+ </div>
+</div>
+
+<div>You should see a green box above. No red should be visible.</div>
+
diff --git a/testing/web-platform/tests/css/css-position/position-relative-table-tbody-left.html b/testing/web-platform/tests/css/css-position/position-relative-table-tbody-left.html
new file mode 100644
index 0000000000..e58de10538
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-table-tbody-left.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<title>position:relative top constraint should behave correctly for &lt;tbody&gt; elements</title>
+<link rel="match" href="position-relative-table-left-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#rel-pos" />
+<meta name="assert" content="This test checks that the position:relative top constraint behaves correctly for &lt;tbody&gt; elements" />
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 100px;
+ height: 50px;
+ width: 50px;
+}
+
+.relative {
+ position: relative;
+ left: 100px;
+ background-color: green;
+}
+</style>
+
+<div class="group">
+ <div>
+ <div class="indicator"></div>
+ <table>
+ <tbody class="relative">
+ <tr><td><div></div></td></tr>
+ </tbody>
+ </table>
+ </div>
+</div>
+
+<div>You should see a green box above. No red should be visible.</div>
+
diff --git a/testing/web-platform/tests/css/css-position/position-relative-table-tbody-top-absolute-child.html b/testing/web-platform/tests/css/css-position/position-relative-table-tbody-top-absolute-child.html
new file mode 100644
index 0000000000..44daea4c1b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-table-tbody-top-absolute-child.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<title>position:relative top constraint should behave correctly for &lt;tbody&gt; elements</title>
+<link rel="match" href="position-relative-table-top-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#rel-pos" />
+<meta name="assert" content="This test checks that the position:relative top constraint behaves correctly for &lt;tbody&gt; elements" />
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 0;
+ top: 100px;
+ height: 50px;
+ width: 50px;
+}
+
+.relative {
+ position: relative;
+ top: 50px;
+ background-color: green;
+}
+
+.absolute {
+ position: absolute;
+ top: 50px;
+ background-color: green;
+}
+</style>
+
+<div class="group">
+ <div>
+ <div class="indicator"></div>
+ <table>
+ <tbody class="relative">
+ <tr><td><div class="absolute"></div></td></tr>
+ </tbody>
+ </table>
+ </div>
+</div>
+
+<div>You should see a green box above. No red should be visible.</div>
+
diff --git a/testing/web-platform/tests/css/css-position/position-relative-table-tbody-top.html b/testing/web-platform/tests/css/css-position/position-relative-table-tbody-top.html
new file mode 100644
index 0000000000..a958de8237
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-table-tbody-top.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<title>position:relative top constraint should behave correctly for &lt;tbody&gt; elements</title>
+<link rel="match" href="position-relative-table-top-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#rel-pos" />
+<meta name="assert" content="This test checks that the position:relative top constraint behaves correctly for &lt;tbody&gt; elements" />
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 0;
+ top: 100px;
+ height: 50px;
+ width: 50px;
+}
+
+.relative {
+ position: relative;
+ top: 100px;
+ background-color: green;
+}
+</style>
+
+<div class="group">
+ <div>
+ <div class="indicator"></div>
+ <table>
+ <tbody class="relative">
+ <tr><td><div></div></td></tr>
+ </tbody>
+ </table>
+ </div>
+</div>
+
+<div>You should see a green box above. No red should be visible.</div>
+
diff --git a/testing/web-platform/tests/css/css-position/position-relative-table-td-left.html b/testing/web-platform/tests/css/css-position/position-relative-table-td-left.html
new file mode 100644
index 0000000000..0b87d62163
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-table-td-left.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<title>position:relative top constraint should behave correctly for &lt;td&gt; elements</title>
+<link rel="match" href="position-relative-table-left-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#rel-pos" />
+<meta name="assert" content="This test checks that the position:relative top constraint behaves correctly for &lt;td&gt; elements" />
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 100px;
+ height: 50px;
+ width: 50px;
+}
+
+.relative {
+ position: relative;
+ left: 100px;
+ background-color: green;
+}
+</style>
+
+<div class="group">
+ <div>
+ <div class="indicator"></div>
+ <table>
+ <tbody>
+ <tr><td class="relative"><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ </table>
+ </div>
+</div>
+
+<div>You should see a green box above. No red should be visible.</div>
+
diff --git a/testing/web-platform/tests/css/css-position/position-relative-table-td-top.html b/testing/web-platform/tests/css/css-position/position-relative-table-td-top.html
new file mode 100644
index 0000000000..dfd8679822
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-table-td-top.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<title>position:relative top constraint should behave correctly for &lt;td&gt; elements</title>
+<link rel="match" href="position-relative-table-top-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#rel-pos" />
+<meta name="assert" content="This test checks that the position:relative top constraint behaves correctly for &lt;td&gt; elements" />
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 0;
+ top: 100px;
+ height: 50px;
+ width: 50px;
+}
+
+.relative {
+ position: relative;
+ top: 100px;
+ background-color: green;
+}
+</style>
+
+<div class="group">
+ <div>
+ <div class="indicator"></div>
+ <table>
+ <tbody>
+ <tr><td class="relative"><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ </table>
+ </div>
+</div>
+
+<div>You should see a green box above. No red should be visible.</div>
+
diff --git a/testing/web-platform/tests/css/css-position/position-relative-table-tfoot-left-absolute-child.html b/testing/web-platform/tests/css/css-position/position-relative-table-tfoot-left-absolute-child.html
new file mode 100644
index 0000000000..9833aab71c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-table-tfoot-left-absolute-child.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<title>position:relative top constraint should behave correctly for &lt;tfoot&gt; elements</title>
+<link rel="match" href="position-relative-table-left-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#rel-pos" />
+<meta name="assert" content="This test checks that the position:relative top constraint behaves correctly for &lt;tfoot&gt; elements" />
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 100px;
+ height: 50px;
+ width: 50px;
+}
+
+.relative {
+ position: relative;
+ left: 50px;
+ background-color: green;
+}
+
+.absolute {
+ position: absolute;
+ left: 50px;
+ background-color: green;
+}
+</style>
+
+<div class="group">
+ <div>
+ <div class="indicator"></div>
+ <table>
+ <tfoot class="relative">
+ <tr><td><div class="absolute"></div></td></tr>
+ </tfoot>
+ </table>
+ </div>
+</div>
+
+<div>You should see a green box above. No red should be visible.</div>
+
diff --git a/testing/web-platform/tests/css/css-position/position-relative-table-tfoot-left.html b/testing/web-platform/tests/css/css-position/position-relative-table-tfoot-left.html
new file mode 100644
index 0000000000..5b72f3bec6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-table-tfoot-left.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<title>position:relative top constraint should behave correctly for &lt;tfoot&gt; elements</title>
+<link rel="match" href="position-relative-table-left-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#rel-pos" />
+<meta name="assert" content="This test checks that the position:relative top constraint behaves correctly for &lt;tfoot&gt; elements" />
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 100px;
+ height: 50px;
+ width: 50px;
+}
+
+.relative {
+ position: relative;
+ left: 100px;
+ background-color: green;
+}
+</style>
+
+<div class="group">
+ <div>
+ <div class="indicator"></div>
+ <table>
+ <tfoot class="relative">
+ <tr><td><div></div></td></tr>
+ </tfoot>
+ </table>
+ </div>
+</div>
+
+<div>You should see a green box above. No red should be visible.</div>
+
diff --git a/testing/web-platform/tests/css/css-position/position-relative-table-tfoot-top-absolute-child.html b/testing/web-platform/tests/css/css-position/position-relative-table-tfoot-top-absolute-child.html
new file mode 100644
index 0000000000..e98712b22b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-table-tfoot-top-absolute-child.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<title>position:relative top constraint should behave correctly for &lt;tfoot&gt; elements</title>
+<link rel="match" href="position-relative-table-tfoot-top-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#rel-pos" />
+<meta name="assert" content="This test checks that the position:relative top constraint behaves correctly for &lt;tfoot&gt; elements" />
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 0;
+ top: 150px;
+ height: 50px;
+ width: 50px;
+}
+
+.relative {
+ position: relative;
+ top: 50px;
+ background-color: white;
+}
+
+.absolute {
+ position: absolute;
+ top: 50px;
+ background-color: green;
+}
+</style>
+
+<div class="group">
+ <div>
+ <div class="indicator"></div>
+ <table>
+ <tbody>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ <tfoot class="relative">
+ <tr><td style="width:50px;height:50px"><div class="absolute"></div></td></tr>
+ </tfoot>
+ </table>
+ </div>
+</div>
+
+<div>You should see a green box above. No red should be visible.</div>
+
diff --git a/testing/web-platform/tests/css/css-position/position-relative-table-tfoot-top-ref.html b/testing/web-platform/tests/css/css-position/position-relative-table-tfoot-top-ref.html
new file mode 100644
index 0000000000..a3e709becf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-table-tfoot-top-ref.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: green;
+ left: 0;
+ top: 150px;
+ height: 50px;
+ width: 50px;
+}
+
+</style>
+
+<div class="group">
+ <div>
+ <div class="indicator"></div>
+ </div>
+</div>
+
+<div>You should see a green box above. No red should be visible.</div>
+
diff --git a/testing/web-platform/tests/css/css-position/position-relative-table-tfoot-top.html b/testing/web-platform/tests/css/css-position/position-relative-table-tfoot-top.html
new file mode 100644
index 0000000000..c55c04b2fa
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-table-tfoot-top.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<title>position:relative top constraint should behave correctly for &lt;tfoot&gt; elements</title>
+<link rel="match" href="position-relative-table-tfoot-top-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#rel-pos" />
+<meta name="assert" content="This test checks that the position:relative top constraint behaves correctly for &lt;tfoot&gt; elements" />
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 0;
+ top: 150px;
+ height: 50px;
+ width: 50px;
+}
+
+.relative {
+ position: relative;
+ top: 100px;
+ background-color: green;
+}
+</style>
+
+<div class="group">
+ <div>
+ <div class="indicator"></div>
+ <table>
+ <tbody>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ <tfoot class="relative">
+ <tr><td><div></div></td></tr>
+ </tfoot>
+ </table>
+ </div>
+</div>
+
+<div>You should see a green box above. No red should be visible.</div>
+
diff --git a/testing/web-platform/tests/css/css-position/position-relative-table-thead-left-absolute-child.html b/testing/web-platform/tests/css/css-position/position-relative-table-thead-left-absolute-child.html
new file mode 100644
index 0000000000..6619455b23
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-table-thead-left-absolute-child.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<title>position:relative top constraint should behave correctly for &lt;thead&gt; elements</title>
+<link rel="match" href="position-relative-table-left-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#rel-pos" />
+<meta name="assert" content="This test checks that the position:relative top constraint behaves correctly for &lt;thead&gt; elements" />
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 100px;
+ height: 50px;
+ width: 50px;
+}
+
+.relative {
+ position: relative;
+ left: 50px;
+ background-color: green;
+}
+
+.absolute {
+ position: absolute;
+ left: 50px;
+ background-color: green;
+}
+</style>
+
+<div class="group">
+ <div>
+ <div class="indicator"></div>
+ <table>
+ <thead class="relative">
+ <tr><td><div class="absolute"></div></td></tr>
+ </thead>
+ </table>
+ </div>
+</div>
+
+<div>You should see a green box above. No red should be visible.</div>
+
diff --git a/testing/web-platform/tests/css/css-position/position-relative-table-thead-left.html b/testing/web-platform/tests/css/css-position/position-relative-table-thead-left.html
new file mode 100644
index 0000000000..d604bc11a3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-table-thead-left.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<title>position:relative top constraint should behave correctly for &lt;thead&gt; elements</title>
+<link rel="match" href="position-relative-table-left-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#rel-pos" />
+<meta name="assert" content="This test checks that the position:relative top constraint behaves correctly for &lt;thead&gt; elements" />
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 100px;
+ height: 50px;
+ width: 50px;
+}
+
+.relative {
+ position: relative;
+ left: 100px;
+ background-color: green;
+}
+</style>
+
+<div class="group">
+ <div>
+ <div class="indicator"></div>
+ <table>
+ <thead class="relative">
+ <tr><td><div></div></td></tr>
+ </thead>
+ </table>
+ </div>
+</div>
+
+<div>You should see a green box above. No red should be visible.</div>
+
diff --git a/testing/web-platform/tests/css/css-position/position-relative-table-thead-top-absolute-child.html b/testing/web-platform/tests/css/css-position/position-relative-table-thead-top-absolute-child.html
new file mode 100644
index 0000000000..c2e2bf85a5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-table-thead-top-absolute-child.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<title>position:relative top constraint should behave correctly for &lt;thead&gt; elements</title>
+<link rel="match" href="position-relative-table-top-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#rel-pos" />
+<meta name="assert" content="This test checks that the position:relative top constraint behaves correctly for &lt;thead&gt; elements" />
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 0;
+ top: 100px;
+ height: 50px;
+ width: 50px;
+}
+
+.relative {
+ position: relative;
+ top: 50px;
+ background-color: green;
+}
+
+.absolute {
+ position: absolute;
+ top: 50px;
+ background-color: green;
+}
+</style>
+
+<div class="group">
+ <div>
+ <div class="indicator"></div>
+ <table>
+ <thead class="relative">
+ <tr><td><div class="absolute"></div></td></tr>
+ </thead>
+ <tbody>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ </table>
+ </div>
+</div>
+
+<div>You should see a green box above. No red should be visible.</div>
+
diff --git a/testing/web-platform/tests/css/css-position/position-relative-table-thead-top.html b/testing/web-platform/tests/css/css-position/position-relative-table-thead-top.html
new file mode 100644
index 0000000000..ae481313db
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-table-thead-top.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<title>position:relative top constraint should behave correctly for &lt;thead&gt; elements</title>
+<link rel="match" href="position-relative-table-top-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#rel-pos" />
+<meta name="assert" content="This test checks that the position:relative top constraint behaves correctly for &lt;thead&gt; elements" />
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 0;
+ top: 100px;
+ height: 50px;
+ width: 50px;
+}
+
+.relative {
+ position: relative;
+ top: 100px;
+ background-color: green;
+}
+</style>
+
+<div class="group">
+ <div>
+ <div class="indicator"></div>
+ <table>
+ <thead class="relative">
+ <tr><td><div></div></td></tr>
+ </thead>
+ <tbody>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ </table>
+ </div>
+</div>
+
+<div>You should see a green box above. No red should be visible.</div>
+
diff --git a/testing/web-platform/tests/css/css-position/position-relative-table-top-ref.html b/testing/web-platform/tests/css/css-position/position-relative-table-top-ref.html
new file mode 100644
index 0000000000..795e08b8ba
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-table-top-ref.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<title>Reference for position:relative top constraint should behave correctly for table part elements</title>
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: green;
+ left: 0;
+ top: 100px;
+ height: 50px;
+ width: 50px;
+}
+
+</style>
+
+<div class="group">
+ <div>
+ <div class="indicator"></div>
+ </div>
+</div>
+
+<div>You should see a green box above. No red should be visible.</div>
+
diff --git a/testing/web-platform/tests/css/css-position/position-relative-table-tr-left-absolute-child.html b/testing/web-platform/tests/css/css-position/position-relative-table-tr-left-absolute-child.html
new file mode 100644
index 0000000000..ef812e4323
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-table-tr-left-absolute-child.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<title>position:relative top constraint should behave correctly for &lt;tr&gt; elements</title>
+<link rel="match" href="position-relative-table-left-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#rel-pos" />
+<meta name="assert" content="This test checks that the position:relative top constraint behaves correctly for &lt;tr&gt; elements" />
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 100px;
+ height: 50px;
+ width: 50px;
+}
+
+.relative {
+ position: relative;
+ left: 50px;
+ background-color: green;
+}
+
+.absolute {
+ position: absolute;
+ left: 50px;
+ background-color: green;
+}
+</style>
+
+<div class="group">
+ <div>
+ <div class="indicator"></div>
+ <table>
+ <tbody>
+ <tr class="relative"><td><div class="absolute"></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ </table>
+ </div>
+</div>
+
+<div>You should see a green box above. No red should be visible.</div>
+
diff --git a/testing/web-platform/tests/css/css-position/position-relative-table-tr-left.html b/testing/web-platform/tests/css/css-position/position-relative-table-tr-left.html
new file mode 100644
index 0000000000..004b284cb7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-table-tr-left.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<title>position:relative top constraint should behave correctly for &lt;tr&gt; elements</title>
+<link rel="match" href="position-relative-table-left-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#rel-pos" />
+<meta name="assert" content="This test checks that the position:relative top constraint behaves correctly for &lt;tr&gt; elements" />
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 100px;
+ height: 50px;
+ width: 50px;
+}
+
+.relative {
+ position: relative;
+ left: 100px;
+ background-color: green;
+}
+</style>
+
+<div class="group">
+ <div>
+ <div class="indicator"></div>
+ <table>
+ <tbody>
+ <tr class="relative"><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ </table>
+ </div>
+</div>
+
+<div>You should see a green box above. No red should be visible.</div>
+
diff --git a/testing/web-platform/tests/css/css-position/position-relative-table-tr-top-absolute-child.html b/testing/web-platform/tests/css/css-position/position-relative-table-tr-top-absolute-child.html
new file mode 100644
index 0000000000..855080adc8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-table-tr-top-absolute-child.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<title>position:relative top constraint should behave correctly for &lt;tr&gt; elements</title>
+<link rel="match" href="position-relative-table-top-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#rel-pos" />
+<meta name="assert" content="This test checks that the position:relative top constraint behaves correctly for &lt;tr&gt; elements" />
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 0;
+ top: 100px;
+ height: 50px;
+ width: 50px;
+}
+
+.relative {
+ position: relative;
+ top: 50px;
+}
+.absolute {
+ position: absolute;
+ top: 50px;
+ background-color: green;
+}
+</style>
+
+<div class="group">
+ <div>
+ <div class="indicator"></div>
+ <table>
+ <tbody>
+ <tr class="relative"><td><div class="absolute"></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ </table>
+ </div>
+</div>
+
+<div>You should see a green box above. No red should be visible.</div>
+
diff --git a/testing/web-platform/tests/css/css-position/position-relative-table-tr-top.html b/testing/web-platform/tests/css/css-position/position-relative-table-tr-top.html
new file mode 100644
index 0000000000..92f95d4422
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/position-relative-table-tr-top.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<title>position:relative top constraint should behave correctly for &lt;tr&gt; elements</title>
+<link rel="match" href="position-relative-table-top-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#rel-pos" />
+<meta name="assert" content="This test checks that the position:relative top constraint behaves correctly for &lt;tr&gt; elements" />
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 0;
+ top: 100px;
+ height: 50px;
+ width: 50px;
+}
+
+.relative {
+ position: relative;
+ top: 100px;
+ background-color: green;
+}
+</style>
+
+<div class="group">
+ <div>
+ <div class="indicator"></div>
+ <table>
+ <tbody>
+ <tr class="relative"><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ </table>
+ </div>
+</div>
+
+<div>You should see a green box above. No red should be visible.</div>
+
diff --git a/testing/web-platform/tests/css/css-position/positon-absolute-scrollable-overflow-001.html b/testing/web-platform/tests/css/css-position/positon-absolute-scrollable-overflow-001.html
new file mode 100644
index 0000000000..67e24a2475
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/positon-absolute-scrollable-overflow-001.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>CSS Positioned Layout Test: Absolute positioned elements are included in the scrollable overflow area</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-position/#valdef-position-absolute">
+<link rel="help" href="https://drafts.csswg.org/css-overflow/#scrollable">
+<link rel="help" href="https://drafts.csswg.org/cssom-view/#dom-element-scrollheight">
+<meta name=assert content="Absolute positioned elements are included in the scrollable overflow area of its containing block.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/check-layout-th.js"></script>
+<style>
+.containing-block {
+ position: relative;
+ width: 100px;
+ height: 100px;
+ margin: 100px;
+}
+
+.abspos {
+ position: absolute;
+ background: rgba(0, 255, 0, 0.5);
+ width: 10px;
+ height: 10px;
+ left: 0;
+ top: 0;
+}
+</style>
+<body onload="checkLayout('.containing-block');">
+ <div id="log"></div>
+ <div class="containing-block" data-expected-scroll-width="100" data-expected-scroll-height="500">
+ <div class="abspos" style="left: -50px; height: 500px;"></div>
+ </div>
+ <div class="containing-block" data-expected-scroll-width="100" data-expected-scroll-height="550">
+ <div class="abspos" style="left: -50px; height: 500px; top: 50px;"></div>
+ </div>
+ <div class="containing-block" data-expected-scroll-width="100" data-expected-scroll-height="700">
+ <div class="abspos" style="left: -50px; height: 500px; top: 200px;"></div>
+ </div>
+ <div class="containing-block" data-expected-scroll-width="100" data-expected-scroll-height="400">
+ <div class="abspos" style="left: -50px; height: 500px; top: -100px;"></div>
+ </div>
+ <div class="containing-block" data-expected-scroll-width="100" data-expected-scroll-height="100">
+ <div class="abspos" style="left: -50px; height: 500px; top: -1000px;"></div>
+ </div>
+ <div class="containing-block" data-expected-scroll-width="100" data-expected-scroll-height="100">
+ <div class="abspos" style="left: 50px; height: 500px; top: -1000px;"></div>
+ </div>
+ <div class="containing-block" data-expected-scroll-width="210" data-expected-scroll-height="700">
+ <div class="abspos" style="left: 200px; height: 500px; top: 200px;"></div>
+ </div>
+ <div class="containing-block" data-expected-scroll-width="500" data-expected-scroll-height="100">
+ <div class="abspos" style="width: 500px; top: -50px;"></div>
+ </div>
+ <div class="containing-block" data-expected-scroll-width="550" data-expected-scroll-height="100">
+ <div class="abspos" style="width: 500px; left: 50px; top: -50px;"></div>
+ </div>
+ <div class="containing-block" data-expected-scroll-width="700" data-expected-scroll-height="100">
+ <div class="abspos" style="width: 500px; left: 200px; top: -50px;"></div>
+ </div>
+ <div class="containing-block" data-expected-scroll-width="400" data-expected-scroll-height="100">
+ <div class="abspos" style="width: 500px; left: -100px; top: -50px;"></div>
+ </div>
+ <div class="containing-block" data-expected-scroll-width="100" data-expected-scroll-height="100">
+ <div class="abspos" style="width: 500px; left: -1000px; top: -50px;"></div>
+ </div>
+ <div class="containing-block" data-expected-scroll-width="100" data-expected-scroll-height="100">
+ <div class="abspos" style="width: 500px; left: -1000px; top: 50px;"></div>
+ </div>
+ <div class="containing-block" data-expected-scroll-width="700" data-expected-scroll-height="210">
+ <div class="abspos" style="width: 500px; left: 200px; top: 200px;"></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/css/css-position/resources/position-absolute-iframe-child-002.sub.html b/testing/web-platform/tests/css/css-position/resources/position-absolute-iframe-child-002.sub.html
new file mode 100644
index 0000000000..745a95ff98
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/resources/position-absolute-iframe-child-002.sub.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<style>
+ body {
+ margin: 0;
+ }
+ iframe {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ top: 0;
+ left: 0;
+ }
+</style>
+<div style="height:200vh;"></div>
+<iframe frameborder=0 scrolling=no
+ src="//{{hosts[][]}}:{{ports[http][0]}}{{location[path]}}/../position-absolute-iframe-child.html"></iframe>
diff --git a/testing/web-platform/tests/css/css-position/resources/position-absolute-iframe-child.html b/testing/web-platform/tests/css/css-position/resources/position-absolute-iframe-child.html
new file mode 100644
index 0000000000..3169cac0af
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/resources/position-absolute-iframe-child.html
@@ -0,0 +1,6 @@
+<!doctype html>
+<style>
+ body { margin: 0 }
+</style>
+<div style="height:200vh;"></div>
+<div style="position:absolute; top:0; left:0;">This text should be visible in the first page</div>
diff --git a/testing/web-platform/tests/css/css-position/resources/position-sticky-fixed-ancestor-iframe-child.html b/testing/web-platform/tests/css/css-position/resources/position-sticky-fixed-ancestor-iframe-child.html
new file mode 100644
index 0000000000..ee91178ff6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/resources/position-sticky-fixed-ancestor-iframe-child.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<style>
+ body,html {
+ margin: 0;
+ width: 100%;
+ height: 100%;
+ }
+
+ .sticky {
+ background: green;
+ position: sticky;
+ bottom: 50vh;
+ width: 100px;
+ height: 10%;
+ }
+
+ .spacer {
+ height: 90%;
+ }
+ .long {
+ height: 600vh;
+ }
+
+ .position-parent {
+ position: absolute;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: 100%;
+ top: 100vh;
+ background-color: lightgrey;
+ }
+
+ .container {
+ width: 100px;
+ height: 100%;
+ background-color: grey;
+ }
+
+ button {
+ position: fixed;
+ left: 20px;
+ top: 20px;
+ }
+
+ .fixed {
+ position: fixed;
+ top: 25vh;
+ }
+</style>
+
+<div class="position-parent">
+ <div class="container">
+ <div class="spacer"></div>
+ <div class="sticky"></div>
+ </div>
+</div>
+<div class="long"></div>
+<button id="button">Toggle Fixed</button>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/resources/ref-rectangle.js b/testing/web-platform/tests/css/css-position/resources/ref-rectangle.js
new file mode 100644
index 0000000000..c94c15720f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/resources/ref-rectangle.js
@@ -0,0 +1,34 @@
+/**
+ * The function positions a new div to exactly the bounding client rect without
+ * using sticky position. If it's directly under the sticky element it could be
+ * obscured and not show up when compared to the ref. */
+function createIndicatorForStickyElements(sticky_divs) {
+ if (sticky_divs.length == 0)
+ throw "No sticky div was found in the test case.";
+
+ sticky_divs.forEach((sticky_div) => {
+ if (getComputedStyle(sticky_div).position != "sticky")
+ throw "Provided sticky element does not have position: sticky";
+ });
+
+ document.fonts.ready.then(() => {
+ sticky_divs.forEach((sticky_div) => {
+ // The relative position indicator will be able to share the same containing
+ // block to match the position with the same offset from in flow position
+ // (offsetTop/offsetLeft)
+ let position_div = document.createElement("div");
+ position_div.style.left = sticky_div.offsetLeft + "px";
+ position_div.style.top = sticky_div.offsetTop + "px";
+ // The absolute position is to ensure that the position_div adds zero size
+ // to in flow layout
+ position_div.style.position = "absolute"
+ let indicator_div = document.createElement("div");
+ indicator_div.style.width = sticky_div.offsetWidth + "px";
+ indicator_div.style.height = sticky_div.offsetHeight + "px";
+ indicator_div.style.backgroundColor = "blue";
+ indicator_div.style.position = "relative";
+ position_div.appendChild(indicator_div);
+ sticky_div.parentNode.insertBefore(position_div, sticky_div);
+ });
+ });
+}
diff --git a/testing/web-platform/tests/css/css-position/resources/sticky-util.js b/testing/web-platform/tests/css/css-position/resources/sticky-util.js
new file mode 100644
index 0000000000..074c25c81f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/resources/sticky-util.js
@@ -0,0 +1,109 @@
+/**
+ * Builds a generic structure that looks like:
+ *
+ * <div class="scroller"> // 100x200 viewport
+ * <div class="contents"> // 100x500
+ * <div class="prepadding"></div> // 100x100
+ * <div class="container"> // 300x300 containing block
+ * <div class="filler"></div> // 100x100
+ * <div class="sticky box"></div> // 100x100
+ * </div>
+ * </div>
+ * </div>
+ *
+ * If the sticky direction is 'left' or 'right', the necessary blocks will be
+ * marked as inline-block and the dimensions above are flipped.
+ *
+ * Returns an 'elements' object which has each of the above elements as an
+ * accessible property.
+ */
+function setupStickyTest(stickyDirection, stickyOffset) {
+ const elements = {};
+ const inline = stickyDirection === 'left' || stickyDirection === 'right';
+
+ elements.scroller = document.createElement('div');
+ elements.scroller.style.position = 'relative';
+ elements.scroller.style.width = (inline ? '200px' : '100px');
+ elements.scroller.style.height = (inline ? '100px' : '200px');
+
+ // 'hidden' is used here instead of 'scroll' because this prevents
+ // scrollbars from affecting the size and offset of sticky items.
+ elements.scroller.style.overflow = 'hidden';
+
+ elements.contents = document.createElement('div');
+ elements.contents.style.height = (inline ? '100%' : '500px');
+ elements.contents.style.width = (inline ? '500px' : '100%');
+
+ elements.prepadding = document.createElement('div');
+ elements.prepadding.style.height = (inline ? '100%' : '100px');
+ elements.prepadding.style.width = (inline ? '100px' : '100%');
+ if (inline)
+ elements.prepadding.style.display = 'inline-block';
+
+ elements.container = document.createElement('div');
+ elements.container.style.height = (inline ? '100%' : '300px');
+ elements.container.style.width = (inline ? '300px' : '100%');
+ if (inline)
+ elements.container.style.display = 'inline-block';
+
+ elements.filler = document.createElement('div');
+ elements.filler.style.height = (inline ? '100%' : '100px');
+ elements.filler.style.width = (inline ? '100px' : '100%');
+ if (inline)
+ elements.filler.style.display = 'inline-block';
+
+ elements.sticky = document.createElement('div');
+ elements.sticky.style = `${stickyDirection}: ${stickyOffset}px;`;
+ elements.sticky.style.position = 'sticky';
+ elements.sticky.style.height = (inline ? '100%' : '100px');
+ elements.sticky.style.width = (inline ? '100px' : '100%');
+ elements.sticky.style.backgroundColor = 'green';
+ if (inline)
+ elements.sticky.style.display = 'inline-block';
+
+ elements.scroller.appendChild(elements.contents);
+ elements.contents.appendChild(elements.prepadding);
+ elements.contents.appendChild(elements.container);
+ elements.container.appendChild(elements.filler);
+ elements.container.appendChild(elements.sticky);
+
+ document.body.appendChild(elements.scroller);
+
+ return elements;
+}
+
+/**
+ * Similar to above, but nests a second sticky (named innerSticky) inside the
+ * sticky element.
+ *
+ * In the 'bottom' and 'right' cases, we also inject some padding before the
+ * innerSticky element, to give it something to push into. This inner padding is
+ * not exposed.
+ */
+function setupNestedStickyTest(stickyDirection, outerStickyOffset,
+ innerStickyOffset) {
+ const elements = setupStickyTest(stickyDirection, outerStickyOffset);
+
+ const inline = stickyDirection === 'left' || stickyDirection === 'right';
+ if (stickyDirection === 'bottom' || stickyDirection === 'right') {
+ const innerPadding = document.createElement('div');
+ innerPadding.style.height = (inline ? '100%' : '50px');
+ innerPadding.style.width = (inline ? '50px' : '100%');
+ if (inline)
+ innerPadding.style.display = 'inline-block';
+ elements.sticky.appendChild(innerPadding);
+ }
+
+ elements.innerSticky = document.createElement('div');
+ elements.innerSticky.style = `${stickyDirection}: ${innerStickyOffset}px;`;
+ elements.innerSticky.style.position = 'sticky';
+ elements.innerSticky.style.height = (inline ? '100%' : '50px');
+ elements.innerSticky.style.width = (inline ? '50px' : '100%');
+ elements.innerSticky.style.backgroundColor = 'blue';
+ if (inline)
+ elements.innerSticky.style.display = 'inline-block';
+
+ elements.sticky.appendChild(elements.innerSticky);
+
+ return elements;
+}
diff --git a/testing/web-platform/tests/css/css-position/static-position/htb-ltr-ltr.html b/testing/web-platform/tests/css/css-position/static-position/htb-ltr-ltr.html
new file mode 100644
index 0000000000..5a19c0e9cc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/htb-ltr-ltr.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="htb-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+ position: relative;
+ background: green;
+ color: green;
+ font: 16px/1 Ahem;
+ border: solid black 3px;
+ width: 400px;
+ margin: 16px 0;
+}
+.red { color: red; }
+.cb { position: relative; }
+.rtl { direction: rtl; }
+.ltr { direction: ltr; }
+.inline { display: inline; }
+.abs { position: absolute; }
+
+.indent { text-indent: 20px; }
+* { text-indent: initial; }
+</style>
+
+There should be no red.
+<div class="container ltr">
+ XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ XXX<span class="ltr cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="ltr cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ XXX<span class="ltr cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="ltr cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container ltr indent">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container ltr">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container ltr indent">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/htb-ltr-rtl.tentative.html b/testing/web-platform/tests/css/css-position/static-position/htb-ltr-rtl.tentative.html
new file mode 100644
index 0000000000..de6ef1c6c1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/htb-ltr-rtl.tentative.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="htb-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+ position: relative;
+ background: green;
+ color: green;
+ font: 16px/1 Ahem;
+ border: solid black 3px;
+ width: 400px;
+ margin: 16px 0;
+}
+.red { color: red; }
+.cb { position: relative; }
+.rtl { direction: rtl; }
+.ltr { direction: ltr; }
+.inline { display: inline; }
+.abs { position: absolute; }
+
+.indent { text-indent: 20px; }
+* { text-indent: initial; }
+</style>
+
+There should be no red.
+<div class="container ltr">
+ XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ XXX<span class="rtl cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="rtl cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ XXX<span class="rtl cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="rtl cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container ltr indent">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container ltr">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container ltr indent">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/htb-ref.html b/testing/web-platform/tests/css/css-position/static-position/htb-ref.html
new file mode 100644
index 0000000000..bd534b0772
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/htb-ref.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<style>
+.container {
+ background: green;
+ height: 16px;
+ border: solid black 3px;
+ width: 400px;
+ margin: 16px 0;
+}
+
+.large { height: 32px; }
+</style>
+
+There should be no red.
+<div class="container"></div>
+
+<div class="container"></div>
+
+<div class="container large"></div>
+
+<div class="container large"></div>
+
+<div class="container"></div>
+
+<div class="container"></div>
+
+<div class="container large"></div>
+
+<div class="container large"></div>
+
+<div class="container"></div>
+
+<div class="container"></div>
+
+<div class="container large"></div>
+
+<div class="container large"></div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/htb-rtl-ltr.tentative.html b/testing/web-platform/tests/css/css-position/static-position/htb-rtl-ltr.tentative.html
new file mode 100644
index 0000000000..c3a3155a10
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/htb-rtl-ltr.tentative.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="htb-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+ position: relative;
+ background: green;
+ color: green;
+ font: 16px/1 Ahem;
+ border: solid black 3px;
+ width: 400px;
+ margin: 16px 0;
+}
+.red { color: red; }
+.cb { position: relative; }
+.rtl { direction: rtl; }
+.ltr { direction: ltr; }
+.inline { display: inline; }
+.abs { position: absolute; }
+
+.indent { text-indent: 20px; }
+* { text-indent: initial; }
+</style>
+
+There should be no red.
+<div class="container rtl">
+ XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ XXX<span class="ltr cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="ltr cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ XXX<span class="ltr cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="ltr cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container rtl indent">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container rtl">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container rtl indent">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/htb-rtl-rtl.html b/testing/web-platform/tests/css/css-position/static-position/htb-rtl-rtl.html
new file mode 100644
index 0000000000..03ea18770a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/htb-rtl-rtl.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="htb-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.container {
+ position: relative;
+ background: green;
+ color: green;
+ font: 16px/1 Ahem;
+ border: solid black 3px;
+ width: 400px;
+ margin: 16px 0;
+}
+.red { color: red; }
+.cb { position: relative; }
+.rtl { direction: rtl; }
+.ltr { direction: ltr; }
+.inline { display: inline; }
+.abs { position: absolute; }
+
+.indent { text-indent: 20px; }
+* { text-indent: initial; }
+</style>
+
+There should be no red.
+<div class="container rtl">
+ XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ XXX<span class="rtl cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="rtl cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ XXX<span class="rtl cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="rtl cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container rtl indent">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container rtl">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container rtl indent">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-001.html b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-001.html
new file mode 100644
index 0000000000..d6f8ed4e39
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-001.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="Tests the static position of inline-level absolute-positioned elements, with combinations of float, direction, and text-align." />
+<style>
+#container { position: relative; background: red; width: 100px; height: 100px; }
+#container > div { background: green; }
+#inflow { height: 50px; }
+#float { float: left; width: 50px; height: 50px; }
+#abs { display: inline; position: absolute; width: 50px; height: 50px; }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id=container style="direction: ltr; text-align: left;">
+ <div id=inflow></div>
+ <div id=float style="float: left;"></div>
+ <div id=abs style="transform: translateX(0%);"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-002.html b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-002.html
new file mode 100644
index 0000000000..9b0f5c2bea
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-002.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="Tests the static position of inline-level absolute-positioned elements, with combinations of float, direction, and text-align." />
+<style>
+#container { position: relative; background: red; width: 100px; height: 100px; }
+#container > div { background: green; }
+#inflow { height: 50px; }
+#float { float: left; width: 50px; height: 50px; }
+#abs { display: inline; position: absolute; width: 50px; height: 50px; }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id=container style="direction: ltr; text-align: center;">
+ <div id=inflow></div>
+ <div id=float style="float: left;"></div>
+ <div id=abs style="transform: translateX(-50%);"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-003.html b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-003.html
new file mode 100644
index 0000000000..90db2d4f80
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-003.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="Tests the static position of inline-level absolute-positioned elements, with combinations of float, direction, and text-align." />
+<style>
+#container { position: relative; background: red; width: 100px; height: 100px; }
+#container > div { background: green; }
+#inflow { height: 50px; }
+#float { float: left; width: 50px; height: 50px; }
+#abs { display: inline; position: absolute; width: 50px; height: 50px; }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id=container style="direction: ltr; text-align: right;">
+ <div id=inflow></div>
+ <div id=float style="float: left;"></div>
+ <div id=abs style="transform: translateX(-100%);"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-004.html b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-004.html
new file mode 100644
index 0000000000..a6b13b26c8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-004.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="Tests the static position of inline-level absolute-positioned elements, with combinations of float, direction, and text-align." />
+<style>
+#container { position: relative; background: red; width: 100px; height: 100px; }
+#container > div { background: green; }
+#inflow { height: 50px; }
+#float { float: left; width: 50px; height: 50px; }
+#abs { display: inline; position: absolute; width: 50px; height: 50px; }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id=container style="direction: ltr; text-align: left;">
+ <div id=inflow></div>
+ <div id=float style="float: right;"></div>
+ <div id=abs style="transform: translateX(0%);"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-005.html b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-005.html
new file mode 100644
index 0000000000..481c83a757
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-005.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="Tests the static position of inline-level absolute-positioned elements, with combinations of float, direction, and text-align." />
+<style>
+#container { position: relative; background: red; width: 100px; height: 100px; }
+#container > div { background: green; }
+#inflow { height: 50px; }
+#float { float: left; width: 50px; height: 50px; }
+#abs { display: inline; position: absolute; width: 50px; height: 50px; }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id=container style="direction: ltr; text-align: center;">
+ <div id=inflow></div>
+ <div id=float style="float: right;"></div>
+ <div id=abs style="transform: translateX(-50%);"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-006.html b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-006.html
new file mode 100644
index 0000000000..de5322f819
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-006.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="Tests the static position of inline-level absolute-positioned elements, with combinations of float, direction, and text-align." />
+<style>
+#container { position: relative; background: red; width: 100px; height: 100px; }
+#container > div { background: green; }
+#inflow { height: 50px; }
+#float { float: left; width: 50px; height: 50px; }
+#abs { display: inline; position: absolute; width: 50px; height: 50px; }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id=container style="direction: ltr; text-align: right;">
+ <div id=inflow></div>
+ <div id=float style="float: right;"></div>
+ <div id=abs style="transform: translateX(-100%);"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-007.html b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-007.html
new file mode 100644
index 0000000000..1168b1d228
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-007.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="Tests the static position of inline-level absolute-positioned elements, with combinations of float, direction, and text-align." />
+<style>
+#container { position: relative; background: red; width: 100px; height: 100px; }
+#container > div { background: green; }
+#inflow { height: 50px; }
+#float { float: left; width: 50px; height: 50px; }
+#abs { display: inline; position: absolute; width: 50px; height: 50px; }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id=container style="direction: rtl; text-align: right;">
+ <div id=inflow></div>
+ <div id=float style="float: left;"></div>
+ <div id=abs style="transform: translateX(0%);"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-008.html b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-008.html
new file mode 100644
index 0000000000..e10a7e191d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-008.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="Tests the static position of inline-level absolute-positioned elements, with combinations of float, direction, and text-align." />
+<style>
+#container { position: relative; background: red; width: 100px; height: 100px; }
+#container > div { background: green; }
+#inflow { height: 50px; }
+#float { float: left; width: 50px; height: 50px; }
+#abs { display: inline; position: absolute; width: 50px; height: 50px; }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id=container style="direction: rtl; text-align: center;">
+ <div id=inflow></div>
+ <div id=float style="float: left;"></div>
+ <div id=abs style="transform: translateX(50%);"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-009.html b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-009.html
new file mode 100644
index 0000000000..86102fa1d9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-009.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="Tests the static position of inline-level absolute-positioned elements, with combinations of float, direction, and text-align." />
+<style>
+#container { position: relative; background: red; width: 100px; height: 100px; }
+#container > div { background: green; }
+#inflow { height: 50px; }
+#float { float: left; width: 50px; height: 50px; }
+#abs { display: inline; position: absolute; width: 50px; height: 50px; }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id=container style="direction: rtl; text-align: left;">
+ <div id=inflow></div>
+ <div id=float style="float: left;"></div>
+ <div id=abs style="transform: translateX(100%);"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-010.html b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-010.html
new file mode 100644
index 0000000000..95d43b9cfb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-010.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="Tests the static position of inline-level absolute-positioned elements, with combinations of float, direction, and text-align." />
+<style>
+#container { position: relative; background: red; width: 100px; height: 100px; }
+#container > div { background: green; }
+#inflow { height: 50px; }
+#float { float: left; width: 50px; height: 50px; }
+#abs { display: inline; position: absolute; width: 50px; height: 50px; }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id=container style="direction: rtl; text-align: right;">
+ <div id=inflow></div>
+ <div id=float style="float: right;"></div>
+ <div id=abs style="transform: translateX(0%);"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-011.html b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-011.html
new file mode 100644
index 0000000000..375566388e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-011.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="Tests the static position of inline-level absolute-positioned elements, with combinations of float, direction, and text-align." />
+<style>
+#container { position: relative; background: red; width: 100px; height: 100px; }
+#container > div { background: green; }
+#inflow { height: 50px; }
+#float { float: left; width: 50px; height: 50px; }
+#abs { display: inline; position: absolute; width: 50px; height: 50px; }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id=container style="direction: rtl; text-align: center;">
+ <div id=inflow></div>
+ <div id=float style="float: right;"></div>
+ <div id=abs style="transform: translateX(50%);"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-012.html b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-012.html
new file mode 100644
index 0000000000..1972317822
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-012.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="../../reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="Tests the static position of inline-level absolute-positioned elements, with combinations of float, direction, and text-align." />
+<style>
+#container { position: relative; background: red; width: 100px; height: 100px; }
+#container > div { background: green; }
+#inflow { height: 50px; }
+#float { float: left; width: 50px; height: 50px; }
+#abs { display: inline; position: absolute; width: 50px; height: 50px; }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id=container style="direction: rtl; text-align: left;">
+ <div id=inflow></div>
+ <div id=float style="float: right;"></div>
+ <div id=abs style="transform: translateX(100%);"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-013.html b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-013.html
new file mode 100644
index 0000000000..59541dd679
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-013.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/982403" />
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="Tests the static position of an inline-level absolute-positioned element." />
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="overflow: hidden;">
+ <div style="float: left; width: 100px; height: 50px; background: green;"></div>
+ <div style="clear: both; width: 100px; height: 50px; background: red;">
+ <div style="position: absolute; display: inline; width: 100px; height: 50px; background: green;"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-014.html b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-014.html
new file mode 100644
index 0000000000..69416c1cd7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/inline-level-absolute-in-block-level-context-014.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/982403" />
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="Tests the static position of an inline-level absolute-positioned element." />
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="overflow: hidden;">
+ <div style="float: left; width: 100px; height: 50px; background: green;"></div>
+ <div style="clear: both; width: 100px; height: 50px; background: red;">
+ <div></div>
+ <div style="position: absolute; display: inline; width: 100px; height: 50px; background: green;"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/vlr-ltr-ltr.html b/testing/web-platform/tests/css/css-position/static-position/vlr-ltr-ltr.html
new file mode 100644
index 0000000000..992bb720f4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/vlr-ltr-ltr.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vlr-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+body { writing-mode: vertical-lr; }
+.container {
+ position: relative;
+ background: green;
+ color: green;
+ font: 16px/1 Ahem;
+ border: solid black 3px;
+ height: 400px;
+ margin: 0 16px;
+ padding: 2px;
+}
+.red { color: red; }
+.cb {
+ position: relative;
+ inset-block-start: 2px;
+ inset-inline-start: 2px;
+}
+.rtl { direction: rtl; }
+.ltr { direction: ltr; }
+.inline { display: inline; }
+.abs { position: absolute; }
+
+.indent { text-indent: 20px; }
+* { text-indent: initial; }
+</style>
+
+There should be no red.
+<div class="container ltr">
+ XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ XXX<span class="ltr cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="ltr cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ XXX<span class="ltr cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="ltr cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container ltr indent">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container ltr">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container ltr indent">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/vlr-ltr-rtl.tentative.html b/testing/web-platform/tests/css/css-position/static-position/vlr-ltr-rtl.tentative.html
new file mode 100644
index 0000000000..9491fb89a2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/vlr-ltr-rtl.tentative.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vlr-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+body { writing-mode: vertical-lr; }
+.container {
+ position: relative;
+ background: green;
+ color: green;
+ font: 16px/1 Ahem;
+ border: solid black 3px;
+ height: 400px;
+ margin: 0 16px;
+ padding: 2px;
+}
+.red { color: red; }
+.cb {
+ position: relative;
+ inset-block-start: 2px;
+ inset-inline-start: 2px;
+}
+.rtl { direction: rtl; }
+.ltr { direction: ltr; }
+.inline { display: inline; }
+.abs { position: absolute; }
+
+.indent { text-indent: 20px; }
+* { text-indent: initial; }
+</style>
+
+There should be no red.
+<div class="container ltr">
+ XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ XXX<span class="rtl cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="rtl cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ XXX<span class="rtl cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="rtl cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container ltr indent">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container ltr">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container ltr indent">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/vlr-ref.html b/testing/web-platform/tests/css/css-position/static-position/vlr-ref.html
new file mode 100644
index 0000000000..2ab92decd3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/vlr-ref.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<style>
+body { writing-mode: vertical-lr; }
+.container {
+ background: green;
+ width: 16px;
+ border: solid black 3px;
+ height: 400px;
+ margin: 0 16px;
+ padding: 2px;
+}
+
+.large { width: 32px; }
+</style>
+
+There should be no red.
+<div class="container"></div>
+
+<div class="container"></div>
+
+<div class="container large"></div>
+
+<div class="container large"></div>
+
+<div class="container"></div>
+
+<div class="container"></div>
+
+<div class="container large"></div>
+
+<div class="container large"></div>
+
+<div class="container"></div>
+
+<div class="container"></div>
+
+<div class="container large"></div>
+
+<div class="container large"></div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/vlr-rtl-ltr.tentative.html b/testing/web-platform/tests/css/css-position/static-position/vlr-rtl-ltr.tentative.html
new file mode 100644
index 0000000000..e334ff74b8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/vlr-rtl-ltr.tentative.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vlr-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+body { writing-mode: vertical-lr; }
+.container {
+ position: relative;
+ background: green;
+ color: green;
+ font: 16px/1 Ahem;
+ border: solid black 3px;
+ height: 400px;
+ margin: 0 16px;
+ padding: 2px;
+}
+.red { color: red; }
+.cb {
+ position: relative;
+ inset-block-start: 2px;
+ inset-inline-start: 2px;
+}
+.rtl { direction: rtl; }
+.ltr { direction: ltr; }
+.inline { display: inline; }
+.abs { position: absolute; }
+
+.indent { text-indent: 20px; }
+* { text-indent: initial; }
+</style>
+
+There should be no red.
+<div class="container rtl">
+ XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ XXX<span class="ltr cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="ltr cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ XXX<span class="ltr cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="ltr cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container rtl indent">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container rtl">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container rtl indent">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/vlr-rtl-rtl.html b/testing/web-platform/tests/css/css-position/static-position/vlr-rtl-rtl.html
new file mode 100644
index 0000000000..45c8aa3c26
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/vlr-rtl-rtl.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vlr-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+body { writing-mode: vertical-lr; }
+.container {
+ position: relative;
+ background: green;
+ color: green;
+ font: 16px/1 Ahem;
+ border: solid black 3px;
+ height: 400px;
+ margin: 0 16px;
+ padding: 2px;
+}
+.red { color: red; }
+.cb {
+ position: relative;
+ inset-block-start: 2px;
+ inset-inline-start: 2px;
+}
+.rtl { direction: rtl; }
+.ltr { direction: ltr; }
+.inline { display: inline; }
+.abs { position: absolute; }
+
+.indent { text-indent: 20px; }
+* { text-indent: initial; }
+</style>
+
+There should be no red.
+<div class="container rtl">
+ XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ XXX<span class="rtl cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="rtl cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ XXX<span class="rtl cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="rtl cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container rtl indent">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container rtl">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container rtl indent">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/vrl-ltr-ltr.html b/testing/web-platform/tests/css/css-position/static-position/vrl-ltr-ltr.html
new file mode 100644
index 0000000000..9e3c1306ab
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/vrl-ltr-ltr.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vrl-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+body { writing-mode: vertical-rl; }
+.container {
+ position: relative;
+ background: green;
+ color: green;
+ font: 16px/1 Ahem;
+ border: solid black 3px;
+ height: 400px;
+ margin: 0 16px;
+ padding: 2px;
+}
+.red { color: red; }
+.cb {
+ position: relative;
+ inset-block-start: 2px;
+ inset-inline-start: 2px;
+}
+.rtl { direction: rtl; }
+.ltr { direction: ltr; }
+.inline { display: inline; }
+.abs { position: absolute; }
+
+.indent { text-indent: 20px; }
+* { text-indent: initial; }
+</style>
+
+There should be no red.
+<div class="container ltr">
+ XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ XXX<span class="ltr cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="ltr cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ XXX<span class="ltr cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="ltr cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container ltr indent">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container ltr">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container ltr indent">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/vrl-ltr-rtl.tentative.html b/testing/web-platform/tests/css/css-position/static-position/vrl-ltr-rtl.tentative.html
new file mode 100644
index 0000000000..a0923f3b48
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/vrl-ltr-rtl.tentative.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vrl-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+body { writing-mode: vertical-rl; }
+.container {
+ position: relative;
+ background: green;
+ color: green;
+ font: 16px/1 Ahem;
+ border: solid black 3px;
+ height: 400px;
+ margin: 0 16px;
+ padding: 2px;
+}
+.red { color: red; }
+.cb {
+ position: relative;
+ inset-block-start: 2px;
+ inset-inline-start: 2px;
+}
+.rtl { direction: rtl; }
+.ltr { direction: ltr; }
+.inline { display: inline; }
+.abs { position: absolute; }
+
+.indent { text-indent: 20px; }
+* { text-indent: initial; }
+</style>
+
+There should be no red.
+<div class="container ltr">
+ XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ XXX<span class="rtl cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="rtl cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ XXX<span class="rtl cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr indent">
+ XXX<span class="rtl cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container ltr">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container ltr indent">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container ltr">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container ltr indent">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/vrl-ref.html b/testing/web-platform/tests/css/css-position/static-position/vrl-ref.html
new file mode 100644
index 0000000000..5e607dbb86
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/vrl-ref.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<style>
+body { writing-mode: vertical-rl; }
+.container {
+ background: green;
+ width: 16px;
+ border: solid black 3px;
+ height: 400px;
+ margin: 0 16px;
+ padding: 2px;
+}
+
+.large { width: 32px; }
+</style>
+
+There should be no red.
+<div class="container"></div>
+
+<div class="container"></div>
+
+<div class="container large"></div>
+
+<div class="container large"></div>
+
+<div class="container"></div>
+
+<div class="container"></div>
+
+<div class="container large"></div>
+
+<div class="container large"></div>
+
+<div class="container"></div>
+
+<div class="container"></div>
+
+<div class="container large"></div>
+
+<div class="container large"></div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/vrl-rtl-ltr.tentative.html b/testing/web-platform/tests/css/css-position/static-position/vrl-rtl-ltr.tentative.html
new file mode 100644
index 0000000000..29ae6a5f98
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/vrl-rtl-ltr.tentative.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vrl-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+body { writing-mode: vertical-rl; }
+.container {
+ position: relative;
+ background: green;
+ color: green;
+ font: 16px/1 Ahem;
+ border: solid black 3px;
+ height: 400px;
+ margin: 0 16px;
+ padding: 2px;
+}
+.red { color: red; }
+.cb {
+ position: relative;
+ inset-block-start: 2px;
+ inset-inline-start: 2px;
+}
+.rtl { direction: rtl; }
+.ltr { direction: ltr; }
+.inline { display: inline; }
+.abs { position: absolute; }
+
+.indent { text-indent: 20px; }
+* { text-indent: initial; }
+</style>
+
+There should be no red.
+<div class="container rtl">
+ XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ XXX<span class="ltr cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="ltr cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ XXX<span class="ltr cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="ltr cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container rtl indent">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container rtl">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container rtl indent">
+ <span class="cb">XXX<span class="ltr">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/static-position/vrl-rtl-rtl.html b/testing/web-platform/tests/css/css-position/static-position/vrl-rtl-rtl.html
new file mode 100644
index 0000000000..cfb4118718
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/static-position/vrl-rtl-rtl.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width" />
+<link rel="match" href="vrl-ref.html">
+<meta name="assert" content="This test checks the static position of an out of flow absolute positioned element, under various conditions." />
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+body { writing-mode: vertical-rl; }
+.container {
+ position: relative;
+ background: green;
+ color: green;
+ font: 16px/1 Ahem;
+ border: solid black 3px;
+ height: 400px;
+ margin: 0 16px;
+ padding: 2px;
+}
+.red { color: red; }
+.cb {
+ position: relative;
+ inset-block-start: 2px;
+ inset-inline-start: 2px;
+}
+.rtl { direction: rtl; }
+.ltr { direction: ltr; }
+.inline { display: inline; }
+.abs { position: absolute; }
+
+.indent { text-indent: 20px; }
+* { text-indent: initial; }
+</style>
+
+There should be no red.
+<div class="container rtl">
+ XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ XXX<span class="rtl cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="rtl cb">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ XXX<span class="rtl cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl indent">
+ XXX<span class="rtl cb">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span>
+</div>
+
+<div class="container rtl">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container rtl indent">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs inline">XXXXX</div><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container rtl">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
+
+<div class="container rtl indent">
+ <span class="cb">XXX<span class="rtl">XX<div class="abs block">XXXXX</div><br><span class="red">XXXXX</span></span></span>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-bottom-002.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-bottom-002.html
new file mode 100644
index 0000000000..980de2e651
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-bottom-002.html
@@ -0,0 +1,121 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Position Test: sticky element with bottom offset specified with px unit</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos">
+ <link rel="match" href="reference/position-sticky-bottom-002-ref.html">
+
+ <meta name="flags" content="">
+
+ <style>
+ div.scrolling-container
+ {
+ background-image: url("support/100x100-red.png");
+ background-repeat: no-repeat;
+ display: inline-block;
+ height: 250px;
+ margin-right: 30px;
+ overflow: auto;
+ position: static;
+ width: 150px;
+ }
+
+ div#first-scrolling-container
+ {
+ background-position: left 75px;
+ }
+
+ div#second-scrolling-container
+ {
+ background-position: left 50px;
+ }
+
+ div#third-scrolling-container
+ {
+ background-position: left top;
+ }
+
+ div.vertical-spacer
+ {
+ height: 100px;
+ }
+
+ div.sticky
+ {
+ background-color: green;
+ bottom: 100px;
+ height: 100px;
+ position: sticky;
+ width: 100px;
+ }
+ </style>
+
+ <body onload="document.getElementById(&quot;first-scrolling-container&quot;).scrollTop = 25; document.getElementById(&quot;second-scrolling-container&quot;).scrollTop = 100; document.getElementById(&quot;third-scrolling-container&quot;).scrollTop = 200;">
+
+ <p>Test passes if there are 3 filled green squares and <strong>no red</strong>.
+
+ <!--
+ first-scrolling-container: before reaching the sticking point
+ -->
+
+ <div id="first-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div class="content">
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div id="first-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
+
+ <!--
+ second-scrolling-container: when reaching the sticking point and beyond
+ -->
+
+ <div id="second-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div class="content">
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div id="second-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
+
+
+ <div id="third-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div class="content">
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div id="third-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-bottom-003.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-bottom-003.html
new file mode 100644
index 0000000000..649dfc9d36
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-bottom-003.html
@@ -0,0 +1,121 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Position Test: sticky element with bottom offset specified with percentage unit</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos">
+ <link rel="match" href="reference/position-sticky-bottom-002-ref.html">
+
+ <meta name="flags" content="">
+
+ <style>
+ div.scrolling-container
+ {
+ background-image: url("support/100x100-red.png");
+ background-repeat: no-repeat;
+ display: inline-block;
+ height: 250px;
+ margin-right: 30px;
+ overflow: auto;
+ position: static;
+ width: 150px;
+ }
+
+ div#first-scrolling-container
+ {
+ background-position: left 75px;
+ }
+
+ div#second-scrolling-container
+ {
+ background-position: left 50px;
+ }
+
+ div#third-scrolling-container
+ {
+ background-position: left top;
+ }
+
+ div.vertical-spacer
+ {
+ height: 100px;
+ }
+
+ div.sticky
+ {
+ background-color: green;
+ bottom: 40%;
+ height: 100px;
+ position: sticky;
+ width: 100px;
+ }
+ </style>
+
+ <body onload="document.getElementById(&quot;first-scrolling-container&quot;).scrollTop = 25; document.getElementById(&quot;second-scrolling-container&quot;).scrollTop = 100; document.getElementById(&quot;third-scrolling-container&quot;).scrollTop = 200;">
+
+ <p>Test passes if there are 3 filled green squares and <strong>no red</strong>.
+
+ <!--
+ first-scrolling-container: before reaching the sticking point
+ -->
+
+ <div id="first-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div class="content">
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div id="first-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
+
+ <!--
+ second-scrolling-container: when reaching the sticking point and beyond
+ -->
+
+ <div id="second-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div class="content">
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div id="second-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
+
+
+ <div id="third-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div class="content">
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div id="third-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-bottom.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-bottom.html
new file mode 100644
index 0000000000..9cfae6d3ba
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-bottom.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<title>position:sticky elements should respect the bottom constraint</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that position:sticky elements obey their bottom anchor after scrolling" />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script src="../resources/sticky-util.js"></script>
+
+<body></body>
+
+<script>
+test(() => {
+ const elements = setupStickyTest('bottom', 25);
+ elements.scroller.scrollTop = 300;
+ const nonStickyTopY = elements.container.offsetTop +
+ elements.filler.clientHeight;
+ assert_equals(elements.sticky.offsetTop, nonStickyTopY);
+}, 'before reaching the sticking point the sticky box should not be offset');
+
+test(() => {
+ const elements = setupStickyTest('bottom', 25);
+ elements.scroller.scrollTop = 100;
+
+ const nonStickyTopY = elements.container.offsetTop +
+ elements.filler.clientHeight;
+ const nonStickyBottomY = nonStickyTopY + elements.sticky.clientHeight;
+ const targetBottomY = elements.scroller.clientHeight +
+ elements.scroller.scrollTop - 25;
+ const stickyOffset = nonStickyBottomY - targetBottomY;
+
+ assert_equals(elements.sticky.offsetTop, nonStickyTopY - stickyOffset);
+}, 'after reaching the sticking point the sticky box should be offset');
+
+test(() => {
+ const elements = setupStickyTest('bottom', 25);
+ elements.scroller.scrollTop = 0;
+ assert_equals(elements.sticky.offsetTop, elements.container.offsetTop);
+}, 'the sticky box should not be pushed outside its containing block');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-change-top-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-change-top-ref.html
new file mode 100644
index 0000000000..8ccc1548ef
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-change-top-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<title>Reference for sticky elements should invalidate when top/left/bottom/right changes</title>
+
+<style>
+.box {
+ /* Triggers promotion without creating stacking context. */
+ backface-visibility: hidden;
+ background: green;
+ position: sticky;
+ top: 200px;
+ width: 100px;
+ height: 100px;
+}
+
+.spacer {
+ height: 200vh;
+}
+</style>
+
+<div class="box"></div>
+<div class="spacer"></div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-change-top.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-change-top.html
new file mode 100644
index 0000000000..6a327ccd56
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-change-top.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+<title>Sticky elements should invalidate when top/left/bottom/right changes</title>
+<link rel="match" href="position-sticky-change-top-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<link rel="help" href="https://crbug.com/939632">
+<meta name="assert" content="This test checks that sticky elements are invalidated correctly when top/left/bottom/right change "/>
+
+<script src="/common/reftest-wait.js"></script>
+<script src="../resources/ref-rectangle.js"></script>
+
+<!--
+ It is important for this test that the sticky element is viewport-bound, and
+ that multiple animation frames pass before changing the style.
+-->
+<style>
+.marker {
+ background: red;
+ position: absolute;
+ top: 200px;
+ height: 100px;
+ width: 100px;
+}
+
+.sticky {
+ /* Triggers promotion without creating stacking context. */
+ backface-visibility: hidden;
+ background: green;
+ position: sticky;
+ top: 0;
+ width: 100px;
+ height: 100px;
+}
+
+.spacer {
+ height: 200vh;
+}
+</style>
+<div class="marker"></div>
+
+<div class="sticky"></div>
+<div class="spacer"></div>
+
+<script>
+requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ document.querySelector('.sticky').style.setProperty('top', '200px');
+ createIndicatorForStickyElements(document.querySelectorAll('.sticky'));
+ takeScreenshot();
+ });
+});
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-child-multicolumn-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-child-multicolumn-ref.html
new file mode 100644
index 0000000000..ccbeaa8ca7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-child-multicolumn-ref.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<title>Reference for multicolumn under position:sticky should be positioned correctly</title>
+<style>
+ body {
+ margin: 0;
+ }
+ #scroller {
+ overflow-y: scroll;
+ width: 200px;
+ height: 200px;
+ }
+ #relative {
+ position: relative;
+ top: 100px;
+ margin: 10px;
+ }
+ #child {
+ width: 100px;
+ height: 100px;
+ background: green;
+ }
+ #contents {
+ position: relative;
+ top: 10%;
+ left: 10%;
+ width: 80%;
+ height: 80%;
+ background: lightgreen;
+ }
+ #spacer {
+ height: 400px;
+ }
+</style>
+
+<div id="scroller">
+ <div id="relative">
+ <div id="child">
+ <div id="contents"></div>
+ </div>
+ </div>
+ <div id="spacer"></div>
+</div>
+
+<div>You should see a light green box above with a dark green border, no blue should be visible.</div>
+
+<script>
+ window.addEventListener('load', function() {
+ scroller.scrollTop = 100;
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-child-multicolumn.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-child-multicolumn.html
new file mode 100644
index 0000000000..14bb695f1a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-child-multicolumn.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<title>Multicolumn under position:sticky should be positioned correctly</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<link rel="match" href="position-sticky-child-multicolumn-ref.html" />
+<link rel="author" title="Philip Rogers" href="mailto:pdr@chromium.org" />
+<meta name="assert" content="This test checks that a multicolumn element is positioned relative to a sticky position" />
+
+<script src="../resources/ref-rectangle.js"></script>
+
+<style>
+ body {
+ margin: 0;
+ }
+ #scroller {
+ overflow-y: scroll;
+ width: 200px;
+ height: 200px;
+ }
+ #sticky {
+ position: sticky;
+ top: 10px;
+ margin: 10px;
+ }
+ #multicolumn {
+ width: 100px;
+ height: 100px;
+ background: green;
+ columns: 1;
+ }
+ #contents {
+ margin-left: 10%;
+ margin-top: 10%;
+ width: 80%;
+ height: 80%;
+ background: lightgreen;
+ }
+ #spacer {
+ height: 400px;
+ }
+</style>
+
+<div id="scroller">
+ <div id="sticky">
+ <div id="multicolumn">
+ <div id="contents"></div>
+ </div>
+ </div>
+ <div id="spacer"></div>
+</div>
+
+<div>You should see a light green box above with a dark green border, no blue should be visible.</div>
+
+<script>
+ window.addEventListener('load', function() {
+ scroller.scrollTop = 100;
+ createIndicatorForStickyElements(document.querySelectorAll('.sticky'));
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-contained-by-display-table-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-contained-by-display-table-ref.html
new file mode 100644
index 0000000000..32115516ef
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-contained-by-display-table-ref.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<title>position:sticky should work for elements with display: table* containing blocks</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that position:sticky works for elements with containing blocks that have display: table*" />
+
+<style>
+.group {
+ display: inline-block;
+}
+
+.container {
+ height: 1000px;
+ width: 50px;
+ margin-right: 10px;
+}
+
+.scroll-container {
+ height: 300px;
+ width: 500px;
+ overflow: hidden;
+}
+
+.sticky {
+ height: 50px;
+ width: 50px;
+ background: green;
+}
+</style>
+
+<div class="scroll-container">
+ <div class="group">
+ <div class="container" style="display: table-cell;">
+ <div class="sticky"></div>
+ </div>
+ </div>
+
+ <div class="group">
+ <div class="container" style="display: table-row;">
+ <div class="sticky"></div>
+ </div>
+ </div>
+
+ <div class="group">
+ <div class="container" style="display: table;">
+ <div class="sticky"></div>
+ </div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-contained-by-display-table.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-contained-by-display-table.html
new file mode 100644
index 0000000000..e9c016e938
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-contained-by-display-table.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<title>position:sticky should work for elements with display: table* containing blocks</title>
+<link rel="match" href="position-sticky-contained-by-display-table-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that position:sticky works for elements with containing blocks that have display: table*" />
+
+<style>
+.group {
+ display: inline-block;
+}
+
+.container {
+ height: 1000px;
+ width: 50px;
+ margin-right: 10px;
+}
+
+#scroll-container {
+ height: 300px;
+ width: 500px;
+ overflow: hidden;
+ position: relative;
+}
+
+.sticky {
+ position: sticky;
+ height: 50px;
+ width: 50px;
+ background: green;
+ top: 0;
+}
+
+#scroll-indicator {
+ display: inline-block;
+ position: absolute;
+ top: 0px;
+ width: 300px;
+ height: 50px;
+ background: red;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroll-container').scrollTop = 300;
+});
+</script>
+
+
+<div id="scroll-container">
+ <div class="group">
+ <div class="container" style="display: table-cell;">
+ <div class="sticky"></div>
+ </div>
+ </div>
+
+ <div class="group">
+ <div class="container" style="display: table-row;">
+ <div class="sticky"></div>
+ </div>
+ </div>
+
+ <div class="group">
+ <div class="container" style="display: table;">
+ <div class="sticky"></div>
+ </div>
+ </div>
+
+ <!-- This is here to validate that the container does scroll. -->
+ <div id="scroll-indicator" style=""></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-details-crash.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-details-crash.html
new file mode 100644
index 0000000000..65b7ea4880
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-details-crash.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1470149">
+<details>
+ <div id="target" style="position: sticky; top: 0px;"></div>
+</details>
+<script>
+document.execCommand('selectAll');
+document.getElementById('target').remove();
+document.body.style.height = '100%';
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-001-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-001-ref.html
new file mode 100644
index 0000000000..0d760d18dc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-001-ref.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<div style="width: 200px; height: 200px; background: green"></div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-001.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-001.html
new file mode 100644
index 0000000000..dd58327388
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-001.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<title>CSS Positioned Layout Test: a sticky element contained by fixed under a scroller not containing fixed</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos">
+<link rel="help" href="https://crbug.com/881555">
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3185">
+<link rel="match" href="position-sticky-escape-scroller-001-ref.html">
+<div id="scroller" style="width: 200px; height: 100px; overflow: hidden">
+ <div style="height: 100px; background: red"></div>
+ <div style="position: fixed; height: 400px">
+ <div style="position: sticky; top: 0; width: 200px; height: 100px; background: green"></div>
+ </div>
+ <div style="height: 100px; background: red"></div>
+ <div style="height: 100px; background: green"></div>
+ <div style="height: 1000px; background: red"></div>
+</div>
+<script>
+scroller.scrollTop = 200;
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-002-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-002-ref.html
new file mode 100644
index 0000000000..2fa0a2a9ed
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-002-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<style>body { margin: 0 }</style>
+<div style="height: 3200px"></div>
+<div style="position: fixed; top: 100px; left: 0;
+ width: 200px; height: 200px; background: green"></div>
+<script>
+window.scrollTo(0, 2000);
+</script>
+
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-002.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-002.html
new file mode 100644
index 0000000000..225012b9ec
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-002.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>CSS Positioned Layout Test: a sticky element contained by fixed under a scroller not containing fixed</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos">
+<link rel="help" href="https://crbug.com/881555">
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3185">
+<link rel="match" href="position-sticky-escape-scroller-002-ref.html">
+<style>body { margin: 0 }</style>
+<div id="scroller" style="width: 200px; height: 200px; overflow: scroll">
+ <div style="position: fixed; top: 100px; height: 2000px">
+ <div style="position: sticky; top: 0; width: 200px; height: 200px; background: green"></div>
+ </div>
+ <div style="height: 1000px; background: red"></div>
+</div>
+<div style="height: 3000px"></div>
+<script>
+window.scrollTo(0, 2000);
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-003.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-003.html
new file mode 100644
index 0000000000..434b279705
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-003.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<title>CSS Positioned Layout Test: a sticky element contained by absolute under a scroller not containing absolute</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos">
+<link rel="help" href="https://crbug.com/881555">
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3185">
+<link rel="match" href="position-sticky-escape-scroller-001-ref.html">
+<div id="scroller" style="width: 200px; height: 100px; overflow: hidden">
+ <div style="height: 100px; background: red"></div>
+ <div style="position: absolute; height: 400px">
+ <div style="position: sticky; top: 0; width: 200px; height: 100px; background: green"></div>
+ </div>
+ <div style="height: 100px; background: red"></div>
+ <div style="height: 100px; background: green"></div>
+ <div style="height: 1000px; background: red"></div>
+</div>
+<script>
+scroller.scrollTop = 200;
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-004-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-004-ref.html
new file mode 100644
index 0000000000..fa9f2b7dc0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-004-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<style>body { margin: 0 }</style>
+<div style="height: 3200px"></div>
+<div style="position: fixed; top: 0; left: 0;
+ width: 200px; height: 200px; background: green"></div>
+<script>
+window.scrollTo(0, 1000);
+</script>
+
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-004.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-004.html
new file mode 100644
index 0000000000..ed14d62ac4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-escape-scroller-004.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>CSS Positioned Layout Test: a sticky element contained by absolute under a scroller not containing absolute</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos">
+<link rel="help" href="https://crbug.com/881555">
+<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3185">
+<link rel="match" href="position-sticky-escape-scroller-004-ref.html">
+<style>body { margin: 0 }</style>
+<div id="scroller" style="width: 200px; height: 200px; overflow: scroll">
+ <div style="position: absolute; top: 100px; height: 2000px">
+ <div style="position: sticky; top: 0; width: 200px; height: 200px; background: green"></div>
+ </div>
+ <div style="height: 1000px; background: red"></div>
+</div>
+<div style="height: 3000px"></div>
+<script>
+window.scrollTo(0, 1000);
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor-002.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor-002.html
new file mode 100644
index 0000000000..dc3c383ea5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor-002.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Positioned Layout Test: a sticky element inside a fixed ancestor</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="match" href="reference/position-sticky-fixed-ancestor-002-ref.html">
+ <link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos">
+
+ <meta name="flags" content="">
+
+ <style>
+ html, body, div
+ {
+ height: 100%;
+ margin: 0;
+ width: 100%;
+ }
+
+ div#positioned-container
+ {
+ background-color: red;
+ color: yellow;
+ font-size: 40vh;
+ position: absolute;
+ }
+
+ div#sticky
+ {
+ background-color: green;
+ bottom: 0;
+ color: white;
+ position: sticky;
+ }
+ </style>
+
+ <script type="text/javascript">
+ function startTest()
+ {
+ document.getElementById("positioned-container").style.position = "fixed";
+ }
+ </script>
+
+ <body onload="startTest();">
+
+ <div id="positioned-container">
+
+ <div id="vertical-spacer">FAIL</div>
+
+ <div id="sticky">PASS</div>
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor-003.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor-003.html
new file mode 100644
index 0000000000..382112cae4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor-003.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Positioned Layout Test: a sticky element inside a fixed ancestor</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="match" href="reference/position-sticky-fixed-ancestor-002-ref.html">
+ <link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos">
+
+ <meta name="flags" content="">
+
+ <style>
+ html, body, div
+ {
+ height: 100%;
+ margin: 0;
+ width: 100%;
+ }
+
+ div#fixed-container
+ {
+ background-color: red;
+ color: yellow;
+ font-size: 40vh;
+ position: fixed;
+ }
+
+ div#sticky
+ {
+ background-color: green;
+ bottom: 0;
+ color: white;
+ position: sticky;
+ }
+ </style>
+
+ <div id="fixed-container">
+
+ <div id="vertical-spacer">FAIL</div>
+
+ <div id="sticky">PASS</div>
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor-iframe-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor-iframe-ref.html
new file mode 100644
index 0000000000..37372ceca1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor-iframe-ref.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<title>Sticky elements inside fixed ancestors and iframe shouldn't account for scroll</title>
+
+<style>
+ body,html {
+ margin: 0;
+ width: 100%;
+ height: 100%;
+ }
+
+ iframe {
+ margin: 10px;
+ width: 90%;
+ height: 90%;
+ border: 1px solid black;
+ }
+
+ .spacer {
+ height: 120vh;
+ }
+</style>
+
+<div class="spacer"></div>
+<iframe srcdoc="
+ <!DOCTYPE html>
+ <title>Reference for sticky elements inside fixed ancestors shouldn't account for scroll</title>
+ <style>
+ body,html {
+ margin: 0;
+ width: 100%;
+ height: 100%;
+ }
+
+ .sticky {
+ background: green;
+ width: 100px;
+ height: 10%;
+ }
+
+ .spacer {
+ height: calc(25vh - 10%);
+ }
+ .long {
+ height: 600vh;
+ }
+
+ .position-parent {
+ position: absolute;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: 100%;
+ top: 100vh;
+ background-color: lightgrey;
+ }
+
+ .container {
+ width: 100px;
+ height: 100%;
+ background-color: grey;
+ }
+
+ button {
+ position: fixed;
+ left: 20px;
+ top: 20px;
+ }
+
+ .fixed {
+ position: fixed;
+ top: 25vh;
+ }
+ </style>
+
+ <div class='position-parent fixed'>
+ <div class='container'>
+ <div class='spacer'></div>
+ <div class='sticky'></div>
+ </div>
+ </div>
+ <div class='long'></div>
+ <button id='button'>Toggle Fixed</button>
+ <script>
+ window.scrollTo(0, document.querySelector('.long').clientHeight);
+ </script>
+"></iframe>
+<div class="spacer"></div>
+
+<script>
+ const child = document.querySelector('iframe');
+ child.scrollIntoView();
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor-iframe.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor-iframe.html
new file mode 100644
index 0000000000..e50f5c829b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor-iframe.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+<title>Sticky elements inside fixed ancestors and iframe shouldn't account for scroll</title>
+<link rel="match" href="position-sticky-fixed-ancestor-iframe-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<link rel="help" href="https://crbug.com/1019142">
+<meta name="assert" content="This test checks that a sticky element inside a fixed subtree and iframe doesn't scroll with the viewport "/>
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+ body,html {
+ margin: 0;
+ width: 100%;
+ height: 100%;
+ }
+
+ iframe {
+ margin: 10px;
+ width: 90%;
+ height: 90%;
+ border: 1px solid black;
+ }
+
+ .spacer {
+ height: 120vh;
+ }
+</style>
+
+<div class="spacer"></div>
+<iframe src="../resources/position-sticky-fixed-ancestor-iframe-child.html"></iframe>
+<div class="spacer"></div>
+
+<script>
+ const child = document.querySelector('iframe');
+ child.scrollIntoView();
+ window.onload = () => {
+ const childDoc = child.contentDocument;
+ function toggleFixed() {
+ childDoc.querySelector('.position-parent').classList.toggle('fixed');
+ }
+
+ childDoc.getElementById('button').addEventListener('click', toggleFixed);
+
+ requestAnimationFrame(() => {
+ childDoc.scrollingElement.scrollTop = childDoc.querySelector('.long').clientHeight;
+ requestAnimationFrame(() => {
+ toggleFixed();
+ takeScreenshot();
+ });
+ });
+ };
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor-ref.html
new file mode 100644
index 0000000000..fe404b5bab
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor-ref.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<title>Reference for sticky elements inside fixed ancestors shouldn't account for scroll</title>
+<style>
+ body,html {
+ margin: 0;
+ width: 100%;
+ height: 100%;
+ }
+
+ .sticky {
+ background: green;
+ width: 100px;
+ height: 10%;
+ }
+
+ .spacer {
+ height: calc(25vh - 10%);
+ }
+ .long {
+ height: 600vh;
+ }
+
+ .position-parent {
+ position: absolute;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: 100%;
+ top: 100vh;
+ background-color: lightgrey;
+ }
+
+ .container {
+ width: 100px;
+ height: 100%;
+ background-color: grey;
+ }
+
+ button {
+ position: fixed;
+ left: 20px;
+ top: 20px;
+ }
+
+ .fixed {
+ position: fixed;
+ top: 25vh;
+ }
+</style>
+
+<div>You should see a green box below. No blue should be visible.</div>
+<div class="position-parent fixed">
+ <div class="container">
+ <div class="spacer"></div>
+ <div class="sticky"></div>
+ </div>
+</div>
+<div class="long"></div>
+<button id="button">Toggle Fixed</button>
+
+<script>
+ window.scrollTo(0, document.querySelector('.long').clientHeight);
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor.html
new file mode 100644
index 0000000000..52760992b1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-fixed-ancestor.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<html class='reftest-wait'>
+<title>Sticky elements inside fixed ancestors shouldn't account for scroll</title>
+<link rel="match" href="position-sticky-fixed-ancestor-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<link rel="help" href="https://crbug.com/1019142">
+<meta name="assert" content="This test checks that a sticky element inside a fixed subtree doesn't scroll with the viewport "/>
+
+<script src="/common/reftest-wait.js"></script>
+<script src="../resources/ref-rectangle.js"></script>
+
+
+<style>
+ body,html {
+ margin: 0;
+ width: 100%;
+ height: 100%;
+ }
+
+ .sticky {
+ background: green;
+ position: sticky;
+ bottom: 50vh;
+ width: 100px;
+ height: 10%;
+ }
+
+ .spacer {
+ height: 90%;
+ }
+ .long {
+ height: 600vh;
+ }
+
+ .position-parent {
+ position: absolute;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: 100%;
+ top: 100vh;
+ background-color: lightgrey;
+ }
+
+ .container {
+ width: 100px;
+ height: 100%;
+ background-color: grey;
+ }
+
+ button {
+ position: fixed;
+ left: 20px;
+ top: 20px;
+ }
+
+ .fixed {
+ position: fixed;
+ top: 25vh;
+ }
+</style>
+
+<div>You should see a green box below. No blue should be visible.</div>
+<div class="position-parent">
+ <div class="container">
+ <div class="spacer"></div>
+ <div class="sticky"></div>
+ </div>
+</div>
+<div class="long"></div>
+<button id="button">Toggle Fixed</button>
+<script>
+ function toggleFixed() {
+ document.querySelector('.position-parent').classList.toggle('fixed');
+ }
+
+ document.getElementById('button').addEventListener('click', toggleFixed);
+
+ requestAnimationFrame(() => {
+ window.scrollTo(0, document.querySelector('.long').clientHeight);
+ createIndicatorForStickyElements(document.querySelectorAll('.sticky'));
+ requestAnimationFrame(() => {
+ toggleFixed();
+ takeScreenshot();
+ });
+ });
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-flex-item-001.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-flex-item-001.html
new file mode 100644
index 0000000000..1b1f9d0afb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-flex-item-001.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-position-3/#stickypos-insets">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1377072">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="This test verifies that the sticky flex item reserves its in-flow space in the scroll container's overflow area.">
+
+<style>
+#flex-scroller {
+ overflow: hidden;
+ inline-size: 100px;
+ block-size: 100px;
+ display: flex;
+ flex-direction: column;
+ background-color: green;
+}
+
+#non-sticky {
+ flex: 0 0 80px;
+ background-color: red;
+}
+
+#sticky {
+ position: sticky;
+ flex: 0 0 100px;
+ bottom: 0;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="flex-scroller">
+ <div id="non-sticky"></div>
+ <div id="sticky"></div>
+</div>
+
+<script>
+// Scroll the scroll container down to the bottom.
+document.getElementById("flex-scroller").scrollTop="1000";
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-flex-item-002.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-flex-item-002.html
new file mode 100644
index 0000000000..5b4c81df67
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-flex-item-002.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-position-3/#stickypos-insets">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1377072">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="This test verifies that the sticky flex item reserves its in-flow space in the scroll container's overflow area.">
+
+<style>
+#flex-scroller {
+ overflow: hidden;
+ inline-size: 100px;
+ block-size: 100px;
+ display: flex;
+ flex-direction: row;
+ background-color: green;
+}
+
+#non-sticky {
+ flex: 0 0 80px;
+ background-color: red;
+}
+
+#sticky {
+ position: sticky;
+ flex: 0 0 100px;
+ right: 0;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="flex-scroller">
+ <div id="non-sticky"></div>
+ <div id="sticky"></div>
+</div>
+
+<script>
+// Scroll the scroll container to the far right.
+document.getElementById("flex-scroller").scrollLeft="1000";
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-flex-item-003.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-flex-item-003.html
new file mode 100644
index 0000000000..50e0e25980
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-flex-item-003.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-position-3/#stickypos-insets">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1377072">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="This test verifies that the sticky flex item reserves its in-flow space in the scroll container's overflow area.">
+
+<style>
+#scroller {
+ overflow: hidden;
+ inline-size: 100px;
+ block-size: 100px;
+ background-color: green;
+}
+
+#flex {
+ display: flex;
+ flex-direction: column;
+
+ /* Use a small block-size so that the flex items overflow the flex container.
+ It's necessary to trigger the bug. */
+ block-size: 10px;
+}
+
+#non-sticky {
+ flex: 0 0 80px;
+ background-color: red;
+}
+
+#sticky {
+ position: sticky;
+ flex: 0 0 100px;
+ bottom: 0;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="scroller">
+ <div id="flex">
+ <div id="non-sticky"></div>
+ <div id="sticky"></div>
+ </div>
+</div>
+
+<script>
+// Scroll the scroll container down to the bottom.
+document.getElementById("scroller").scrollTop="1000";
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-flex-item-004.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-flex-item-004.html
new file mode 100644
index 0000000000..68b933a319
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-flex-item-004.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-position-3/#stickypos-insets">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1377072">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<meta name="assert" content="This test verifies that the sticky flex item reserves its in-flow space in the scroll container's overflow area.">
+
+<style>
+#scroller {
+ overflow: hidden;
+ inline-size: 100px;
+ block-size: 100px;
+ background-color: green;
+}
+
+#flex {
+ display: flex;
+ flex-direction: row;
+
+ /* Use a small inline-size so that the flex items overflow the flex container.
+ It's necessary to trigger the bug. */
+ inline-size: 10px;
+ block-size: 100px;
+}
+
+#non-sticky {
+ flex: 0 0 80px;
+ background-color: red;
+}
+
+#sticky {
+ position: sticky;
+ flex: 0 0 100px;
+ right: 0;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="scroller">
+ <div id="flex">
+ <div id="non-sticky"></div>
+ <div id="sticky"></div>
+ </div>
+</div>
+
+<script>
+// Scroll the scroll container to the far right.
+document.getElementById("scroller").scrollLeft="1000";
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-flexbox-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-flexbox-ref.html
new file mode 100644
index 0000000000..b78c784de1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-flexbox-ref.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<title>Reference for position:sticky elements should work correctly with flexbox</title>
+
+<style>
+.scroller {
+ overflow: scroll;
+ width: 350px;
+ height: 100px;
+ margin-bottom: 15px;
+}
+
+.flex-container {
+ width: 600px;
+ position: relative;
+ display: flex;
+ flex-flow: row wrap;
+}
+
+.green {
+ background-color: green;
+}
+
+.flex-item {
+ height: 85px;
+ width: 100px;
+ display: flex;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollLeft = 50;
+ document.getElementById('scroller2').scrollLeft = 150;
+ document.getElementById('scroller3').scrollLeft = 250;
+});
+</script>
+
+<p>You should see three green boxes of varying size below. There should be no red or blue.</p>
+
+<div id="scroller1" class="scroller">
+ <div class="flex-container">
+ <div class="flex-item"></div>
+ <div class="green flex-item"></div>
+ <div class="green flex-item"></div>
+ </div>
+</div>
+
+<div id="scroller2" class="scroller">
+ <div class="flex-container">
+ <div class="flex-item"></div>
+ <div class="flex-item"></div>
+ <div class="green flex-item"></div>
+ </div>
+</div>
+
+<div id="scroller3" class="scroller">
+ <div class="flex-container">
+ <div class="flex-item"></div>
+ <div class="flex-item"></div>
+ <div class="green flex-item"></div>
+ <div class="green flex-item"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-flexbox.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-flexbox.html
new file mode 100644
index 0000000000..951de1e71c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-flexbox.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<title>position:sticky elements should work correctly with flexbox</title>
+<link rel="match" href="position-sticky-flexbox-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that position:sticky elements interoperate correctly with flexbox" />
+
+<script src="../resources/ref-rectangle.js"></script>
+
+<style>
+.scroller {
+ overflow: scroll;
+ width: 350px;
+ height: 100px;
+ margin-bottom: 15px;
+}
+
+.flex-container {
+ width: 600px;
+ position: relative;
+ display: flex;
+ flex-flow: row wrap;
+}
+
+.sticky {
+ position: sticky;
+ left: 50px;
+}
+
+.green {
+ background-color: green;
+}
+
+.flex-item {
+ width: 100px;
+ height: 85px;
+ display: flex;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ width: 100px;
+ height: 85px;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollLeft = 50;
+ document.getElementById('scroller2').scrollLeft = 150;
+ document.getElementById('scroller3').scrollLeft = 250;
+ createIndicatorForStickyElements(document.querySelectorAll('.sticky'));
+});
+</script>
+
+<p>You should see three green boxes of varying size below. There should be no red or blue.</p>
+
+<div id="scroller1" class="scroller">
+ <div class="flex-container">
+ <div class="indicator" style="left: 100px;"></div>
+ <div class="flex-item"></div>
+ <div class="sticky green flex-item"></div>
+ <div class="green flex-item"></div>
+ </div>
+</div>
+
+<div id="scroller2" class="scroller">
+ <div class="flex-container">
+ <div class="indicator" style="left: 200px;"></div>
+ <div class="flex-item"></div>
+ <div class="sticky green flex-item"></div>
+ <div class="green flex-item"></div>
+ </div>
+</div>
+
+<div id="scroller3" class="scroller">
+ <div class="flex-container">
+ <div class="indicator" style="left: 300px;"></div>
+ <div class="flex-item"></div>
+ <div class="sticky green flex-item"></div>
+ <div class="green flex-item"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-fractional-offset-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-fractional-offset-ref.html
new file mode 100644
index 0000000000..8b7a1f8a19
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-fractional-offset-ref.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<style>
+ .container {
+ width: 100px;
+ height: 100px;
+ overflow-y: scroll;
+ background: lightgreen;
+ display: inline-block;
+ }
+</style>
+
+<div class="container">
+ <div style="height: calc(300px + 50px + 10.10px);"></div>
+</div>
+
+<div class="container">
+ <div style="height: calc(300px + 50px + 10.25px);"></div>
+</div>
+
+<div class="container">
+ <div style="height: calc(300px + 50px + 10.50px);"></div>
+</div>
+
+<div class="container">
+ <div style="height: calc(300px + 50px + 10.75px);"></div>
+</div>
+
+<div class="container">
+ <div style="height: calc(300px + 50px + 10.90px);"></div>
+</div>
+
+<script>
+ window.onload = function() {
+ var containers = document.getElementsByClassName('container');
+ for (let i = 0; i < containers.length; i++) {
+ containers[i].scrollTo(0, 20);
+ }
+ };
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-fractional-offset.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-fractional-offset.html
new file mode 100644
index 0000000000..79c29f4e87
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-fractional-offset.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="Position sticky with a fractional offset should not show a gap" />
+<link rel="match" href="position-sticky-fractional-offset-ref.html" />
+
+<style>
+ .sticky-container {
+ width: 100px;
+ height: 100px;
+ overflow-y: scroll;
+ background: red;
+ display: inline-block;
+ }
+
+ .sticky {
+ position: sticky;
+ top: 0;
+ height: 50px;
+ background: lightgreen;
+ }
+
+ .force-scroll {
+ height: 300px;
+ background: lightgreen;
+ }
+</style>
+
+<div class="sticky-container">
+ <div style="height: 10.10px;"></div>
+ <div class="sticky"></div>
+ <div class="force-scroll"></div>
+</div>
+
+<div class="sticky-container">
+ <div style="height: 10.25px;"></div>
+ <div class="sticky"></div>
+ <div class="force-scroll"></div>
+</div>
+
+<div class="sticky-container">
+ <div style="height: 10.50px;"></div>
+ <div class="sticky"></div>
+ <div class="force-scroll"></div>
+</div>
+
+<div class="sticky-container">
+ <div style="height: 10.75px;"></div>
+ <div class="sticky"></div>
+ <div class="force-scroll"></div>
+</div>
+
+<div class="sticky-container">
+ <div style="height: 10.90px;"></div>
+ <div class="sticky"></div>
+ <div class="force-scroll"></div>
+</div>
+
+<script>
+ window.onload = function() {
+ // Start with all containers scrolled to the top.
+ var containers = document.getElementsByClassName('sticky-container');
+ for (let i = 0; i < containers.length; i++) {
+ containers[i].scrollTo(0, 0);
+ }
+
+ // Wait for a full frame, then scroll all containers down so the sticky
+ // elements are stuck to the container. There should be no visible gap
+ // where the container's red background color is visible.
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ for (let i = 0; i < containers.length; i++) {
+ containers[i].scrollTo(0, 20);
+ }
+ document.documentElement.classList.remove('reftest-wait');
+ });
+ });
+ };
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-get-bounding-client-rect.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-get-bounding-client-rect.html
new file mode 100644
index 0000000000..18b2acfe16
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-get-bounding-client-rect.html
@@ -0,0 +1,99 @@
+<!DOCTYPE html>
+<title>Sticky positioned element should be observable by getBoundingClientRect.</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that sticky positioned element
+should be observable by getBoundingClientRect." />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+body {
+ margin: 0;
+}
+
+.container {
+ overflow: scroll;
+ width: 200px;
+ height: 200px;
+}
+
+.spacer {
+ width: 2000px;
+ height: 2000px;
+}
+
+.box {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+}
+
+.sticky {
+ position: sticky;
+ top: 50px;
+ left: 20px;
+}
+</style>
+
+<div id="scroller1" class="container">
+ <div id="sticky1" class="sticky box"></div>
+ <div class="spacer"></div>
+</div>
+
+<script>
+test(() => {
+ var sticky = document.getElementById('sticky1');
+ assert_equals(sticky.getBoundingClientRect().top, 50);
+ document.getElementById('scroller1').scrollTop = 100;
+ assert_equals(sticky.getBoundingClientRect().top, 50);
+ sticky.style.position = 'relative';
+ assert_equals(sticky.getBoundingClientRect().top, -50);
+ sticky.style.position = 'sticky';
+ assert_equals(sticky.getBoundingClientRect().top, 50);
+}, 'sticky positioned element should be observable by getBoundingClientRect.');
+</script>
+
+<div id="scroller2" class="container">
+ <div class="spacer"></div>
+</div>
+
+<script>
+test(() => {
+ var scroller = document.getElementById('scroller2');
+ scroller.scrollTop = 100;
+ scroller.scrollLeft = 75;
+
+ var sticky = document.createElement('div');
+ sticky.className = 'sticky box';
+ scroller.insertBefore(sticky, scroller.querySelector('.spacer'));
+
+ var sticky_bounds = sticky.getBoundingClientRect();
+ var scroller_bounds = scroller.getBoundingClientRect();
+ assert_equals(sticky_bounds.top, scroller_bounds.top + 50);
+ assert_equals(sticky_bounds.left, scroller_bounds.left + 20);
+}, 'getBoundingClientRect should be correct for sticky after script insertion');
+</script>
+
+<div id="scroller3" class="container">
+ <div id="sticky3" class="sticky box"></div>
+ <div class="spacer"></div>
+</div>
+
+<script>
+test(() => {
+ var scroller = document.getElementById('scroller3');
+ var sticky = document.getElementById('sticky3');
+ scroller.scrollTop = 100;
+ scroller.scrollLeft = 75;
+
+ var div = document.createElement('div');
+ div.style.height = '65px';
+ scroller.insertBefore(div, sticky);
+
+ var sticky_bounds = sticky.getBoundingClientRect();
+ var scroller_bounds = scroller.getBoundingClientRect();
+ assert_equals(sticky_bounds.top, scroller_bounds.top + 50);
+ assert_equals(sticky_bounds.left, scroller_bounds.left + 20);
+}, 'getBoundingClientRect should be correct for sticky after script-caused layout');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-grid-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-grid-ref.html
new file mode 100644
index 0000000000..123eed311b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-grid-ref.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<title>Reference for position:sticky elements should work correctly with grid layout</title>
+
+<style>
+.scroller {
+ position: relative;
+ overflow-x: scroll;
+ overflow-y: hidden;
+ width: 300px;
+ height: 100px;
+ margin-bottom: 15px;
+}
+
+.grid-container {
+ display: grid;
+ grid-template-columns: 25% 25% 25% 25%;
+ grid-template-rows: 100%;
+ width: 400px;
+ height: 90px;
+}
+
+.green {
+ background-color: green;
+}
+
+.grid-item {
+ width: 100%;
+ height: 100%;
+ grid-row: 1;
+}
+
+.padding {
+ height: 1px;
+ width: 700px;
+}
+
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollLeft = 0;
+ document.getElementById('scroller2').scrollLeft = 150;
+ document.getElementById('scroller3').scrollLeft = 300;
+});
+</script>
+
+<p>You should see three green boxes of varying size below. There should be no red or blue.</p>
+
+<div id="scroller1" class="scroller">
+ <div class="grid-container">
+ <div class="grid-item" style="grid-column: 1;"></div>
+ <div class="green grid-item" style="grid-column: 2;"></div>
+ <div class="green grid-item" style="grid-column: 3;"></div>
+ </div>
+ <div class="padding"></div>
+</div>
+
+<div id="scroller2" class="scroller">
+ <div class="grid-container">
+ <div class="grid-item" style="grid-column: 1;"></div>
+ <div class="grid-item" style="grid-column: 2;"></div>
+ <div class="green grid-item" style="grid-column: 3;"></div>
+ </div>
+ <div class="padding"></div>
+</div>
+
+<div id="scroller3" class="scroller">
+ <div class="grid-container">
+ <div class="grid-item" style="grid-column: 1;"></div>
+ <div class="grid-item" style="grid-column: 2;"></div>
+ <div class="grid-item" style="grid-column: 3;"></div>
+ <div class="green grid-item" style="grid-column: 4;"></div>
+ </div>
+ <div class="padding"></div>
+</div>
+
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-grid.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-grid.html
new file mode 100644
index 0000000000..607e7c2936
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-grid.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<title>position:sticky elements should work correctly with grid layout</title>
+<link rel="match" href="position-sticky-grid-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that position:sticky elements interoperate correctly with grid" />
+
+<script src="../resources/ref-rectangle.js"></script>
+
+<style>
+.scroller {
+ position: relative;
+ overflow-x: scroll;
+ overflow-y: hidden;
+ width: 300px;
+ height: 100px;
+ margin-bottom: 15px;
+}
+
+.grid-container {
+ display: grid;
+ grid-template-columns: 25% 25% 25% 25%;
+ grid-template-rows: 100%;
+ width: 400px;
+ height: 90px;
+}
+
+.sticky {
+ position: sticky;
+ left: 50px;
+}
+
+.green {
+ background-color: green;
+}
+
+.grid-item {
+ width: 100%;
+ height: 100%;
+ grid-row: 1;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ width: 100px;
+ height: 90px;
+}
+
+.padding {
+ height: 1px;
+ width: 700px;
+}
+
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollLeft = 0;
+ document.getElementById('scroller2').scrollLeft = 150;
+ document.getElementById('scroller3').scrollLeft = 300;
+ createIndicatorForStickyElements(document.querySelectorAll('.sticky'));
+});
+</script>
+
+<p>You should see three green boxes of varying size below. There should be no red or blue.</p>
+
+<div id="scroller1" class="scroller">
+ <div class="grid-container">
+ <div class="indicator" style="left: 100px;"></div>
+ <div class="grid-item" style="grid-column: 1;"></div>
+ <div class="sticky green grid-item" style="grid-column: 2;"></div>
+ <div class="green grid-item" style="grid-column: 3;"></div>
+ </div>
+ <div class="padding"></div>
+</div>
+
+<div id="scroller2" class="scroller">
+ <div class="grid-container">
+ <div class="indicator" style="left: 200px;"></div>
+ <div class="grid-item" style="grid-column: 1;"></div>
+ <div class="sticky green grid-item" style="grid-column: 2;"></div>
+ <div class="green grid-item" style="grid-column: 3;"></div>
+ </div>
+ <div class="padding"></div>
+</div>
+
+<div id="scroller3" class="scroller">
+ <div class="grid-container">
+ <div class="indicator" style="left: 300px;"></div>
+ <div class="grid-item" style="grid-column: 1;"></div>
+ <div class="sticky green grid-item" style="grid-column: 2;"></div>
+ <div class="green grid-item" style="grid-column: 3;"></div>
+ </div>
+ <div class="padding"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-hyperlink-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-hyperlink-ref.html
new file mode 100644
index 0000000000..88d45a7e6d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-hyperlink-ref.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<title>Reference for sticky hyperlink should work on high dpi devices</title>
+
+<style>
+body {
+ margin: 0;
+}
+
+.scroller {
+ overflow: scroll;
+ width: 200px;
+ height: 200px;
+}
+
+.positioned {
+ position: relative;
+ top: 100px;
+ will-change: transform;
+}
+
+.spacer {
+ height: 700px;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.querySelector('.scroller').scrollTop = 100;
+});
+</script>
+
+<div>You should see a sticky link at the top of the scrollable area.</div>
+
+<div class='scroller'>
+ <a href='#' class='positioned'>Link</a>
+ <div class='spacer'></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-hyperlink.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-hyperlink.html
new file mode 100644
index 0000000000..cc8de9a822
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-hyperlink.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<title>Sticky element with hyperlink should work</title>
+<link rel="match" href="position-sticky-hyperlink-ref.html">
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos">
+<meta name="assert" content="This test checks that sticky hyperlink works.">
+<meta name="fuzzy" content="maxDifference=0-5; totalPixels=0-80">
+
+<style>
+body {
+ margin: 0;
+}
+
+.scroller {
+ overflow: scroll;
+ width: 200px;
+ height: 200px;
+}
+
+.sticky {
+ position: sticky;
+ top: 0;
+ will-change: transform;
+}
+
+.spacer {
+ height: 700px;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.querySelector('.scroller').scrollTop = 100;
+});
+</script>
+
+<div>You should see a sticky link at the top of the scrollable area.</div>
+
+<div class='scroller'>
+ <a href='#' class='sticky'>Link</a>
+ <div class='spacer'></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-in-fixed-container-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-in-fixed-container-ref.html
new file mode 100644
index 0000000000..7d8e148995
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-in-fixed-container-ref.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<style>
+ .modal {
+ bottom: 0;
+ left: 0;
+ right: 0;
+ position: fixed;
+ }
+
+ .modal-dialog {
+ position: relative;
+ overflow: auto;
+ max-height: 400px;
+ transform: translateY(0);
+ }
+
+ .modal-content {
+ background-color: purple;
+ height: 300px;
+ }
+
+ .modal-footer {
+ height: 100px;
+ background-color: blue;
+ }
+
+ .additional-content {
+ height: 100px;
+ background-color: purple;
+ }
+</style>
+<div class="modal">
+ <div class="modal-dialog">
+ <div class="modal-content"></div>
+ <div class="modal-footer"></div>
+ <div class="additional-content"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-in-fixed-container.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-in-fixed-container.html
new file mode 100644
index 0000000000..359ec2fd33
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-in-fixed-container.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width,initial-scale=1">
+<link rel="match" href="position-sticky-in-fixed-container-ref.html">
+<link rel="help" href="https://drafts.csswg.org/css-position-3/#sticky-pos">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1854010">
+<style>
+ .modal {
+ bottom: 0;
+ left: 0;
+ right: 0;
+ position: fixed;
+ }
+
+ .modal-dialog {
+ position: relative;
+ overflow: auto;
+ max-height: 400px;
+ transform: translateY(0);
+ }
+
+ .modal-content {
+ background-color: purple;
+ height: 400px;
+ }
+
+ .modal-footer {
+ height: 100px;
+ background-color: blue;
+
+ position:sticky;
+ bottom: 0;
+ }
+</style>
+<div class="modal">
+ <div class="modal-dialog">
+ <div class="modal-content"></div>
+ <div class="modal-footer"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-inflow-position.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-inflow-position.html
new file mode 100644
index 0000000000..a6774b7a71
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-inflow-position.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<title>position:sticky elements should not affect the flow position of other elements</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that position:sticky elements do not affect the flow position of other elements" />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+.scroller {
+ position: relative;
+ height: 200px;
+ width: 100px;
+ overflow: scroll;
+}
+
+#sticky {
+ background-color: green;
+ position: sticky;
+ top: 150px;
+}
+
+#before {
+ background-color: fuchsia;
+}
+
+#after {
+ background-color: orange;
+}
+
+.box {
+ height: 50px;
+ width: 50px;
+}
+
+.padding {
+ height: 500px;
+}
+</style>
+
+<div class="scroller">
+ <div id="before" class="box"></div>
+ <div id="sticky" class="box"></div>
+ <div id="after" class="box"></div>
+ <div class="padding"></div>
+</div>
+
+<script>
+test(() => {
+ // The sticky element is pushed to be stuck 150 pixels from the top.
+ assert_equals(sticky.offsetTop, 150);
+
+ // Neither 'before' or 'after' should be affected by the change in the sticky
+ // element's location.
+ assert_equals(before.offsetTop, 0);
+ assert_equals(after.offsetTop, before.clientHeight + sticky.clientHeight);
+}, 'sticky offset should not affect the position of other elements.');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-inline-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-inline-ref.html
new file mode 100644
index 0000000000..d3b4869afe
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-inline-ref.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<title>Reference for position:sticky should work for inline elements</title>
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 250px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 200px;
+ overflow-x: hidden;
+ overflow-y: auto;
+ font: 25px/1 Ahem;
+}
+
+.contents {
+ height: 500px;
+}
+
+.indicator {
+ position: absolute;
+ left: 0;
+ color: green;
+}
+
+.inline {
+ display: inline;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 50;
+ document.getElementById('scroller2').scrollTop = 125;
+ document.getElementById('scroller3').scrollTop = 250;
+});
+</script>
+
+<div>You should see three green rectangles below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="contents">
+ <div class="indicator inline" style="top: 150px;">XXX</div>
+ </div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="contents">
+ <div class="indicator inline" style="top: 175px;">XXX</div>
+ </div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="contents">
+ <div class="indicator inline" style="top: 275px;">XXX</div>
+ </div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-inline.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-inline.html
new file mode 100644
index 0000000000..6bd49befe5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-inline.html
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<title>position:sticky should work for inline elements</title>
+<link rel="match" href="position-sticky-inline-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that position:sticky works for inline elements" />
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+
+<script src="../resources/ref-rectangle.js"></script>
+
+<style>
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 250px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 200px;
+ overflow-x: hidden;
+ overflow-y: auto;
+ font: 25px/1 Ahem;
+}
+
+.contents {
+ height: 500px;
+}
+
+.prepadding {
+ height: 100px;
+}
+
+.container {
+ height: 200px;
+}
+
+.innerpadding {
+ height: 50px;
+}
+
+.indicator {
+ position: absolute;
+ left: 0;
+ color: red;
+}
+
+.sticky {
+ position: sticky;
+ top: 50px;
+ color: green;
+}
+
+.inline {
+ display: inline;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 50;
+ document.getElementById('scroller2').scrollTop = 125;
+ document.getElementById('scroller3').scrollTop = 250;
+ createIndicatorForStickyElements(document.querySelectorAll('.sticky'));
+});
+</script>
+
+<div>You should see three green rectangles below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator inline" style="top: 150px;">XXX</div>
+ <div class="contents">
+ <div class="prepadding"></div>
+ <div class="container">
+ <div class="innerpadding"></div>
+ <div class="sticky inline">XXX</div>
+ </div>
+ </div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator inline" style="top: 175px;">XXX</div>
+ <div class="contents">
+ <div class="prepadding"></div>
+ <div class="container">
+ <div class="innerpadding"></div>
+ <div class="sticky inline">XXX</div>
+ </div>
+ </div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator inline" style="top: 275px;">XXX</div>
+ <div class="contents">
+ <div class="prepadding"></div>
+ <div class="container">
+ <div class="innerpadding"></div>
+ <div class="sticky inline">XXX</div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-input-box-gets-focused-after-scroll.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-input-box-gets-focused-after-scroll.html
new file mode 100644
index 0000000000..438547dbb7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-input-box-gets-focused-after-scroll.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>Focusing on visible sticky input box should scroll to unshifted sticky position.</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that focusing on visible sticky
+positioned input box should not scroll the page." />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+body {
+ height: 2000px;
+}
+
+input {
+ position: sticky;
+ top: 10px;
+}
+</style>
+
+<input type="text" id="input"/>
+
+<script>
+test(() => {
+ var input = document.getElementById('input');
+ window.scrollTo(0, 100);
+ input.focus();
+ assert_equals(window.scrollY, 0);
+}, 'Focusing on visible sticky input box should reset the scroll to unshifted sticky position.');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-large-top-2-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-large-top-2-ref.html
new file mode 100644
index 0000000000..1890063fb9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-large-top-2-ref.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="utf-8">
+ <title>CSS Position Test Reference: Test position:sticky element with large top in an overflow scroll container</title>
+ <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+ <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+
+ <style>
+ .scroll {
+ border: 5px solid blue;
+ padding: 5px 3px 0 8px;
+ overflow: auto;
+ height: 200px;
+ width: 200px;
+ position: relative;
+ }
+
+ .block {
+ width: 150px;
+ height: 200px;
+ background: yellow;
+ position: absolute;
+ top: 55px;
+ }
+
+ .sticky {
+ position: absolute;
+ background: purple;
+ width: 50px;
+ height: 50px;
+ top: 205px;
+ z-index: 1;
+ }
+ </style>
+ <script>
+ function runTest() {
+ document.getElementById("scroll2").scrollTop = 50;
+ }
+ </script>
+
+ <body onload="runTest();">
+ <div class="scroll">
+ <span>
+ <div class="sticky"></div>
+ </span>
+ <div class="block"></div>
+ </div>
+
+ <div class="scroll" id="scroll2">
+ <span>
+ <div class="sticky"></div>
+ </span>
+ <div class="block"></div>
+ </div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-large-top-2.tentative.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-large-top-2.tentative.html
new file mode 100644
index 0000000000..1cf9c0dfb4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-large-top-2.tentative.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="utf-8">
+ <title>CSS Position Test: Test position:sticky element with large top in an overflow container</title>
+ <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+ <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+ <link rel="help" href="https://drafts.csswg.org/css-position/#sticky-pos">
+ <link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1598112">
+ <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/2794">
+ <link rel="match" href="position-sticky-large-top-2-ref.html">
+ <meta name="assert" content="This test verifies the position of a position:sticky element with large top value can be reached by scrolling the overflow container.">
+
+ <style>
+ .scroll {
+ border: 5px solid blue;
+ padding: 5px 3px 0 8px;
+ overflow: auto;
+ height: 200px;
+ width: 200px;
+ }
+
+ .block {
+ width: 150px;
+ height: 200px;
+ background: yellow;
+ }
+
+ .sticky {
+ position: sticky;
+ background: purple;
+ width: 50px;
+ height: 50px;
+ top: 200px;
+ }
+ </style>
+ <script>
+ function runTest() {
+ document.getElementById("scroll2").scrollTop = 50;
+ }
+ </script>
+
+ <body onload="runTest();">
+ <!-- test before scroll -->
+ <div class="scroll">
+ <span>
+ <div class="sticky"></div>
+ </span>
+ <div class="block"></div>
+ </div>
+
+ <!-- test after scroll -->
+ <div class="scroll" id="scroll2">
+ <span>
+ <div class="sticky"></div>
+ </span>
+ <div class="block"></div>
+ </div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-large-top-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-large-top-ref.html
new file mode 100644
index 0000000000..b50bae2260
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-large-top-ref.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="utf-8">
+ <title>CSS Position Test Reference: Test position:sticky element with large top in an overflow scroll container</title>
+ <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+ <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+
+ <style>
+ .scroll {
+ border: 5px solid blue;
+ overflow: auto;
+ height: 200px;
+ width: 200px;
+ position: relative;
+ }
+
+ .block {
+ width: 100%;
+ height: 200px;
+ background: yellow;
+ position: absolute;
+ top: 50px;
+ }
+
+ .sticky {
+ position: absolute;
+ background: purple;
+ width: 50px;
+ height: 50px;
+ top: 200px;
+ z-index: 1;
+ }
+ </style>
+ <script>
+ function runTest() {
+ document.getElementById("scroll2").scrollTop = 50;
+ }
+ </script>
+
+ <body onload="runTest();">
+ <div class="scroll">
+ <div class="sticky"></div>
+ <div class="block"></div>
+ </div>
+
+ <div class="scroll" id="scroll2">
+ <div class="sticky"></div>
+ <div class="block"></div>
+ </div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-large-top.tentative.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-large-top.tentative.html
new file mode 100644
index 0000000000..b00a0d1396
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-large-top.tentative.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+ <meta charset="utf-8">
+ <title>CSS Position Test: Test position:sticky element with large top in an overflow container</title>
+ <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+ <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+ <link rel="help" href="https://drafts.csswg.org/css-position/#sticky-pos">
+ <link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1598112">
+ <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/2794">
+ <link rel="match" href="position-sticky-large-top-ref.html">
+ <meta name="assert" content="This test verifies the position of a position:sticky element with large top value can be reached by scrolling the overflow container.">
+
+ <style>
+ .scroll {
+ border: 5px solid blue;
+ overflow: auto;
+ height: 200px;
+ width: 200px;
+ }
+
+ .block {
+ width: 100%;
+ height: 200px;
+ background: yellow;
+ }
+
+ .sticky {
+ position: sticky;
+ background: purple;
+ width: 50px;
+ height: 50px;
+ top: 200px;
+ }
+ </style>
+ <script>
+ function runTest() {
+ document.getElementById("scroll2").scrollTop = 50;
+ }
+ </script>
+
+ <body onload="runTest();">
+ <!-- test before scroll -->
+ <div class="scroll">
+ <div class="sticky"></div>
+ <div class="block"></div>
+ </div>
+
+ <!-- test after scroll -->
+ <div class="scroll" id="scroll2">
+ <div class="sticky"></div>
+ <div class="block"></div>
+ </div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-left-002.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-left-002.html
new file mode 100644
index 0000000000..868b58adb0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-left-002.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Position Test: sticky element with left offset specified with px unit</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos">
+ <link rel="match" href="reference/position-sticky-left-002-ref.html">
+
+ <meta name="flags" content="">
+
+ <style>
+ div.scrolling-container
+ {
+ background-image: url("support/100x100-red.png");
+ background-repeat: no-repeat;
+ height: 150px;
+ margin-bottom: 30px;
+ overflow-y: hidden;
+ position: static;
+ white-space: nowrap;
+ width: 250px;
+ }
+
+ div#first-scrolling-container
+ {
+ background-position: right top;
+ }
+
+ div#second-scrolling-container
+ {
+ background-position: 100px top;
+ }
+
+ div#third-scrolling-container
+ {
+ background-position: 50px top;
+ }
+
+ div.horizontal-spacer
+ {
+ display: inline-block;
+ height: 100%;
+ width: 100px;
+ }
+
+ div.content
+ {
+ display: inline-block;
+ height: 100%;
+ width: 300px;
+ }
+
+ div.sticky
+ {
+ background-color: green;
+ display: inline-block;
+ height: 100px;
+ left: 100px;
+ position: sticky;
+ vertical-align: top;
+ width: 100px;
+ }
+ </style>
+
+ <body onload="document.getElementById(&quot;first-scrolling-container&quot;).scrollLeft = 50; document.getElementById(&quot;second-scrolling-container&quot;).scrollLeft = 150; document.getElementById(&quot;third-scrolling-container&quot;).scrollLeft = 300;">
+
+ <p>Test passes if there are 3 filled green squares and <strong>no red</strong>.
+
+ <!--
+ first-scrolling-container: before reaching the sticking point
+ -->
+
+ <div id="first-scrolling-container" class="scrolling-container">
+
+ <div class="horizontal-spacer"></div><div class="content"><div class="horizontal-spacer"></div><div id="first-sticky" class="sticky"></div><div class="horizontal-spacer"></div></div><div class="horizontal-spacer"></div>
+
+ </div>
+
+ <!--
+ second-scrolling-container: when reaching the sticking point and beyond
+ -->
+
+ <div id="second-scrolling-container" class="scrolling-container">
+
+ <div class="horizontal-spacer"></div><div class="content"><div class="horizontal-spacer"></div><div id="second-sticky" class="sticky"></div><div class="horizontal-spacer"></div></div><div class="horizontal-spacer"></div>
+
+ </div>
+
+
+ <div id="third-scrolling-container" class="scrolling-container">
+
+ <div class="horizontal-spacer"></div><div class="content"><div class="horizontal-spacer"></div><div id="third-sticky" class="sticky"></div><div class="horizontal-spacer"></div></div><div class="horizontal-spacer"></div>
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-left-003.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-left-003.html
new file mode 100644
index 0000000000..3114981a69
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-left-003.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Position Test: sticky element with left offset specified with percentage unit</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos">
+ <link rel="match" href="reference/position-sticky-left-002-ref.html">
+
+ <meta name="flags" content="">
+
+ <style>
+ div.scrolling-container
+ {
+ background-image: url("support/100x100-red.png");
+ background-repeat: no-repeat;
+ height: 150px;
+ margin-bottom: 30px;
+ overflow-y: hidden;
+ position: static;
+ white-space: nowrap;
+ width: 250px;
+ }
+
+ div#first-scrolling-container
+ {
+ background-position: right top;
+ }
+
+ div#second-scrolling-container
+ {
+ background-position: 100px top;
+ }
+
+ div#third-scrolling-container
+ {
+ background-position: 50px top;
+ }
+
+ div.horizontal-spacer
+ {
+ display: inline-block;
+ height: 100%;
+ width: 100px;
+ }
+
+ div.content
+ {
+ display: inline-block;
+ height: 100%;
+ width: 300px;
+ }
+
+ div.sticky
+ {
+ background-color: green;
+ display: inline-block;
+ height: 100px;
+ left: 40%;
+ position: sticky;
+ vertical-align: top;
+ width: 100px;
+ }
+ </style>
+
+ <body onload="document.getElementById(&quot;first-scrolling-container&quot;).scrollLeft = 50; document.getElementById(&quot;second-scrolling-container&quot;).scrollLeft = 150; document.getElementById(&quot;third-scrolling-container&quot;).scrollLeft = 300;">
+
+ <p>Test passes if there are 3 filled green squares and <strong>no red</strong>.
+
+ <!--
+ first-scrolling-container: before reaching the sticking point
+ -->
+
+ <div id="first-scrolling-container" class="scrolling-container">
+
+ <div class="horizontal-spacer"></div><div class="content"><div class="horizontal-spacer"></div><div id="first-sticky" class="sticky"></div><div class="horizontal-spacer"></div></div><div class="horizontal-spacer"></div>
+
+ </div>
+
+ <!--
+ second-scrolling-container: when reaching the sticking point and beyond
+ -->
+
+ <div id="second-scrolling-container" class="scrolling-container">
+
+ <div class="horizontal-spacer"></div><div class="content"><div class="horizontal-spacer"></div><div id="second-sticky" class="sticky"></div><div class="horizontal-spacer"></div></div><div class="horizontal-spacer"></div>
+
+ </div>
+
+
+ <div id="third-scrolling-container" class="scrolling-container">
+
+ <div class="horizontal-spacer"></div><div class="content"><div class="horizontal-spacer"></div><div id="third-sticky" class="sticky"></div><div class="horizontal-spacer"></div></div><div class="horizontal-spacer"></div>
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-left.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-left.html
new file mode 100644
index 0000000000..1fc2e8f88d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-left.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<title>position:sticky elements should respect the left constraint</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that position:sticky elements obey their left anchor after scrolling" />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script src="../resources/sticky-util.js"></script>
+
+<body></body>
+
+<script>
+test(() => {
+ const elements = setupStickyTest('left', 50);
+ elements.scroller.scrollLeft = 100;
+ const nonStickyLeftX = elements.container.offsetLeft +
+ elements.filler.clientWidth;
+ assert_equals(elements.sticky.offsetLeft, nonStickyLeftX);
+}, 'before reaching the sticking point the sticky box should not be offset');
+
+test(() => {
+ const elements = setupStickyTest('left', 50);
+ elements.scroller.scrollLeft = 200;
+
+ // This math actually cancels to sticky.offsetLeft == (scroller.scrollLeft + 50),
+ // but for clarity the calculations are left explicit.
+ const nonStickyLeftX = elements.container.offsetLeft +
+ elements.filler.clientWidth;
+ const targetLeftX = elements.scroller.scrollLeft + 50;
+ const stickyOffset = targetLeftX - nonStickyLeftX;
+
+ assert_equals(elements.sticky.offsetLeft, nonStickyLeftX + stickyOffset);
+}, 'after reaching the sticking point the sticky box should be offset');
+
+test(() => {
+ const elements = setupStickyTest('left', 50);
+ elements.scroller.scrollLeft = 300;
+ const maxOffsetInContainer = elements.container.offsetLeft +
+ elements.container.clientWidth - elements.sticky.clientWidth;
+ assert_equals(elements.sticky.offsetLeft, maxOffsetInContainer);
+}, 'the sticky box should not be pushed outside its containing block');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-margins.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-margins.html
new file mode 100644
index 0000000000..7a9cf09faa
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-margins.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<title>position:sticky elements should properly interact with margins</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="position:sticky elements should ignore margins when sticking, but consider them when making sure sticky elements do not escape their containing block" />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script src="../resources/sticky-util.js"></script>
+
+<body></body>
+
+<script>
+test(() => {
+ const elements = setupStickyTest('top', 50);
+ elements.sticky.style.margin = '15px';
+ elements.scroller.scrollTop = 100;
+ assert_equals(elements.sticky.offsetTop,
+ elements.container.offsetTop + elements.filler.clientHeight + 15);
+}, 'Before sticking, the margin should be obeyed.');
+
+test(() => {
+ const elements = setupStickyTest('top', 50);
+ elements.sticky.style.margin = '15px';
+
+ elements.scroller.scrollTop = 200;
+
+ // This math cancels to sticky.offsetTop == (scroller.scrollTop + 50), but
+ // for clarity the calculations are left explicit.
+ const nonStickyTopY = elements.container.offsetTop +
+ elements.filler.clientHeight;
+ const targetTopY = elements.scroller.scrollTop + 50;
+ const stickyOffset = targetTopY - nonStickyTopY;
+
+ assert_equals(elements.sticky.offsetTop, nonStickyTopY + stickyOffset);
+}, 'Whilst stuck, the margin is irrelevant.');
+
+test(() => {
+ const elements = setupStickyTest('top', 50);
+ elements.sticky.style.margin = '15px';
+
+ elements.scroller.scrollTop = 300;
+
+ const maxOffsetInContainer = elements.container.offsetTop +
+ elements.container.clientHeight - elements.sticky.clientHeight;
+ assert_equals(elements.sticky.offsetTop, maxOffsetInContainer - 15);
+}, 'The margin is taken into account when making sure the sticky element ' +
+ 'does not escape its container');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-bottom.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-bottom.html
new file mode 100644
index 0000000000..34fb3b32fc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-bottom.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<title>Nested bottom-constrained position:sticky elements should render correctly</title>
+
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that nested position:sticky elements with a bottom constraint render correctly" />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script src="../resources/sticky-util.js"></script>
+
+<body></body>
+
+<script>
+test(() => {
+ const elements = setupNestedStickyTest('bottom', 25, 35);
+ elements.scroller.scrollTop = 300;
+ const nonStickyTopY = elements.container.offsetTop +
+ elements.filler.clientHeight;
+ assert_equals(elements.sticky.offsetTop, nonStickyTopY);
+ // The inner sticky should not be offset from the outer.
+ const nonStickyInnerTopY = elements.sticky.clientHeight -
+ elements.innerSticky.clientHeight;
+ assert_equals(elements.innerSticky.offsetTop, nonStickyInnerTopY);
+}, 'before reaching the sticking point, neither sticky box should be offset');
+
+test(() => {
+ const elements = setupNestedStickyTest('bottom', 25, 50);
+ elements.scroller.scrollTop = 150;
+ const nonStickyTopY = elements.container.offsetTop +
+ elements.filler.clientHeight;
+ assert_equals(elements.sticky.offsetTop, nonStickyTopY);
+ assert_equals(elements.innerSticky.offsetTop, 50);
+}, 'the inner sticky can stick before the outer one if necessary');
+
+test(() => {
+ const elements = setupNestedStickyTest('bottom', 25, 35);
+ elements.scroller.scrollTop = 100;
+
+ const nonStickyTopY = elements.container.offsetTop +
+ elements.filler.clientHeight;
+ const nonStickyBottomY = nonStickyTopY + elements.sticky.clientHeight;
+ const targetBottomY = elements.scroller.clientHeight +
+ elements.scroller.scrollTop - 25;
+ const stickyOffset = nonStickyBottomY - targetBottomY;
+ assert_equals(elements.sticky.offsetTop, nonStickyTopY - stickyOffset);
+
+ // The inner sticky has similar math, but its offsetTop is relative to the
+ // sticky element and in this test is (height - the difference between the
+ // top values).
+ assert_equals(elements.innerSticky.offsetTop, 40);
+}, 'both sticky boxes can be stuck at the same time');
+
+test(() => {
+ const elements = setupNestedStickyTest('bottom', 25, 75);
+ elements.scroller.scrollTop = 0;
+ assert_equals(elements.sticky.offsetTop, elements.container.offsetTop);
+ assert_equals(elements.innerSticky.offsetTop, 0);
+}, 'neither sticky can escape their containing block');
+
+test(() => {
+ const elements = setupNestedStickyTest('bottom', 25, 300);
+ elements.scroller.scrollTop = 200;
+ // It doesn't matter how big the inner sticky offset is, it cannot escape its
+ // containing block (the outer sticky).
+ assert_equals(elements.innerSticky.offsetTop, 0);
+}, 'the inner sticky cannot be pushed outside the outer sticky');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-inline-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-inline-ref.html
new file mode 100644
index 0000000000..4ad6dee5d0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-inline-ref.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<title>Reference for nested inline position:sticky elements should render correctly</title>
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 250px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 200px;
+ overflow-x: hidden;
+ overflow-y: auto;
+ font: 25px/1 Ahem;
+}
+
+.contents {
+ height: 500px;
+}
+
+.outerIndicator {
+ color: green;
+ position: absolute;
+ left: 0;
+}
+
+.innerIndicator {
+ color: yellow;
+ position: absolute;
+ left: 25px;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 50;
+ document.getElementById('scroller2').scrollTop = 125;
+ document.getElementById('scroller3').scrollTop = 225;
+});
+</script>
+
+<div>You should see three green and three yellow rectangles below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="contents">
+ <div class="outerIndicator" style="top: 150px;">X</div>
+ <div class="innerIndicator" style="top: 150px;">XX</div>
+ </div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="contents">
+ <div class="outerIndicator" style="top: 175px;">X</div>
+ <div class="innerIndicator" style="top: 185px;">XX</div>
+ </div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="contents">
+ <div class="outerIndicator" style="top: 275px;">X</div>
+ <div class="innerIndicator" style="top: 275px;">XX</div>
+ </div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-inline.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-inline.html
new file mode 100644
index 0000000000..92eda147bd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-inline.html
@@ -0,0 +1,119 @@
+<!DOCTYPE html>
+<title>Nested inline position:sticky elements should render correctly</title>
+<link rel="match" href="position-sticky-nested-inline-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that nested inline position:sticky elements render correctly" />
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+
+<script src="../resources/ref-rectangle.js"></script>
+
+<style>
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 250px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 200px;
+ overflow-x: hidden;
+ overflow-y: auto;
+ font: 25px/1 Ahem;
+}
+
+.contents {
+ height: 500px;
+}
+
+.prepadding {
+ height: 100px;
+}
+
+.container {
+ height: 200px;
+}
+
+.innerpadding {
+ height: 50px;
+}
+
+.outerIndicator {
+ color: red;
+ position: absolute;
+ left: 0;
+}
+
+.innerIndicator {
+ color: red;
+ position: absolute;
+ left: 25px;
+}
+
+.outerSticky {
+ display: inline;
+ color: green;
+ position: sticky;
+ top: 50px;
+}
+
+.innerSticky {
+ display: inline;
+ color: yellow;
+ position: sticky;
+ top: 60px;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 50;
+ document.getElementById('scroller2').scrollTop = 125;
+ document.getElementById('scroller3').scrollTop = 225;
+ createIndicatorForStickyElements(document.querySelectorAll('.sticky'));
+});
+</script>
+
+<div>You should see three green and three yellow rectangles below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="outerIndicator" style="top: 150px;">X</div>
+ <div class="contents">
+ <div class="prepadding"></div>
+ <div class="container">
+ <div class="innerpadding"></div>
+ <div class="outerSticky">X<div class="innerIndicator" style="top: 0;">XX</div><div class="innerSticky">XX</div></div>
+ </div>
+ </div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="outerIndicator" style="top: 175px;">X</div>
+ <div class="contents">
+ <div class="prepadding"></div>
+ <div class="container">
+ <div class="innerpadding"></div>
+ <div class="outerSticky">X<div class="innerIndicator" style="top: 10px;">XX</div><div class="innerSticky">XX</div></div>
+ </div>
+ </div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="outerIndicator" style="top: 200px;">X</div>
+ <div class="contents">
+ <div class="prepadding"></div>
+ <div class="container">
+ <div class="innerpadding"></div>
+ <div class="outerSticky">X<div class="innerIndicator" style="top: 0;">XX</div><div class="innerSticky">XX</div></div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-left.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-left.html
new file mode 100644
index 0000000000..b92d45319b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-left.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<title>Nested left-constrained position:sticky elements should render correctly</title>
+
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that nested position:sticky elements with a left constraint render correctly" />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script src="../resources/sticky-util.js"></script>
+
+<body></body>
+
+<script>
+test(() => {
+ const elements = setupNestedStickyTest('left', 50, 60);
+ elements.scroller.scrollLeft = 100;
+ const nonStickyLeftX = elements.container.offsetLeft +
+ elements.filler.clientWidth;
+ assert_equals(elements.sticky.offsetLeft, nonStickyLeftX);
+ // The inner sticky should not be offset from the outer.
+ assert_equals(elements.innerSticky.offsetLeft, 0);
+}, 'before reaching the sticking point, neither sticky box should be offset');
+
+test(() => {
+ const elements = setupNestedStickyTest('left', 50, 60);
+ elements.scroller.scrollLeft = 145;
+ const nonStickyLeftX = elements.container.offsetLeft +
+ elements.filler.clientWidth;
+ assert_equals(elements.sticky.offsetLeft, nonStickyLeftX);
+ assert_equals(elements.innerSticky.offsetLeft, 5);
+}, 'the inner sticky can stick before the outer one if necessary');
+
+test(() => {
+ const elements = setupNestedStickyTest('left', 50, 60);
+ elements.scroller.scrollLeft = 200;
+
+ // This math cancels to sticky.offsetLeft == (scroller.scrollLeft + 50), but
+ // for clarity the calculations are left explicit.
+ const nonStickyLeftX = elements.container.offsetLeft +
+ elements.filler.clientWidth;
+ const targetLeftX = elements.scroller.scrollLeft + 50;
+ const stickyOffset = targetLeftX - nonStickyLeftX;
+ assert_equals(elements.sticky.offsetLeft, nonStickyLeftX + stickyOffset);
+
+ // The inner sticky has similar math, but its offsetLeft is relative to the
+ // sticky element and in this test is the difference between the left values.
+ assert_equals(elements.innerSticky.offsetLeft, 10);
+}, 'both sticky boxes can be stuck at the same time');
+
+test(() => {
+ const elements = setupNestedStickyTest('left', 50, 60);
+ elements.scroller.scrollLeft = 300;
+ const maxOffsetInContainer = elements.container.offsetLeft +
+ elements.container.clientWidth - elements.sticky.clientWidth;
+ assert_equals(elements.sticky.offsetLeft, maxOffsetInContainer);
+ const maxOffsetInOuterSticky = elements.sticky.clientWidth -
+ elements.innerSticky.clientWidth;
+ assert_equals(elements.innerSticky.offsetLeft, maxOffsetInOuterSticky);
+}, 'neither sticky can escape their containing block');
+
+test(() => {
+ const elements = setupNestedStickyTest('left', 50, 300);
+ elements.scroller.scrollLeft = 100;
+ // The outer sticky has not stuck yet.
+ const nonStickyLeftX = elements.container.offsetLeft +
+ elements.filler.clientWidth;
+ assert_equals(elements.sticky.offsetLeft, nonStickyLeftX);
+ // But the inner sticky still cannot escape the outer sticky (as it is the
+ // containing block).
+ const maxOffsetInOuterSticky = elements.sticky.clientWidth -
+ elements.innerSticky.clientWidth;
+ assert_equals(elements.innerSticky.offsetLeft, maxOffsetInOuterSticky);
+}, 'the inner sticky cannot be pushed outside the outer sticky');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-right.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-right.html
new file mode 100644
index 0000000000..0f7e43f35a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-right.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<title>Nested right-constrained position:sticky elements should render correctly</title>
+
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that nested position:sticky elements with a right constraint render correctly" />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script src="../resources/sticky-util.js"></script>
+
+<body></body>
+
+<script>
+test(() => {
+ const elements = setupNestedStickyTest('right', 25, 35);
+ elements.scroller.scrollLeft = 200;
+ const nonStickyLeftX = elements.container.offsetLeft +
+ elements.filler.clientWidth;
+ assert_equals(elements.sticky.offsetLeft, nonStickyLeftX);
+ // The inner sticky should not be offset from the outer.
+ const nonStickyInnerLeftX = elements.sticky.clientWidth -
+ elements.innerSticky.clientWidth;
+ assert_equals(elements.innerSticky.offsetLeft, nonStickyInnerLeftX);
+}, 'before reaching the sticking point, neither sticky box should be offset');
+
+test(() => {
+ const elements = setupNestedStickyTest('right', 25, 50);
+ elements.scroller.scrollLeft = 150;
+ const nonStickyLeftX = elements.container.offsetLeft +
+ elements.filler.clientWidth;
+ assert_equals(elements.sticky.offsetLeft, nonStickyLeftX);
+ assert_equals(elements.innerSticky.offsetLeft, 50);
+}, 'the inner sticky can stick before the outer one if necessary');
+
+test(() => {
+ const elements = setupNestedStickyTest('right', 25, 35);
+ elements.scroller.scrollLeft = 100;
+
+ const nonStickyLeftX = elements.container.offsetLeft +
+ elements.filler.clientWidth;
+ const nonStickyBottomX = nonStickyLeftX + elements.sticky.clientWidth;
+ const targetBottomX = elements.scroller.clientWidth +
+ elements.scroller.scrollLeft - 25;
+ const stickyOffset = nonStickyBottomX - targetBottomX;
+ assert_equals(elements.sticky.offsetLeft, nonStickyLeftX - stickyOffset);
+
+ // The inner sticky has similar math, but its offsetLeft is relative to the
+ // sticky element and in this test is (height - the difference between the
+ // top values).
+ assert_equals(elements.innerSticky.offsetLeft, 40);
+}, 'both sticky boxes can be stuck at the same time');
+
+test(() => {
+ const elements = setupNestedStickyTest('right', 25, 100);
+ elements.scroller.scrollLeft = 0;
+ assert_equals(elements.sticky.offsetLeft, elements.container.offsetLeft);
+ assert_equals(elements.innerSticky.offsetLeft, 0);
+}, 'neither sticky can escape their containing block');
+
+test(() => {
+ const elements = setupNestedStickyTest('right', 25, 500);
+ elements.scroller.scrollLeft = 200;
+ // It doesn't matter how big the inner sticky offset is, it cannot escape its
+ // containing block (the outer sticky).
+ assert_equals(elements.innerSticky.offsetLeft, 0);
+}, 'the inner sticky cannot be pushed outside the outer sticky');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-table-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-table-ref.html
new file mode 100644
index 0000000000..36fabc3845
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-table-ref.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<title>Reference for nested position:sticky table elements should render correctly</title>
+
+<style>
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 250px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 200px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.contents {
+ height: 700px;
+}
+
+.indicator {
+ position: absolute;
+ left: 0;
+ background-color: green;
+ height: 50px;
+ width: 50px;
+}
+
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 50;
+ document.getElementById('scroller2').scrollTop = 125;
+ document.getElementById('scroller3').scrollTop = 250;
+});
+</script>
+
+<div>You should see three green rectangles below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="contents">
+ <div class="indicator" style="top: 100px;"></div>
+ </div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="contents">
+ <div class="indicator" style="top: 150px;"></div>
+ </div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="contents">
+ <div class="indicator" style="top: 250px;"></div>
+ </div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-table.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-table.html
new file mode 100644
index 0000000000..b2a8bf1e87
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-table.html
@@ -0,0 +1,133 @@
+<!DOCTYPE html>
+<title>Nested position:sticky table elements should render correctly</title>
+<link rel="match" href="position-sticky-nested-table-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that nested position:sticky table elements render correctly" />
+
+<script src="../resources/ref-rectangle.js"></script>
+
+<style>
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 250px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 200px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.contents {
+ height: 700px;
+}
+
+.prepadding {
+ height: 100px;
+}
+
+table {
+ border-collapse: collapse;
+}
+
+td, th {
+ height: 50px;
+ width: 50px;
+ padding: 0;
+}
+
+th {
+ background: green;
+}
+
+.sticky {
+ position: sticky;
+ top: 25px;
+}
+
+.indicator {
+ position: absolute;
+ left: 0;
+ background-color: red;
+ height: 50px;
+ width: 50px;
+}
+
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 50;
+ document.getElementById('scroller2').scrollTop = 125;
+ document.getElementById('scroller3').scrollTop = 250;
+});
+</script>
+
+<div>You should see three green rectangles below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="contents">
+ <div class="indicator" style="top: 100px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <thead class="sticky">
+ <tr class="sticky">
+ <th class="sticky"></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr><td></td></tr>
+ <tr><td></td></tr>
+ <tr><td></td></tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="contents">
+ <div class="indicator" style="top: 150px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <thead class="sticky">
+ <tr class="sticky">
+ <th class="sticky"></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr><td></td></tr>
+ <tr><td></td></tr>
+ <tr><td></td></tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="contents">
+ <div class="indicator" style="top: 250px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <thead class="sticky">
+ <tr class="sticky">
+ <th class="sticky"></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr><td></td></tr>
+ <tr><td></td></tr>
+ <tr><td></td></tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-thead-th.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-thead-th.html
new file mode 100644
index 0000000000..51f58b7591
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-thead-th.html
@@ -0,0 +1,133 @@
+<!DOCTYPE html>
+<title>Nested position:sticky table elements should render correctly</title>
+<link rel="match" href="position-sticky-nested-table-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that nested position:sticky table elements render correctly" />
+
+<script src="../resources/ref-rectangle.js"></script>
+
+<style>
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 250px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 200px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.contents {
+ height: 700px;
+}
+
+.prepadding {
+ height: 100px;
+}
+
+table {
+ border-collapse: collapse;
+}
+
+td, th {
+ height: 50px;
+ width: 50px;
+ padding: 0;
+}
+
+th {
+ background: green;
+}
+
+.sticky {
+ position: sticky;
+ top: 25px;
+}
+
+.indicator {
+ position: absolute;
+ left: 0;
+ background-color: red;
+ height: 50px;
+ width: 50px;
+}
+
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 50;
+ document.getElementById('scroller2').scrollTop = 125;
+ document.getElementById('scroller3').scrollTop = 250;
+});
+</script>
+
+<div>You should see three green rectangles below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="contents">
+ <div class="indicator" style="top: 100px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <thead class="sticky">
+ <tr>
+ <th class="sticky"></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr><td></td></tr>
+ <tr><td></td></tr>
+ <tr><td></td></tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="contents">
+ <div class="indicator" style="top: 150px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <thead class="sticky">
+ <tr>
+ <th class="sticky"></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr><td></td></tr>
+ <tr><td></td></tr>
+ <tr><td></td></tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="contents">
+ <div class="indicator" style="top: 250px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <thead class="sticky">
+ <tr>
+ <th class="sticky"></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr><td></td></tr>
+ <tr><td></td></tr>
+ <tr><td></td></tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-top.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-top.html
new file mode 100644
index 0000000000..90dc52dba8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-nested-top.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<title>Nested top-constrainted position:sticky elements should render correctly</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that nested position:sticky elements with a top constraint render correctly" />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script src="../resources/sticky-util.js"></script>
+
+<body></body>
+
+<script>
+test(() => {
+ const elements = setupNestedStickyTest('top', 50, 60);
+ elements.scroller.scrollTop = 100;
+ const nonStickyTopY = elements.container.offsetTop +
+ elements.filler.clientHeight;
+ assert_equals(elements.sticky.offsetTop, nonStickyTopY);
+ // The inner sticky should not be offset from the outer.
+ assert_equals(elements.innerSticky.offsetTop, 0);
+}, 'before reaching the sticking point, neither sticky box should be offset');
+
+test(() => {
+ const elements = setupNestedStickyTest('top', 50, 60);
+ elements.scroller.scrollTop = 145;
+ const nonStickyTopY = elements.container.offsetTop +
+ elements.filler.clientHeight;
+ assert_equals(elements.sticky.offsetTop, nonStickyTopY);
+ assert_equals(elements.innerSticky.offsetTop, 5);
+}, 'the inner sticky can stick before the outer one if necessary');
+
+test(() => {
+ const elements = setupNestedStickyTest('top', 50, 60);
+ elements.scroller.scrollTop = 200;
+
+ // This math cancels to sticky.offsetTop == (scroller.scrollTop + 50), but
+ // for clarity the calculations are left explicit.
+ const nonStickyTopY = elements.container.offsetTop +
+ elements.filler.clientHeight;
+ const targetTopY = elements.scroller.scrollTop + 50;
+ const stickyOffset = targetTopY - nonStickyTopY;
+ assert_equals(elements.sticky.offsetTop, nonStickyTopY + stickyOffset);
+
+ // The inner sticky has similar math, but its offsetTop is relative to the
+ // sticky element and in this test is the difference between the top values.
+ assert_equals(elements.innerSticky.offsetTop, 10);
+}, 'both sticky boxes can be stuck at the same time');
+
+test(() => {
+ const elements = setupNestedStickyTest('top', 50, 60);
+ elements.scroller.scrollTop = 300;
+ const maxOffsetInContainer = elements.container.offsetTop +
+ elements.container.clientHeight - elements.sticky.clientHeight;
+ assert_equals(elements.sticky.offsetTop, maxOffsetInContainer);
+ const maxOffsetInOuterSticky = elements.sticky.clientHeight -
+ elements.innerSticky.clientHeight;
+ assert_equals(elements.innerSticky.offsetTop, maxOffsetInOuterSticky);
+}, 'neither sticky can escape their containing block');
+
+test(() => {
+ const elements = setupNestedStickyTest('top', 50, 300);
+ elements.scroller.scrollTop = 100;
+ // The outer sticky has not stuck yet.
+ const nonStickyTopY = elements.container.offsetTop +
+ elements.filler.clientHeight;
+ assert_equals(elements.sticky.offsetTop, nonStickyTopY);
+ // But the inner sticky still cannot escape the outer sticky (as it is the
+ // containing block).
+ const maxOffsetInOuterSticky = elements.sticky.clientHeight -
+ elements.innerSticky.clientHeight;
+ assert_equals(elements.innerSticky.offsetTop, maxOffsetInOuterSticky);
+}, 'the inner sticky cannot be pushed outside the outer sticky');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-offset-overflow.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-offset-overflow.html
new file mode 100644
index 0000000000..4882e110eb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-offset-overflow.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<title>Sticky positioning can cause overflow but must be accessible.</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that a sticky positioned element
+does not extend overflow" />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+.container {
+ overflow-y: scroll;
+ width: 100px;
+ height: 100px;
+}
+
+.box {
+ background-color: green;
+ height: 50px;
+ width: 50px;
+}
+
+.sticky {
+ position: sticky;
+ top: 200px; /* Forces the sticky position element below the overflow. */
+}
+</style>
+
+<div id="scroller1" class="container">
+ <div class="sticky box"></div>
+</div>
+
+<script>
+test(() => {
+ var scroller = document.getElementById('scroller1');
+ var sticky = scroller.querySelector('.sticky');
+
+ var stickyOffset = sticky.offsetTop -
+ scroller.scrollTop - scroller.offsetTop;
+ assert_equals(stickyOffset, 50);
+ assert_equals(scroller.scrollHeight, 100);
+}, 'sticky position offset should be contained by scrolling box');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-offset-print.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-offset-print.html
new file mode 100644
index 0000000000..3954bbcf44
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-offset-print.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1485969">
+<link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id="scroller" style="position:relative; width:200px; height:100px; overflow:hidden;">
+ <div style="position:absolute; width:1000px;">
+ <div style="position:sticky; left:0; height:100px; width:100px; background:green;"></div>
+ </div>
+ <div style="width:100px; height:100px; background:red;"></div>
+</div>
+<script>
+document.getElementById('scroller').scrollLeft = 100;
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-offset-top-left.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-offset-top-left.html
new file mode 100644
index 0000000000..ade9e108cf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-offset-top-left.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<title>Sticky positioned element should be observable by offsetTop and offsetLeft</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that a sticky positioned element
+should be observable by offsetTop/offsetLeft." />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+body {
+ margin: 0;
+}
+
+.container {
+ position: relative; /* Required for offsetTop/offsetLeft tests. */
+ overflow: scroll;
+ width: 200px;
+ height: 200px;
+}
+
+.spacer {
+ width: 2000px;
+ height: 2000px;
+}
+
+.box {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+}
+
+.sticky {
+ position: sticky;
+ top: 50px;
+ left: 20px;
+}
+</style>
+
+<div id="scroller1" class="container">
+ <div class="spacer"></div>
+</div>
+
+<script>
+test(() => {
+ var scroller = document.getElementById('scroller1');
+ scroller.scrollTop = 100;
+ scroller.scrollLeft = 75;
+
+ var sticky = document.createElement('div');
+ sticky.className = 'sticky box';
+ scroller.insertBefore(sticky, scroller.querySelector('.spacer'));
+
+ assert_equals(sticky.offsetTop, scroller.scrollTop + 50);
+ assert_equals(sticky.offsetLeft, scroller.scrollLeft + 20);
+}, 'offsetTop/offsetLeft should be correct for sticky after script insertion');
+</script>
+
+<div id="scroller2" class="container">
+ <div id="sticky2" class="sticky box"></div>
+ <div class="spacer"></div>
+</div>
+
+<script>
+test(function() {
+ var scroller = document.getElementById('scroller2');
+ var sticky = document.getElementById('sticky2');
+ scroller.scrollTop = 100;
+ scroller.scrollLeft = 75;
+
+ var div = document.createElement('div');
+ div.style.height = '65px';
+ scroller.insertBefore(div, sticky);
+
+ assert_equals(sticky.offsetTop, scroller.scrollTop + 50);
+ assert_equals(sticky.offsetLeft, scroller.scrollLeft + 20);
+}, 'offsetTop/offsetLeft should be correct for sticky after script-caused layout');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-overflow-clip-container-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-overflow-clip-container-ref.html
new file mode 100644
index 0000000000..2a29b435a7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-overflow-clip-container-ref.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<title>Sticky elements should not consider overflow: clip containers as possible scroll ancestor</title>
+<style>
+body {
+ margin: 0;
+ overflow: hidden; /* hide scrollbars */
+}
+
+#container {
+ height: 300px;
+ overflow-y: scroll;
+}
+
+#overflowClipContainer {
+ overflow: visible;
+ height: 600px;
+}
+
+#sticky {
+ position: sticky;
+ top: 0;
+ height: 50px;
+ background-color: yellow;
+}
+</style>
+<script>
+function doTest()
+{
+ container.scrollTo(0, 50);
+}
+window.addEventListener('load', doTest, false);
+</script>
+<div id="container">
+ <div id="overflowClipContainer">
+ <div id="sticky"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-overflow-clip-container.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-overflow-clip-container.html
new file mode 100644
index 0000000000..63356349af
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-overflow-clip-container.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<title>Sticky elements should not consider overflow: clip containers as possible scroll ancestor</title>
+<link rel="match" href="position-sticky-overflow-clip-container-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that sticky elements do not consider overflow:clip containers as possible scroll ancestor"/>
+<style>
+body {
+ margin: 0;
+ overflow: hidden; /* hide scrollbars */
+}
+
+#container {
+ height: 300px;
+ overflow: auto;
+}
+
+#overflowClipContainer {
+ overflow: clip;
+ height: 600px;
+}
+
+#sticky {
+ position: sticky;
+ top: 0;
+ height: 50px;
+ background-color: yellow;
+}
+</style>
+<script>
+function doTest()
+{
+ container.scrollTo(0, 50);
+}
+window.addEventListener('load', doTest, false);
+</script>
+<div id="container">
+ <div id="overflowClipContainer">
+ <div id="sticky"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-overflow-hidden.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-overflow-hidden.html
new file mode 100644
index 0000000000..622ca8fbef
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-overflow-hidden.html
@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+<title>position:sticky elements should respect an overflow:hidden ancestor</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that position:sticky elements adhere to an overflow:hidden ancestor" />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script src="../resources/sticky-util.js"></script>
+
+<body></body>
+
+<script>
+test(() => {
+ const outer_scroller = document.createElement('div');
+ outer_scroller.style.width = '100px';
+ outer_scroller.style.height = '100px';
+ outer_scroller.style.overflow = 'scroll';
+
+ const inner_scroller = document.createElement('div');
+ inner_scroller.style.width = '80%';
+ inner_scroller.style.height = '200px';
+ inner_scroller.style.overflow = 'hidden';
+
+ const sticky = document.createElement('div');
+ sticky.style.width = '20px';
+ sticky.style.height = '20px';
+ sticky.style.position = 'sticky';
+ sticky.style.top = '0';
+ sticky.style.background = 'red';
+
+ const spacer = document.createElement('div');
+ spacer.style.height = '500px';
+
+ inner_scroller.appendChild(sticky);
+ inner_scroller.appendChild(spacer);
+ outer_scroller.appendChild(inner_scroller);
+ document.body.appendChild(outer_scroller);
+
+ outer_scroller.scrollTop = 50;
+
+ // The sticky should attach to the inner scroller, and so should not stick.
+ assert_equals(sticky.offsetTop, inner_scroller.offsetTop);
+}, 'A sticky element should attach to an overflow:hidden ancestor');
+
+// This tests a specific bug in Firefox where the sticky element incorrectly
+// started sticking when inside a table. See https://bugzilla.mozilla.org/show_bug.cgi?id=1488810
+test(() => {
+ const outer_scroller = document.createElement('div');
+ outer_scroller.style.width = '100px';
+ outer_scroller.style.height = '100px';
+ outer_scroller.style.overflow = 'scroll';
+
+ const table = document.createElement('div');
+ table.style.display = 'table';
+
+ const tr = document.createElement('div');
+ tr.style.display = 'table-row';
+
+ const inner_scroller = document.createElement('div');
+ inner_scroller.style.display = 'table-cell';
+ inner_scroller.style.overflow = 'hidden';
+
+ const sticky = document.createElement('div');
+ sticky.style.width = '20px';
+ sticky.style.height = '20px';
+ sticky.style.position = 'sticky';
+ sticky.style.top = '0';
+ sticky.style.background = 'red';
+
+ const spacer = document.createElement('div');
+ spacer.style.height = '500px';
+
+ inner_scroller.appendChild(sticky);
+ inner_scroller.appendChild(spacer);
+ tr.append(inner_scroller);
+ table.appendChild(tr);
+ outer_scroller.appendChild(table);
+ document.body.appendChild(outer_scroller);
+
+ outer_scroller.scrollTop = 50;
+
+ // The sticky should attach to the inner scroller, and so should not stick.
+ assert_equals(sticky.offsetTop, inner_scroller.offsetTop);
+}, 'A sticky element should attach to an overflow:hidden ancestor inside a table');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-overflow-padding.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-overflow-padding.html
new file mode 100644
index 0000000000..71b74e7886
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-overflow-padding.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<title>position:sticky elements should respect padding on their ancestor overflow element</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that position:sticky elements respect padding on their ancestor overflow element" />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script src="../resources/sticky-util.js"></script>
+
+<body></body>
+
+<script>
+test(() => {
+ const elements = setupStickyTest('top', 50);
+ elements.scroller.style.padding = '20px 0';
+
+ // Before sticking; the element isn't within the padding range.
+ elements.scroller.scrollTop = 150;
+ const nonStickyTopY = elements.container.offsetTop +
+ elements.filler.clientHeight;
+ assert_equals(elements.sticky.offsetTop, nonStickyTopY);
+}, 'A sticky element should not be affected by ancestor padding until it ' +
+ 'reaches it');
+
+test(() => {
+ const elements = setupStickyTest('top', 50);
+ elements.sticky.style.top = '0';
+ elements.scroller.style.padding = '20px 0';
+
+ elements.scroller.scrollTop = 200;
+
+ // This math cancels to sticky.offsetTop == (scroller.scrollTop + 50), but
+ // for clarity the calculations are left explicit.
+ const nonStickyTopY = elements.container.offsetTop +
+ elements.filler.clientHeight;
+ const targetTopY = elements.scroller.scrollTop;
+ const stickyOffset = targetTopY - nonStickyTopY;
+
+ assert_equals(elements.sticky.offsetTop, nonStickyTopY + stickyOffset + 20);
+}, 'A sticky element should be offset by ancestor padding even when stuck');
+
+test(() => {
+ const elements = setupStickyTest('top', 50);
+ elements.sticky.style.top = '0';
+ elements.scroller.style.padding = '20px 0';
+
+ elements.scroller.scrollTop = 315;
+ const maxOffsetInContainer = elements.container.offsetTop +
+ elements.container.clientHeight - elements.sticky.clientHeight;
+ assert_equals(elements.sticky.offsetTop, maxOffsetInContainer);
+}, 'Ancestor overflow padding does not allow a sticky element to escape its ' +
+ 'container');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-parsing.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-parsing.html
new file mode 100644
index 0000000000..b147429e69
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-parsing.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<title>Position value 'sticky' should be a valid value</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#position-property" />
+<meta name="assert" content="This test checks that setting position to 'sticky'
+should be allowed." />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<!-- We need something to create elements in. -->
+<body></body>
+
+<script>
+const displayTypes = [
+ 'block',
+ 'inline',
+ 'run-in',
+ 'flow',
+ 'flow-root',
+ 'table',
+ 'flex',
+ 'grid',
+ 'ruby',
+ 'subgrid',
+ 'list-item',
+ 'table-row-group',
+ 'table-header-group',
+ 'table-footer-group',
+ 'table-row',
+ 'table-cell',
+ 'table-caption',
+ // Sticky does not apply to table-column or table-column-group, but the
+ // computed value should still be sticky.
+ 'table-column',
+ 'table-column-group',
+ 'ruby-base',
+ 'ruby-text',
+ 'ruby-base-container',
+ 'ruby-text-container',
+ 'contents',
+ 'none',
+];
+
+test(() => {
+ for (displayValue of displayTypes) {
+ let div = document.createElement('div');
+ let style = `position: sticky; display: ${displayValue};`;
+ div.setAttribute('style', style);
+ document.body.appendChild(div);
+
+ // We only check display values that the browser under test recognizes.
+ if (div.style.display == displayValue) {
+ assert_equals(getComputedStyle(div).position, 'sticky',
+ `Expected sticky to be valid for display: ${displayValue}`);
+ }
+ document.body.removeChild(div);
+ }
+}, 'The value of sticky for the position property should be parsed correctly');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-rendering-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-rendering-ref.html
new file mode 100644
index 0000000000..b4411c3bed
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-rendering-ref.html
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<title>Reference for position:sticky elements should be rendered at their sticky offset</title>
+
+<style>
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 250px;
+}
+
+.inlineGroup {
+ display: inline-block;
+ position: relative;
+ width: 250px;
+ height: 150px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 200px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.inlineGroup .scroller {
+ position: relative;
+ width: 200px;
+ height: 100px;
+ overflow-x: auto;
+ overflow-y: hidden;
+}
+
+.contents {
+ height: 500px;
+}
+
+.inlineGroup .contents {
+ height: 100%;
+ width: 500px;
+}
+
+.indicator {
+ background-color: green;
+ position: absolute;
+}
+
+.box {
+ width: 100%;
+ height: 100px;
+}
+
+.inlineGroup .box {
+ height: 100%;
+ width: 100px;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 125;
+ document.getElementById('scroller2').scrollTop = 50;
+ document.getElementById('scroller3').scrollLeft = 125;
+ document.getElementById('scroller4').scrollLeft = 75;
+});
+</script>
+
+<div>You should see four green squares below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="contents">
+ <div class="indicator box" style="top: 175px;"></div>
+ </div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="contents">
+ <div class="indicator box" style="top: 125px;"></div>
+ </div>
+ </div>
+</div>
+
+<!-- Force break to make sure we are within 800px wide. -->
+<div></div>
+
+<div class="inlineGroup">
+ <div id="scroller3" class="scroller">
+ <div class="contents">
+ <div class="indicator box" style="left: 175px;"></div>
+ </div>
+ </div>
+</div>
+
+<div class="inlineGroup">
+ <div id="scroller4" class="scroller">
+ <div class="contents">
+ <div class="indicator box" style="left: 150px;"></div>
+ </div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-rendering.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-rendering.html
new file mode 100644
index 0000000000..a4e03c59d8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-rendering.html
@@ -0,0 +1,159 @@
+<!DOCTYPE html>
+<title>position:sticky elements should be rendered at their sticky offset</title>
+<link rel="match" href="position-sticky-rendering-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that position:sticky elements are rendered correctly" />
+
+<script src="../resources/ref-rectangle.js"></script>
+
+<style>
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 250px;
+}
+
+.inlineGroup {
+ display: inline-block;
+ position: relative;
+ width: 250px;
+ height: 150px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 200px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.inlineGroup .scroller {
+ position: relative;
+ width: 200px;
+ height: 100px;
+ overflow-x: auto;
+ overflow-y: hidden;
+}
+
+.contents {
+ height: 500px;
+}
+
+.inlineGroup .contents {
+ height: 100%;
+ width: 500px;
+}
+
+.prepadding {
+ height: 100px;
+}
+
+.inlineGroup .prepadding {
+ display: inline-block;
+ height: 100%;
+ width: 100px;
+}
+
+.container {
+ height: 200px;
+}
+
+.inlineGroup .container {
+ display: inline-block;
+ height: 100%;
+ width: 200px;
+}
+
+.filler {
+ height: 100px;
+}
+
+.inlineGroup .filler {
+ display: inline-block;
+ height: 100%;
+ width: 100px;
+}
+
+.indicator {
+ background-color: red;
+ position: absolute;
+}
+
+.sticky {
+ background-color: green;
+ position: sticky;
+}
+
+.box {
+ width: 100%;
+ height: 100px;
+}
+
+.inlineGroup .box {
+ display: inline-block;
+ height: 100%;
+ width: 100px;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 125;
+ document.getElementById('scroller2').scrollTop = 50;
+ document.getElementById('scroller3').scrollLeft = 125;
+ document.getElementById('scroller4').scrollLeft = 75;
+ createIndicatorForStickyElements(document.querySelectorAll('.sticky'));
+});
+</script>
+
+<div>You should see four green squares below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator box" style="top: 175px;"></div>
+ <div class="contents">
+ <div class="prepadding"></div>
+ <div class="container">
+ <div style="top: 50px;" class="sticky box"></div>
+ </div>
+ </div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator box" style="top: 125px;"></div>
+ <div class="contents">
+ <div class="prepadding"></div>
+ <div class="container">
+ <div class="filler"></div>
+ <div style="bottom: 25px;" class="sticky box"></div>
+ </div>
+ </div>
+ </div>
+</div>
+
+<!-- Force break to make sure we are within 800px wide. -->
+<div></div>
+
+<div class="inlineGroup">
+ <div id="scroller3" class="scroller">
+ <div class="indicator box" style="left: 175px;"></div>
+ <div class="contents">
+ <!-- As these elements are inline, they are whitespace sensitive. -->
+ <div class="prepadding"></div><div class="container"><div style="left: 50px;" class="sticky box"></div></div>
+ </div>
+ </div>
+</div>
+
+<div class="inlineGroup">
+ <div id="scroller4" class="scroller">
+ <div class="indicator box" style="left: 150px;"></div>
+ <div class="contents">
+ <!-- As these elements are inline, they are whitespace sensitive. -->
+ <div class="prepadding"></div><div class="container"><div class="filler"></div><div style="right: 25px;" class="sticky box"></div></div>
+ </div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-right-002.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-right-002.html
new file mode 100644
index 0000000000..e83189a498
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-right-002.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Position Test: sticky element with right offset specified with px unit</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos">
+ <link rel="match" href="reference/position-sticky-right-002-ref.html">
+
+ <meta name="flags" content="">
+
+ <style>
+ div.scrolling-container
+ {
+ background-image: url("support/100x100-red.png");
+ background-repeat: no-repeat;
+ height: 150px;
+ margin-bottom: 30px;
+ overflow-y: hidden;
+ position: static;
+ white-space: nowrap;
+ width: 250px;
+ }
+
+ div#first-scrolling-container
+ {
+ background-position: 75px top;
+ }
+
+ div#second-scrolling-container
+ {
+ background-position: 50px top;
+ }
+
+ div#third-scrolling-container
+ {
+ background-position: left top;
+ }
+
+ div.horizontal-spacer
+ {
+ display: inline-block;
+ height: 100%;
+ width: 100px;
+ }
+
+ div.content
+ {
+ display: inline-block;
+ height: 100%;
+ width: 300px;
+ }
+
+ div.sticky
+ {
+ background-color: green;
+ display: inline-block;
+ height: 100px;
+ position: sticky;
+ right: 100px;
+ vertical-align: top;
+ width: 100px;
+ }
+ </style>
+
+ <body onload="document.getElementById(&quot;first-scrolling-container&quot;).scrollLeft = 25; document.getElementById(&quot;second-scrolling-container&quot;).scrollLeft = 100; document.getElementById(&quot;third-scrolling-container&quot;).scrollLeft = 200;">
+
+ <p>Test passes if there are 3 filled green squares and <strong>no red</strong>.
+
+ <!--
+ first-scrolling-container: before reaching the sticking point
+ -->
+
+ <div id="first-scrolling-container" class="scrolling-container">
+
+ <div class="horizontal-spacer"></div><div class="content"><div class="horizontal-spacer"></div><div id="first-sticky" class="sticky"></div><div class="horizontal-spacer"></div></div><div class="horizontal-spacer"></div>
+
+ </div>
+
+ <!--
+ second-scrolling-container: when reaching the sticking point and beyond
+ -->
+
+ <div id="second-scrolling-container" class="scrolling-container">
+
+ <div class="horizontal-spacer"></div><div class="content"><div class="horizontal-spacer"></div><div id="second-sticky" class="sticky"></div><div class="horizontal-spacer"></div></div><div class="horizontal-spacer"></div>
+
+ </div>
+
+
+ <div id="third-scrolling-container" class="scrolling-container">
+
+ <div class="horizontal-spacer"></div><div class="content"><div class="horizontal-spacer"></div><div id="third-sticky" class="sticky"></div><div class="horizontal-spacer"></div></div><div class="horizontal-spacer"></div>
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-right-003.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-right-003.html
new file mode 100644
index 0000000000..ea712a99da
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-right-003.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Position Test: sticky element with right offset specified with percentage unit</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos">
+ <link rel="match" href="reference/position-sticky-right-002-ref.html">
+
+ <meta name="flags" content="">
+
+ <style>
+ div.scrolling-container
+ {
+ background-image: url("support/100x100-red.png");
+ background-repeat: no-repeat;
+ height: 150px;
+ margin-bottom: 30px;
+ overflow-y: hidden;
+ position: static;
+ white-space: nowrap;
+ width: 250px;
+ }
+
+ div#first-scrolling-container
+ {
+ background-position: 75px top;
+ }
+
+ div#second-scrolling-container
+ {
+ background-position: 50px top;
+ }
+
+ div#third-scrolling-container
+ {
+ background-position: left top;
+ }
+
+ div.horizontal-spacer
+ {
+ display: inline-block;
+ height: 100%;
+ width: 100px;
+ }
+
+ div.content
+ {
+ display: inline-block;
+ height: 100%;
+ width: 300px;
+ }
+
+ div.sticky
+ {
+ background-color: green;
+ display: inline-block;
+ height: 100px;
+ position: sticky;
+ right: 40%;
+ vertical-align: top;
+ width: 100px;
+ }
+ </style>
+
+ <body onload="document.getElementById(&quot;first-scrolling-container&quot;).scrollLeft = 25; document.getElementById(&quot;second-scrolling-container&quot;).scrollLeft = 100; document.getElementById(&quot;third-scrolling-container&quot;).scrollLeft = 200;">
+
+ <p>Test passes if there are 3 filled green squares and <strong>no red</strong>.
+
+ <!--
+ first-scrolling-container: before reaching the sticking point
+ -->
+
+ <div id="first-scrolling-container" class="scrolling-container">
+
+ <div class="horizontal-spacer"></div><div class="content"><div class="horizontal-spacer"></div><div id="first-sticky" class="sticky"></div><div class="horizontal-spacer"></div></div><div class="horizontal-spacer"></div>
+
+ </div>
+
+ <!--
+ second-scrolling-container: when reaching the sticking point and beyond
+ -->
+
+ <div id="second-scrolling-container" class="scrolling-container">
+
+ <div class="horizontal-spacer"></div><div class="content"><div class="horizontal-spacer"></div><div id="second-sticky" class="sticky"></div><div class="horizontal-spacer"></div></div><div class="horizontal-spacer"></div>
+
+ </div>
+
+
+ <div id="third-scrolling-container" class="scrolling-container">
+
+ <div class="horizontal-spacer"></div><div class="content"><div class="horizontal-spacer"></div><div id="third-sticky" class="sticky"></div><div class="horizontal-spacer"></div></div><div class="horizontal-spacer"></div>
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-right.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-right.html
new file mode 100644
index 0000000000..82d0e9af1d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-right.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<title>position:sticky elements should respect the right constraint</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that position:sticky elements obey their right anchor after scrolling" />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script src="../resources/sticky-util.js"></script>
+
+<body></body>
+
+<script>
+test(() => {
+ const elements = setupStickyTest('right', 25);
+ elements.scroller.scrollLeft = 200;
+ const nonStickyLeftX = elements.container.offsetLeft +
+ elements.filler.clientWidth;
+ assert_equals(elements.sticky.offsetLeft, nonStickyLeftX);
+}, 'before reaching the sticking point the sticky box should not be offset');
+
+test(() => {
+ const elements = setupStickyTest('right', 25);
+ elements.scroller.scrollLeft = 75;
+
+ const nonStickyLeftX = elements.container.offsetLeft +
+ elements.filler.clientWidth;
+ const nonStickyRightX = nonStickyLeftX + elements.sticky.clientWidth;
+ const targetRightX = elements.scroller.clientWidth +
+ elements.scroller.scrollLeft - 25;
+ const stickyOffset = nonStickyRightX - targetRightX;
+
+ assert_equals(elements.sticky.offsetLeft, nonStickyLeftX - stickyOffset);
+}, 'after reaching the sticking point the sticky box should be offset');
+
+test(() => {
+ const elements = setupStickyTest('right', 25);
+ elements.scroller.scrollLeft = 15;
+ assert_equals(elements.sticky.offsetLeft, elements.container.offsetLeft);
+}, 'the sticky box should not be pushed outside its containing block');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-root-scroller.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-root-scroller.html
new file mode 100644
index 0000000000..596fd9b240
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-root-scroller.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<title>position:sticky should operate correctly for the root scroller</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that position:sticky elements work when using the root (document) scroller" />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+body {
+ /* Assumption: 3000px is taller than any user agents test window size. */
+ height: 3000px;
+}
+
+#sticky {
+ position: sticky;
+ top: 50px;
+ width: 200px;
+ height: 200px;
+ background-color: green;
+}
+</style>
+
+<div id="sticky"></div>
+
+<script>
+test(() => {
+ window.scrollTo(0, 700);
+ assert_equals(sticky.offsetTop, 700 + 50);
+}, 'Sticky elements work with the root (document) scroller');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-scroll-offset-clamp-crash.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-scroll-offset-clamp-crash.html
new file mode 100644
index 0000000000..ec6fb90cca
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-scroll-offset-clamp-crash.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1498297">
+<style>
+* {
+ margin-top: 100px;
+ padding-left: 100px;
+ position: sticky;
+ bottom: 0px;
+}
+</style>
+<select id="select1" multiple="multiple" style="writing-mode: vertical-rl">
+ <optgroup id="optgroup">text</optgroup>
+</select>
+<select id="select2" >text</select>
+<script>
+document.body.offsetTop;
+select2.add(optgroup);
+document.body.offsetTop;
+select1.length = 1;
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-scroll-reposition-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-scroll-reposition-ref.html
new file mode 100644
index 0000000000..487a2322fc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-scroll-reposition-ref.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<title>Test that style mutation of contain:strict plus position:sticky updates sticky position</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos">
+<link rel="author" title="Chris Harrelson" href="mailto:chrishtr@chromium.org">
+<div id="scroller" style="width: 200px; height: 200px; overflow-y: scroll;
+ will-change: transform;">
+ <div id="scrollbar" style="width: 100px; height: 100px; position: sticky; background: lightblue;
+ top: 5px; left: 50px; contain: strict;"></div>
+ <div style="width: 100px; height: 500px;"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-scroll-reposition.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-scroll-reposition.html
new file mode 100644
index 0000000000..b75275c64f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-scroll-reposition.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<html class="reftest-wait">
+<title>Test that style mutation of contain:strict plus position:sticky updates sticky position</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos">
+<link rel="author" title="Chris Harrelson" href="mailto:chrishtr@chromium.org">
+<link rel="match" href="position-sticky-scroll-reposition-ref.html">
+<div id="scroller" style="width: 200px; height: 200px; overflow-y: scroll;
+ will-change: transform;">
+ <div id="sticky" style="width: 100px; height: 100px; position: sticky; background: lightblue;
+ top: 50px; left: 50px; contain: strict;"></div>
+ <div style="width: 100px; height: 500px;"></div>
+</div>
+<script src="/common/reftest-wait.js"></script>
+<script>
+ requestAnimationFrame(() =>
+ requestAnimationFrame(() => {
+ sticky.style.top = '5px';
+ takeScreenshot();
+ }));
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-scroll-with-clip-and-abspos-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-scroll-with-clip-and-abspos-ref.html
new file mode 100644
index 0000000000..d9fe863d80
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-scroll-with-clip-and-abspos-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<title>position:sticky should operate correctly</title>
+<link rel="author" href="mailto:masonf@chromium.org">
+
+
+
+
+<div style="position: fixed;">There should be text visible below.</div>
+<div style="height: 200px;width:600px;position: fixed;top: 0px;">
+ <div style="position: relative;top: 100px;">
+ <div style="height: 150px;width: 500px;position: absolute;backface-visibility: hidden;background: white;">
+ </div>
+ <div style="overflow: hidden;">
+ <a style="position: relative;">THIS SHOULD STAY VISIBLE<BR>IF YOU SCROLL DOWN</a>
+ </div>
+ </div>
+</div>
+<div style="height: 2200px;">
+</div>
+<script>
+ window.onload = function() {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ window.scrollTo(0,300);
+ document.documentElement.classList.remove("reftest-wait");
+ });
+ });
+ };
+</script>
+</html>
+
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-scroll-with-clip-and-abspos.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-scroll-with-clip-and-abspos.html
new file mode 100644
index 0000000000..fb7edfe498
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-scroll-with-clip-and-abspos.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<title>position:sticky should operate correctly</title>
+<link rel="author" href="mailto:masonf@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that the combination of position:sticky, overflow clip, and out-of-flow descendants are properly displayed when scrolled" />
+<link rel="match" href="position-sticky-scroll-with-clip-and-abspos-ref.html">
+
+<div style="position: fixed;">There should be text visible below.</div>
+<div style="height: 200px;width:600px;position: sticky;top: 0px;">
+ <div style="position: relative;top: 100px;">
+ <div style="height: 150px;width: 500px;position: absolute;backface-visibility: hidden;background: white;">
+ </div>
+ <div style="overflow: hidden;">
+ <a style="position: relative;">THIS SHOULD STAY VISIBLE<BR>IF YOU SCROLL DOWN</a>
+ </div>
+ </div>
+</div>
+<div style="height: 2000px;">
+</div>
+<script>
+ window.onload = function() {
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ window.scrollTo(0,300);
+ document.documentElement.classList.remove("reftest-wait");
+ });
+ });
+ };
+</script>
+</html>
+
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-scrollIntoView.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-scrollIntoView.html
new file mode 100644
index 0000000000..6fb4723529
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-scrollIntoView.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<title>Scrolling to sticky position elements uses their unshifted position</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#stickypos-scroll" />
+<meta name="assert" content="This test checks that scrolling to sticky position elements uses their initial position" />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+
+h1 {
+ position: sticky;
+ background: #ddd;
+ border: 1px solid black;
+ top: 0px;
+ bottom: 0px;
+}
+
+section {
+ height: 100vh;
+}
+</style>
+
+<body>
+ <h1>Title 1</h1>
+ <section></section>
+ <h1>Title 2</h1>
+ <section></section>
+ <h1>Title 3</h1>
+ <section></section>
+
+<script>
+test(() => {
+ window.scrollTo(0, 0);
+ const element = document.querySelectorAll('h1')[2];
+ element.scrollIntoView();
+ assert_approx_equals(document.scrollingElement.scrollTop, element.offsetTop, 1);
+}, 'scrolling a sticky element into view should use its unshifted position');
+</script>
+</body>
+
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-scrolled-remove-sibling.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-scrolled-remove-sibling.html
new file mode 100644
index 0000000000..845454e1b3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-scrolled-remove-sibling.html
@@ -0,0 +1,99 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Positioned Layout Test: element with 'position: sticky' and removing a sibling in the vertical axis and in the horizontal axis</title>
+
+ <link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos">
+
+ <meta name="flags" content="">
+
+ <style>
+ div#scrollingContainerVert
+ {
+ background-color: red;
+ height: 100px;
+ overflow: auto;
+ width: 200px;
+ }
+
+ div#scrollingContainerHoriz
+ {
+ background-color: red;
+ height: 100px;
+ overflow-x: auto;
+ overflow-y: hidden;
+ width: 200px;
+ }
+
+ div#elemStickyVert
+ {
+ background-color: green;
+ height: 100px;
+ position: sticky;
+ top: 0px;
+ }
+
+ div#scrollingContainerHoriz > div
+ {
+ display: inline-block;
+ height: 100%;
+ }
+
+ div#elemStickyHoriz
+ {
+ background-color: green;
+ left: 0px;
+ position: sticky;
+ width: 200px;
+ }
+
+ div#tallItem
+ {
+ height: 600px;
+ }
+
+ div#wideItem
+ {
+ width: 600px;
+ }
+ </style>
+
+
+ <script src="/resources/testharness.js"></script>
+
+ <script src="/resources/testharnessreport.js"></script>
+
+ <p>Test passes if there is a filled green square and <strong>no scrollbar</strong>.
+
+ <div id="scrollingContainerVert">
+
+ <div id="elemStickyVert"></div>
+
+ <div id="tallItem"></div>
+
+ </div>
+
+
+ <div id="scrollingContainerHoriz">
+
+ <div id="elemStickyHoriz"></div><div id="wideItem"></div>
+
+ </div>
+
+
+ <script>
+ test(()=> {
+ scrollingContainerVert.scrollTop = 600;
+ tallItem.style.display = "none";
+ assert_equals(scrollingContainerVert.scrollHeight, 100);
+ }, "Sticky position and its overflow contribution in the vertical axis");
+
+ test(()=> {
+ scrollingContainerHoriz.scrollLeft = 600;
+ wideItem.style.display = "none";
+ assert_equals(scrollingContainerHoriz.scrollWidth, 200);
+ }, "Sticky position and its overflow contribution in the horizontal axis");
+ </script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-stacking-context-002.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-stacking-context-002.html
new file mode 100644
index 0000000000..1cc162880a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-stacking-context-002.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Positioned Layout Test: an element with 'position: sticky' creates a stacking context</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+ <link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos">
+
+ <meta name="assert" content="This test checks that an element with 'position: sticky' creates a stacking context. In this test, the first 2 divs have the same 'auto' z-index value but since div#sticky is last in document tree order, then it must overlap div#overlapped-red. The final div#overlap-bottom-half-of-sticky exists to make sure that the div#sticky is squeezed, is 'sandwiched' between the other 2.">
+
+ <style>
+ div
+ {
+ height: 100px;
+ width: 100px;
+ }
+
+ div#overlapped-red
+ {
+ background-color: red;
+ position: absolute;
+ }
+
+ div#sticky
+ {
+ background: linear-gradient(to bottom, green 51%, red 49%);
+ position: sticky;
+ }
+
+ div#overlap-bottom-half-of-sticky
+ {
+ background-color: green;
+ bottom: 50px;
+ height: 50px;
+ position: relative;
+ }
+ </style>
+
+ <p>Test passes if there is a filled green square and <strong>no red</strong>.
+
+ <div id="overlapped-red"></div>
+
+ <div id="sticky"></div>
+
+ <div id="overlap-bottom-half-of-sticky"></div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-stacking-context-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-stacking-context-ref.html
new file mode 100644
index 0000000000..2db17cc424
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-stacking-context-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>Reference for position: sticky should create a stacking context</title>
+
+<style>
+.indicator {
+ background-color: green;
+}
+
+.box {
+ width: 200px;
+ height: 200px;
+}
+</style>
+
+<div>You should see a single green box below. No red or blue should be visible.</div>
+
+<div class="indicator box"></div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-stacking-context.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-stacking-context.html
new file mode 100644
index 0000000000..4e91dfbd91
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-stacking-context.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<title>position: sticky should create a stacking context</title>
+<link rel="match" href="position-sticky-stacking-context-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="position:sticky elements should create a stacking context" />
+
+<script src="../resources/ref-rectangle.js"></script>
+
+<style>
+.indicator {
+ position: absolute;
+ background-color: green;
+ z-index: 1;
+}
+
+.sticky {
+ position: sticky;
+ z-index: 0;
+}
+
+.child {
+ position: relative;
+ background-color: red;
+ z-index: 2;
+}
+
+.box {
+ width: 200px;
+ height: 200px;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ createIndicatorForStickyElements(document.querySelectorAll('.sticky'));
+})
+</script>
+
+<div>You should see a single green box below. No red or blue should be visible.</div>
+
+<div class="indicator box"></div>
+<div class="sticky box">
+ <!-- Because sticky forms a stacking context, this child remains on bottom
+ even though it has a higher z-index than the indicator box. -->
+ <div class="child box"></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-parts-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-parts-ref.html
new file mode 100644
index 0000000000..9ba42e18b2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-parts-ref.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<title>Nested position:sticky table elements should render correctly</title>
+<style>
+.scroller {
+ width: 100px;
+ height: 250px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.contents {
+ height: 700px;
+}
+
+table {
+ border-collapse: collapse;
+}
+
+#child, td, th {
+ height: 50px;
+ width: 50px;
+ padding: 0;
+ background: green;
+}
+
+.prepadding {
+ height: 155px;
+}
+
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 150;
+});
+</script>
+
+<div>There should be a green square at the top of the scroll view and no red or blue visible.</div>
+
+ <div id="scroller1" class="scroller">
+ <div class="contents">
+ <div class="prepadding"></div>
+ <table>
+ <tbody>
+ <tr><td><div id="child"></div></td></tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-parts.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-parts.html
new file mode 100644
index 0000000000..eb32099d44
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-parts.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<title>Nested position:sticky table elements should render correctly</title>
+<link rel="match" href="position-sticky-table-parts-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that nested position:sticky table elements render correctly" />
+
+<script src="../resources/ref-rectangle.js"></script>
+
+<style>
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 250px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.contents {
+ height: 700px;
+}
+
+table {
+ border-collapse: collapse;
+}
+
+.child, td, th {
+ height: 50px;
+ width: 50px;
+ padding: 0;
+}
+
+.child {
+ background: green;
+}
+
+table * {
+ position: sticky;
+ top: 5px;
+}
+
+.indicator {
+ position: absolute;
+ left: 0;
+ background-color: red;
+ height: 50px;
+ width: 50px;
+}
+
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.body.offsetTop;
+ document.getElementById('scroller1').scrollTop = 150;
+ createIndicatorForStickyElements(document.querySelectorAll('.sticky'));
+});
+</script>
+
+<div>There should be a green square at the top of the scroll view and no red or blue visible.</div>
+
+<div id="scroller1" class="scroller">
+ <div class="contents">
+ <div class="indicator" style="top: 155px;"></div>
+ <table>
+ <tbody>
+ <tr><td><div class="child"></div></td></tr>
+ <tr><td></td></tr>
+ <tr><td></td></tr>
+ <tr><td></td></tr>
+ <tr><td></td></tr>
+ <tr><td></td></tr>
+ <tr><td></td></tr>
+ </tbody>
+ </table>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-bottom-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-bottom-ref.html
new file mode 100644
index 0000000000..e851315641
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-bottom-ref.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<title>Reference for position:sticky bottom constraint should behave correctly for &lt;td&gt; elements</title>
+
+<style>
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 150px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.contents {
+ height: 550px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: green;
+ left: 0;
+ height: 50px;
+ width: 50px;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 0;
+ document.getElementById('scroller2').scrollTop = 75;
+ document.getElementById('scroller3').scrollTop = 150;
+});
+</script>
+
+<div>You should see three green boxes below. No red should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="top: 100px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="top: 150px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="top: 200px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-bottom.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-bottom.html
new file mode 100644
index 0000000000..7cd3b8d695
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-bottom.html
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<title>position:sticky bottom constraint should behave correctly for &lt;td&gt; elements</title>
+<link rel="match" href="position-sticky-table-td-bottom-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that the position:sticky bottom constraint behaves correctly for &lt;td&gt; elements" />
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 150px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.prepadding {
+ height: 100px;
+}
+
+.postpadding {
+ height: 250px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 0;
+ height: 50px;
+ width: 50px;
+}
+
+.sticky {
+ position: sticky;
+ bottom: 25px;
+ background-color: green;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 0;
+ document.getElementById('scroller2').scrollTop = 75;
+ document.getElementById('scroller3').scrollTop = 150;
+});
+</script>
+
+<div>You should see three green boxes below. No red should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="top: 100px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td class="sticky"><div></div></td></td>
+ <tr><td><div></div></td></tr>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="top: 150px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td class="sticky"><div></div></td></td>
+ <tr><td><div></div></td></tr>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="top: 200px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td class="sticky"><div></div></td></td>
+ <tr><td><div></div></td></tr>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-left-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-left-ref.html
new file mode 100644
index 0000000000..40f80128d1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-left-ref.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<title>Reference for position:sticky left constraint should behave correctly for &lt;td&gt; elements</title>
+
+<style>
+.group {
+ position: relative;
+ width: 250px;
+ height: 150px;
+}
+
+.scroller {
+ position: relative;
+ width: 200px;
+ height: 100px;
+ overflow-x: auto;
+ overflow-y: hidden;
+}
+
+.contents {
+ height: 10px;
+ width: 500px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: green;
+ top: 0;
+ height: 50px;
+ width: 50px;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollLeft = 50;
+ document.getElementById('scroller2').scrollLeft = 175;
+ document.getElementById('scroller3').scrollLeft = 250;
+});
+</script>
+
+<div>You should see three green boxes below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="left: 150px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="left: 200px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="left: 250px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-left.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-left.html
new file mode 100644
index 0000000000..34d31f3eb1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-left.html
@@ -0,0 +1,118 @@
+<!DOCTYPE html>
+<title>position:sticky left constraint should behave correctly for &lt;td&gt; elements</title>
+<link rel="match" href="position-sticky-table-td-left-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that the position:sticky left constraint behaves correctly for &lt;td&gt; elements" />
+
+<script src="../resources/ref-rectangle.js"></script>
+
+<style>
+table {
+ border-collapse: collapse;
+ margin-left: 100px;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ position: relative;
+ width: 250px;
+ height: 150px;
+}
+
+.scroller {
+ position: relative;
+ width: 200px;
+ height: 100px;
+ overflow-x: auto;
+ overflow-y: hidden;
+}
+
+.postpadding {
+ height: 10px;
+ width: 500px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ top: 0;
+ height: 50px;
+ width: 50px;
+}
+
+.sticky {
+ position: sticky;
+ left: 25px;
+ background-color: green;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollLeft = 50;
+ document.getElementById('scroller2').scrollLeft = 175;
+ document.getElementById('scroller3').scrollLeft = 250;
+ createIndicatorForStickyElements(document.querySelectorAll('.sticky'));
+});
+</script>
+
+<div>You should see three green boxes below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="left: 150px;"></div>
+ <table>
+ <tbody>
+ <tr>
+ <td><div></div></td>
+ <td class="sticky"><div></div></td>
+ <td><div></div></td>
+ <td><div></div></td>
+ </tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="left: 200px;"></div>
+ <table>
+ <tbody>
+ <tr>
+ <td><div></div></td>
+ <td class="sticky"><div></div></td>
+ <td><div></div></td>
+ <td><div></div></td>
+ </tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="left: 250px;"></div>
+ <table>
+ <tbody>
+ <tr>
+ <td><div></div></td>
+ <td class="sticky"><div></div></td>
+ <td><div></div></td>
+ <td><div></div></td>
+ </tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-right-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-right-ref.html
new file mode 100644
index 0000000000..633c2fa50e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-right-ref.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<title>Reference for position:sticky right constraint should behave correctly for &lt;td&gt; elements</title>
+
+<style>
+.group {
+ position: relative;
+ width: 250px;
+ height: 150px;
+}
+
+.scroller {
+ position: relative;
+ width: 200px;
+ height: 100px;
+ overflow-x: auto;
+ overflow-y: hidden;
+}
+
+.contents {
+ height: 10px;
+ width: 500px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: green;
+ top: 0;
+ height: 50px;
+ width: 50px;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollLeft = 0;
+ document.getElementById('scroller2').scrollLeft = 75;
+ document.getElementById('scroller3').scrollLeft = 150;
+});
+</script>
+
+<div>You should see three green boxes below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="left: 150px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="left: 200px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="left: 250px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-right.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-right.html
new file mode 100644
index 0000000000..093af91a55
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-right.html
@@ -0,0 +1,118 @@
+<!DOCTYPE html>
+<title>position:sticky right constraint should behave correctly for &lt;td&gt; elements</title>
+<link rel="match" href="position-sticky-table-td-right-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that the position:sticky right constraint behaves correctly for &lt;td&gt; elements" />
+
+<script src="../resources/ref-rectangle.js"></script>
+
+<style>
+table {
+ border-collapse: collapse;
+ margin-left: 150px;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ position: relative;
+ width: 250px;
+ height: 150px;
+}
+
+.scroller {
+ position: relative;
+ width: 200px;
+ height: 100px;
+ overflow-x: auto;
+ overflow-y: hidden;
+}
+
+.postpadding {
+ height: 10px;
+ width: 500px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ top: 0;
+ height: 50px;
+ width: 50px;
+}
+
+.sticky {
+ position: sticky;
+ right: 25px;
+ background-color: green;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollLeft = 0;
+ document.getElementById('scroller2').scrollLeft = 75;
+ document.getElementById('scroller3').scrollLeft = 150;
+ createIndicatorForStickyElements(document.querySelectorAll('.sticky'));
+});
+</script>
+
+<div>You should see three green boxes below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="left: 150px;"></div>
+ <table>
+ <tbody>
+ <tr>
+ <td><div></div></td>
+ <td><div></div></td>
+ <td class="sticky"><div></div></td>
+ <td><div></div></td>
+ </tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="left: 200px;"></div>
+ <table>
+ <tbody>
+ <tr>
+ <td><div></div></td>
+ <td><div></div></td>
+ <td class="sticky"><div></div></td>
+ <td><div></div></td>
+ </tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="left: 250px;"></div>
+ <table>
+ <tbody>
+ <tr>
+ <td><div></div></td>
+ <td><div></div></td>
+ <td class="sticky"><div></div></td>
+ <td><div></div></td>
+ </tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-top-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-top-ref.html
new file mode 100644
index 0000000000..2ef7c2678b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-top-ref.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<title>Reference for position:sticky top constraint should behave correctly for &lt;td&gt; elements</title>
+
+<style>
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 150px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.contents {
+ height: 550px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: green;
+ left: 0;
+ height: 50px;
+ width: 50px;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 150;
+ document.getElementById('scroller2').scrollTop = 225;
+ document.getElementById('scroller3').scrollTop = 250;
+});
+</script>
+
+<div>You should see three green boxes below. No red should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="top: 200px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="top: 250px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="top: 250px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-top.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-top.html
new file mode 100644
index 0000000000..46931333c6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-td-top.html
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<title>position:sticky top constraint should behave correctly for &lt;td&gt; elements</title>
+<link rel="match" href="position-sticky-table-td-top-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that the position:sticky top constraint behaves correctly for &lt;td&gt; elements" />
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 150px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.prepadding {
+ height: 100px;
+}
+
+.postpadding {
+ height: 250px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 0;
+ height: 50px;
+ width: 50px;
+}
+
+.sticky {
+ position: sticky;
+ top: 25px;
+ background-color: green;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 150;
+ document.getElementById('scroller2').scrollTop = 225;
+ document.getElementById('scroller3').scrollTop = 250;
+});
+</script>
+
+<div>You should see three green boxes below. No red should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="top: 200px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td class="sticky"><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="top: 250px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td class="sticky"><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="top: 250px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td class="sticky"><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tfoot-bottom-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tfoot-bottom-ref.html
new file mode 100644
index 0000000000..a1ee8e79f1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tfoot-bottom-ref.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<title>Reference for position:sticky bottom constraint should behave correctly for &lt;tfoot&gt; elements</title>
+
+<style>
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 150px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.contents {
+ height: 550px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: green;
+ left: 0;
+ height: 50px;
+ width: 50px;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 0;
+ document.getElementById('scroller2').scrollTop = 75;
+ document.getElementById('scroller3').scrollTop = 200;
+});
+</script>
+
+<div>You should see three green boxes below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="top: 100px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="top: 150px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="top: 250px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tfoot-bottom.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tfoot-bottom.html
new file mode 100644
index 0000000000..4ddd0cb78e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tfoot-bottom.html
@@ -0,0 +1,124 @@
+<!DOCTYPE html>
+<title>position:sticky bottom constraint should behave correctly for &lt;tfoot&gt; elements</title>
+<link rel="match" href="position-sticky-table-tfoot-bottom-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that the position:sticky bottom constraint behaves correctly for &lt;tfoot&gt; elements" />
+
+<script src="../resources/ref-rectangle.js"></script>
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td, th {
+ padding: 0;
+}
+
+td > div, th > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 150px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.prepadding {
+ height: 100px;
+}
+
+.postpadding {
+ height: 250px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 0;
+ height: 50px;
+ width: 50px;
+}
+
+.sticky {
+ position: sticky;
+ bottom: 25px;
+ background-color: green;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 0;
+ document.getElementById('scroller2').scrollTop = 75;
+ document.getElementById('scroller3').scrollTop = 200;
+ createIndicatorForStickyElements(document.querySelectorAll('.sticky'));
+});
+</script>
+
+<div>You should see three green boxes below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="top: 100px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <tbody>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ <tfoot class="sticky">
+ <tr><th><div></div></th></tr>
+ </tfoot>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="top: 150px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <tbody>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ <tfoot class="sticky">
+ <tr><th><div></div></th></tr>
+ </tfoot>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="top: 250px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <tbody>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ <tfoot class="sticky">
+ <tr><th><div></div></th></tr>
+ </tfoot>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-bottom-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-bottom-ref.html
new file mode 100644
index 0000000000..341a75ca34
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-bottom-ref.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<title>Reference for position:sticky bottom constraint should behave correctly for &lt;th&gt; elements</title>
+
+<style>
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 150px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.contents {
+ height: 550px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: green;
+ left: 0;
+ height: 50px;
+ width: 50px;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 0;
+ document.getElementById('scroller2').scrollTop = 75;
+ document.getElementById('scroller3').scrollTop = 200;
+});
+</script>
+
+<div>You should see three green boxes below. No red should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="top: 100px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="top: 150px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="top: 250px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-bottom.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-bottom.html
new file mode 100644
index 0000000000..bd6a824317
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-bottom.html
@@ -0,0 +1,127 @@
+<!DOCTYPE html>
+<title>position:sticky bottom constraint should behave correctly for &lt;th&gt; elements</title>
+<link rel="match" href="position-sticky-table-th-bottom-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that the position:sticky bottom constraint behaves correctly for &lt;th&gt; elements" />
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td, th {
+ padding: 0;
+}
+
+td > div, th > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 150px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.prepadding {
+ height: 100px;
+}
+
+.postpadding {
+ height: 250px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 0;
+ height: 50px;
+ width: 50px;
+}
+
+.sticky {
+ position: sticky;
+ bottom: 25px;
+ background-color: green;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 0;
+ document.getElementById('scroller2').scrollTop = 75;
+ document.getElementById('scroller3').scrollTop = 200;
+});
+</script>
+
+<div>You should see three green boxes below. No red should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="top: 100px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <tbody>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ <tfoot>
+ <tr>
+ <th class="sticky"><div></div></th>
+ </tr>
+ </tfoot>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="top: 150px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <tbody>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ <tfoot>
+ <tr>
+ <th class="sticky"><div></div></th>
+ </tr>
+ </tfoot>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="top: 250px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <tbody>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ <tfoot>
+ <tr>
+ <th class="sticky"><div></div></th>
+ </tr>
+ </tfoot>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-left-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-left-ref.html
new file mode 100644
index 0000000000..7d0e5f9e58
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-left-ref.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<title>Reference for position:sticky left constraint should behave correctly for &lt;th&gt; elements</title>
+
+<style>
+.group {
+ position: relative;
+ width: 250px;
+ height: 150px;
+}
+
+.scroller {
+ position: relative;
+ width: 200px;
+ height: 100px;
+ overflow-x: auto;
+ overflow-y: hidden;
+}
+
+.contents {
+ height: 10px;
+ width: 500px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: green;
+ top: 0;
+ height: 50px;
+ width: 50px;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollLeft = 50;
+ document.getElementById('scroller2').scrollLeft = 125;
+ document.getElementById('scroller3').scrollLeft = 250;
+});
+</script>
+
+<div>You should see three green boxes below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="left: 100px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="left: 150px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="left: 250px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-left.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-left.html
new file mode 100644
index 0000000000..7361b25ce6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-left.html
@@ -0,0 +1,118 @@
+<!DOCTYPE html>
+<title>position:sticky left constraint should behave correctly for &lt;th&gt; elements</title>
+<link rel="match" href="position-sticky-table-th-left-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that the position:sticky left constraint behaves correctly for &lt;th&gt; elements" />
+
+<script src="../resources/ref-rectangle.js"></script>
+
+<style>
+table {
+ border-collapse: collapse;
+ margin-left: 100px;
+}
+
+td, th {
+ padding: 0;
+}
+
+td > div, th > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ position: relative;
+ width: 250px;
+ height: 150px;
+}
+
+.scroller {
+ position: relative;
+ width: 200px;
+ height: 100px;
+ overflow-x: auto;
+ overflow-y: hidden;
+}
+
+.postpadding {
+ height: 10px;
+ width: 500px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ top: 0;
+ height: 50px;
+ width: 50px;
+}
+
+.sticky {
+ position: sticky;
+ left: 25px;
+ background-color: green;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollLeft = 50;
+ document.getElementById('scroller2').scrollLeft = 125;
+ document.getElementById('scroller3').scrollLeft = 250;
+ createIndicatorForStickyElements(document.querySelectorAll('.sticky'));
+});
+</script>
+
+<div>You should see three green boxes below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="left: 100px;"></div>
+ <table>
+ <tbody>
+ <tr>
+ <th class="sticky"><div></div></th>
+ <td><div></div></td>
+ <td><div></div></td>
+ <td><div></div></td>
+ </tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="left: 150px;"></div>
+ <table>
+ <tbody>
+ <tr>
+ <th class="sticky"><div></div></th>
+ <td><div></div></td>
+ <td><div></div></td>
+ <td><div></div></td>
+ </tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="left: 250px;"></div>
+ <table>
+ <tbody>
+ <tr>
+ <th class="sticky"><div></div></th>
+ <td><div></div></td>
+ <td><div></div></td>
+ <td><div></div></td>
+ </tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-right-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-right-ref.html
new file mode 100644
index 0000000000..760376f10c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-right-ref.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<title>Reference for position:sticky right constraint should behave correctly for &lt;th&gt; elements</title>
+
+<style>
+.group {
+ position: relative;
+ width: 250px;
+ height: 150px;
+}
+
+.scroller {
+ position: relative;
+ width: 200px;
+ height: 100px;
+ overflow-x: auto;
+ overflow-y: hidden;
+}
+
+.contents {
+ height: 10px;
+ width: 500px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: green;
+ top: 0;
+ height: 50px;
+ width: 50px;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollLeft = 0;
+ document.getElementById('scroller2').scrollLeft = 75;
+ document.getElementById('scroller3').scrollLeft = 200;
+});
+</script>
+
+<div>You should see three green boxes below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="left: 150px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="left: 200px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="left: 300px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-right.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-right.html
new file mode 100644
index 0000000000..a1598f5506
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-right.html
@@ -0,0 +1,118 @@
+<!DOCTYPE html>
+<title>position:sticky right constraint should behave correctly for &lt;th&gt; elements</title>
+<link rel="match" href="position-sticky-table-th-right-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that the position:sticky right constraint behaves correctly for &lt;th&gt; elements" />
+
+<script src="../resources/ref-rectangle.js"></script>
+
+<style>
+table {
+ border-collapse: collapse;
+ margin-left: 150px;
+}
+
+td, th {
+ padding: 0;
+}
+
+td > div, th > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ position: relative;
+ width: 250px;
+ height: 150px;
+}
+
+.scroller {
+ position: relative;
+ width: 200px;
+ height: 100px;
+ overflow-x: auto;
+ overflow-y: hidden;
+}
+
+.postpadding {
+ height: 10px;
+ width: 500px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ top: 0;
+ height: 50px;
+ width: 50px;
+}
+
+.sticky {
+ position: sticky;
+ right: 25px;
+ background-color: green;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollLeft = 0;
+ document.getElementById('scroller2').scrollLeft = 75;
+ document.getElementById('scroller3').scrollLeft = 200;
+ createIndicatorForStickyElements(document.querySelectorAll('.sticky'));
+});
+</script>
+
+<div>You should see three green boxes below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="left: 150px;"></div>
+ <table>
+ <tbody>
+ <tr>
+ <td><div></div></td>
+ <td><div></div></td>
+ <td><div></div></td>
+ <th class="sticky"><div></div></th>
+ </tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="left: 200px;"></div>
+ <table>
+ <tbody>
+ <tr>
+ <td><div></div></td>
+ <td><div></div></td>
+ <td><div></div></td>
+ <th class="sticky"><div></div></th>
+ </tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="left: 300px;"></div>
+ <table>
+ <tbody>
+ <tr>
+ <td><div></div></td>
+ <td><div></div></td>
+ <td><div></div></td>
+ <th class="sticky"><div></div></th>
+ </tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-top-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-top-ref.html
new file mode 100644
index 0000000000..c9058c5522
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-top-ref.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<title>Reference for position:sticky top constraint should behave correctly for &lt;th&gt; elements</title>
+
+<style>
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 150px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.contents {
+ height: 550px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: green;
+ left: 0;
+ height: 50px;
+ width: 50px;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 50;
+ document.getElementById('scroller2').scrollTop = 125;
+ document.getElementById('scroller3').scrollTop = 250;
+});
+</script>
+
+<div>You should see three green boxes below. No red should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="top: 100px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="top: 150px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="top: 250px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-top.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-top.html
new file mode 100644
index 0000000000..57ff489e03
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-th-top.html
@@ -0,0 +1,127 @@
+<!DOCTYPE html>
+<title>position:sticky top constraint should behave correctly for &lt;th&gt; elements</title>
+<link rel="match" href="position-sticky-table-th-top-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that the position:sticky top constraint behaves correctly for &lt;th&gt; elements" />
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td, th {
+ padding: 0;
+}
+
+td > div, th > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 150px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.prepadding {
+ height: 100px;
+}
+
+.postpadding {
+ height: 250px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 0;
+ height: 50px;
+ width: 50px;
+}
+
+.sticky {
+ position: sticky;
+ top: 25px;
+ background-color: green;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 50;
+ document.getElementById('scroller2').scrollTop = 125;
+ document.getElementById('scroller3').scrollTop = 250;
+});
+</script>
+
+<div>You should see three green boxes below. No red should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="top: 100px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <thead>
+ <tr>
+ <th class="sticky"><div></div></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="top: 150px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <thead>
+ <tr>
+ <th class="sticky"><div></div></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="top: 250px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <thead>
+ <tr>
+ <th class="sticky"><div></div></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-thead-top-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-thead-top-ref.html
new file mode 100644
index 0000000000..d952c13b3b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-thead-top-ref.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<title>Reference for position:sticky top constraint should behave correctly for &lt;thead&gt; elements</title>
+
+<style>
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 150px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.contents {
+ height: 550px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: green;
+ left: 0;
+ height: 50px;
+ width: 50px;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 50;
+ document.getElementById('scroller2').scrollTop = 125;
+ document.getElementById('scroller3').scrollTop = 250;
+});
+</script>
+
+<div>You should see three green boxes below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="top: 100px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="top: 150px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="top: 250px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-thead-top.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-thead-top.html
new file mode 100644
index 0000000000..13c1b313c5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-thead-top.html
@@ -0,0 +1,124 @@
+<!DOCTYPE html>
+<title>position:sticky top constraint should behave correctly for &lt;thead&gt; elements</title>
+<link rel="match" href="position-sticky-table-thead-top-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that the position:sticky top constraint behaves correctly for &lt;thead&gt; elements" />
+
+<script src="../resources/ref-rectangle.js"></script>
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td, th {
+ padding: 0;
+}
+
+td > div, th > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 150px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.prepadding {
+ height: 100px;
+}
+
+.postpadding {
+ height: 250px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 0;
+ height: 50px;
+ width: 50px;
+}
+
+.sticky {
+ position: sticky;
+ top: 25px;
+ background-color: green;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 50;
+ document.getElementById('scroller2').scrollTop = 125;
+ document.getElementById('scroller3').scrollTop = 250;
+ createIndicatorForStickyElements(document.querySelectorAll('.sticky'));
+});
+</script>
+
+<div>You should see three green boxes below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="top: 100px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <thead class="sticky">
+ <tr><th><div></div></th></tr>
+ </thead>
+ <tbody>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="top: 150px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <thead class="sticky">
+ <tr><th><div></div></th></tr>
+ </thead>
+ <tbody>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="top: 250px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <thead class="sticky">
+ <tr><th><div></div></th></tr>
+ </thead>
+ <tbody>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tr-bottom-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tr-bottom-ref.html
new file mode 100644
index 0000000000..2f61ee6d3a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tr-bottom-ref.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<title>Reference for position:sticky bottom constraint should behave correctly for &lt;tr&gt; elements</title>
+
+<style>
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 150px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.contents {
+ height: 550px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: green;
+ left: 0;
+ height: 50px;
+ width: 50px;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 0;
+ document.getElementById('scroller2').scrollTop = 75;
+ document.getElementById('scroller3').scrollTop = 200;
+});
+</script>
+
+<div>You should see three green boxes below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="top: 100px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="top: 150px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="top: 250px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tr-bottom.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tr-bottom.html
new file mode 100644
index 0000000000..be9f1480a3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tr-bottom.html
@@ -0,0 +1,121 @@
+<!DOCTYPE html>
+<title>position:sticky bottom constraint should behave correctly for &lt;tr&gt; elements</title>
+<link rel="match" href="position-sticky-table-tr-bottom-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that the position:sticky bottom constraint behaves correctly for &lt;tr&gt; elements" />
+
+<script src="../resources/ref-rectangle.js"></script>
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 150px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.prepadding {
+ height: 100px;
+}
+
+.postpadding {
+ height: 250px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 0;
+ height: 50px;
+ width: 50px;
+}
+
+.sticky {
+ position: sticky;
+ bottom: 25px;
+ background-color: green;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 0;
+ document.getElementById('scroller2').scrollTop = 75;
+ document.getElementById('scroller3').scrollTop = 200;
+ createIndicatorForStickyElements(document.querySelectorAll('.sticky'));
+});
+</script>
+
+<div>You should see three green boxes below. No red or blue should be visible.</div>
+
+<!-- .sticky element pushed as far up as possible to table edge -->
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="top: 100px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <tbody>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr class="sticky"><td><div></div></td></tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<!-- .sticky element stuck to bottom of .scroller -->
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="top: 150px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <tbody>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr class="sticky"><td><div></div></td></tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<!-- .sticky element unstuck -->
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="top: 250px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <tbody>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr class="sticky"><td><div></div></td></tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tr-top-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tr-top-ref.html
new file mode 100644
index 0000000000..8b1989520b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tr-top-ref.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<title>Reference for position:sticky top constraint should behave correctly for &lt;tr&gt; elements</title>
+
+<style>
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 150px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.contents {
+ height: 550px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: green;
+ left: 0;
+ height: 50px;
+ width: 50px;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 50;
+ document.getElementById('scroller2').scrollTop = 125;
+ document.getElementById('scroller3').scrollTop = 250;
+});
+</script>
+
+<div>You should see three green boxes below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="top: 100px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="top: 150px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="top: 250px;"></div>
+ <div class="contents"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tr-top.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tr-top.html
new file mode 100644
index 0000000000..5e38ad38d9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-table-tr-top.html
@@ -0,0 +1,121 @@
+<!DOCTYPE html>
+<title>position:sticky top constraint should behave correctly for &lt;tr&gt; elements</title>
+<link rel="match" href="position-sticky-table-tr-top-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that the position:sticky top constraint behaves correctly for &lt;tr&gt; elements" />
+
+<script src="../resources/ref-rectangle.js"></script>
+
+<style>
+table {
+ border-collapse:collapse;
+}
+
+td {
+ padding: 0;
+}
+
+td > div {
+ height: 50px;
+ width: 50px;
+}
+
+.group {
+ display: inline-block;
+ position: relative;
+ width: 150px;
+ height: 200px;
+}
+
+.scroller {
+ position: relative;
+ width: 100px;
+ height: 150px;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.prepadding {
+ height: 100px;
+}
+
+.postpadding {
+ height: 250px;
+}
+
+.indicator {
+ position: absolute;
+ background-color: red;
+ left: 0;
+ height: 50px;
+ width: 50px;
+}
+
+.sticky {
+ position: sticky;
+ top: 25px;
+ background-color: green;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 50;
+ document.getElementById('scroller2').scrollTop = 125;
+ document.getElementById('scroller3').scrollTop = 250;
+ createIndicatorForStickyElements(document.querySelectorAll('.sticky'));
+});
+</script>
+
+<div>You should see three green boxes below. No red or blue should be visible.</div>
+
+<!-- .sticky element not yet stuck -->
+<div class="group">
+ <div id="scroller1" class="scroller">
+ <div class="indicator" style="top: 100px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <tbody>
+ <tr class="sticky"><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<!-- .sticky element stuck to top of .scroller -->
+<div class="group">
+ <div id="scroller2" class="scroller">
+ <div class="indicator" style="top: 150px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <tbody>
+ <tr class="sticky"><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
+
+<!-- .sticky element pushed as down as possible to table edge -->
+<div class="group">
+ <div id="scroller3" class="scroller">
+ <div class="indicator" style="top: 250px;"></div>
+ <div class="prepadding"></div>
+ <table>
+ <tbody>
+ <tr class="sticky"><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ <tr><td><div></div></td></tr>
+ </tbody>
+ </table>
+ <div class="postpadding"></div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-top-002.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-top-002.html
new file mode 100644
index 0000000000..e8025d679e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-top-002.html
@@ -0,0 +1,121 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Position Test: sticky element with top offset specified with px unit</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos">
+ <link rel="match" href="reference/position-sticky-top-002-ref.html">
+
+ <meta name="flags" content="">
+
+ <style>
+ div.scrolling-container
+ {
+ background-image: url("support/100x100-red.png");
+ background-repeat: no-repeat;
+ display: inline-block;
+ height: 250px;
+ margin-right: 30px;
+ overflow: auto;
+ position: static;
+ width: 150px;
+ }
+
+ div#first-scrolling-container
+ {
+ background-position: left bottom;
+ }
+
+ div#second-scrolling-container
+ {
+ background-position: left 100px;
+ }
+
+ div#third-scrolling-container
+ {
+ background-position: left 50px;
+ }
+
+ div.vertical-spacer
+ {
+ height: 100px;
+ }
+
+ div.sticky
+ {
+ background-color: green;
+ height: 100px;
+ position: sticky;
+ top: 100px;
+ width: 100px;
+ }
+ </style>
+
+ <body onload="document.getElementById(&quot;first-scrolling-container&quot;).scrollTop = 50; document.getElementById(&quot;second-scrolling-container&quot;).scrollTop = 200; document.getElementById(&quot;third-scrolling-container&quot;).scrollTop = 300;">
+
+ <p>Test passes if there are 3 filled green squares and <strong>no red</strong>.
+
+ <!--
+ first-scrolling-container: before reaching the sticking point
+ -->
+
+ <div id="first-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div class="content">
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div id="first-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
+
+ <!--
+ second-scrolling-container: when reaching the sticking point and beyond
+ -->
+
+ <div id="second-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div class="content">
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div id="second-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
+
+
+ <div id="third-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div class="content">
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div id="third-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-top-003.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-top-003.html
new file mode 100644
index 0000000000..574b1b359b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-top-003.html
@@ -0,0 +1,121 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Position Test: sticky element with top offset specified with percentage unit</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos">
+ <link rel="match" href="reference/position-sticky-top-002-ref.html">
+
+ <meta name="flags" content="">
+
+ <style>
+ div.scrolling-container
+ {
+ background-image: url("support/100x100-red.png");
+ background-repeat: no-repeat;
+ display: inline-block;
+ height: 250px;
+ margin-right: 30px;
+ overflow: auto;
+ position: static;
+ width: 150px;
+ }
+
+ div#first-scrolling-container
+ {
+ background-position: left bottom;
+ }
+
+ div#second-scrolling-container
+ {
+ background-position: left 100px;
+ }
+
+ div#third-scrolling-container
+ {
+ background-position: left 50px;
+ }
+
+ div.vertical-spacer
+ {
+ height: 100px;
+ }
+
+ div.sticky
+ {
+ background-color: green;
+ height: 100px;
+ position: sticky;
+ top: 40%;
+ width: 100px;
+ }
+ </style>
+
+ <body onload="document.getElementById(&quot;first-scrolling-container&quot;).scrollTop = 50; document.getElementById(&quot;second-scrolling-container&quot;).scrollTop = 200; document.getElementById(&quot;third-scrolling-container&quot;).scrollTop = 300;">
+
+ <p>Test passes if there are 3 filled green squares and <strong>no red</strong>.
+
+ <!--
+ first-scrolling-container: before reaching the sticking point
+ -->
+
+ <div id="first-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div class="content">
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div id="first-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
+
+ <!--
+ second-scrolling-container: when reaching the sticking point and beyond
+ -->
+
+ <div id="second-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div class="content">
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div id="second-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
+
+
+ <div id="third-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div class="content">
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ <div id="third-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
+
+ <div class="vertical-spacer"></div> <!-- 150w x 100h -->
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-top-and-bottom-003.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-top-and-bottom-003.html
new file mode 100644
index 0000000000..af68bcef72
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-top-and-bottom-003.html
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Position Test: sticky element with top and bottom offsets specified with percentage unit</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+ <link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos">
+ <link rel="match" href="reference/position-sticky-top-and-bottom-003-ref.html">
+
+ <meta name="flags" content="">
+
+ <style>
+ div.scrolling-container
+ {
+ background-image: url("support/100x100-red.png");
+ background-repeat: no-repeat;
+ display: inline-block;
+ height: 250px;
+ margin-right: 30px;
+ overflow: auto;
+ position: static;
+ width: 150px;
+ }
+
+ div#first-scrolling-container
+ {
+ background-position: left 125px;
+ }
+
+ div#second-scrolling-container
+ {
+ background-position: left 50px;
+ }
+
+ div#third-scrolling-container
+ {
+ background-position: left 25px;
+ }
+
+ div.vertical-spacer
+ {
+ height: 200px;
+ }
+
+ div.sticky
+ {
+ background-color: green;
+ bottom: 10%;
+ height: 100px;
+ position: sticky;
+ top: 10%;
+ width: 100px;
+ }
+ </style>
+
+ <body onload="document.getElementById(&quot;first-scrolling-container&quot;).scrollTop = 50; document.getElementById(&quot;second-scrolling-container&quot;).scrollTop = 150; document.getElementById(&quot;third-scrolling-container&quot;).scrollTop = 250;">
+
+ <p>Test passes if there are 3 filled green squares and <strong>no red</strong>.
+
+ <!--
+ first-scrolling-container: when reaching the first (top) sticking point
+ -->
+
+ <div id="first-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 200h -->
+
+ <div id="first-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 200h -->
+
+ </div>
+
+ <!--
+ second-scrolling-container: between both sticking points
+ -->
+
+ <div id="second-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 200h -->
+
+ <div id="second-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 200h -->
+
+ </div>
+
+ <!--
+ third-scrolling-container: when reaching the second (bottom) sticking point
+ -->
+
+
+ <div id="third-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 200h -->
+
+ <div id="third-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer"></div> <!-- 150w x 200h -->
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-top-and-bottom.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-top-and-bottom.html
new file mode 100644
index 0000000000..c790eaaf3e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-top-and-bottom.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<title>position:sticky elements can be constrained by top and bottom exceeding container size</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that position:sticky elements obey both top and bottom constraints" />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+
+.scroller {
+ height: 200px;
+ overflow: auto;
+ position: relative;
+}
+.container {
+ height: 120px;
+}
+.padding, .sticky {
+ height: 50px;
+}
+.overflow-padding {
+ height: 200px;
+}
+.sticky {
+ position: sticky;
+ background: green;
+ top: -25px;
+ bottom: 150px;
+}
+</style>
+
+<body>
+ <div class="scroller">
+ <div class="container">
+ <div class="padding"></div>
+ <div class="sticky"></div>
+ </div>
+ <div class="overflow-padding"></div>
+ </div>
+</body>
+
+<script>
+test(() => {
+ const scroller = document.querySelector('.scroller');
+ const element = document.querySelector('.sticky');
+ scroller.scrollTop = 0;
+ assert_equals(element.offsetTop, 0);
+}, 'initially the sticky box should be pushed to the top of the container');
+
+test(() => {
+ const scroller = document.querySelector('.scroller');
+ const element = document.querySelector('.sticky');
+ scroller.scrollTop = 95;
+ assert_equals(element.offsetTop, 70);
+}, 'when we scroll past the flow position the top constraint pushes it down');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-top.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-top.html
new file mode 100644
index 0000000000..9929fc734b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-top.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<title>position:sticky elements should respect the top constraint</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that position:sticky elements obey their top anchor after scrolling" />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script src="../resources/sticky-util.js"></script>
+
+<body></body>
+
+<script>
+test(() => {
+ const elements = setupStickyTest('top', 50);
+ elements.scroller.scrollTop = 100;
+ const nonStickyTopY = elements.container.offsetTop +
+ elements.filler.clientHeight;
+ assert_equals(elements.sticky.offsetTop, nonStickyTopY);
+}, 'before reaching the sticking point the sticky box should not be offset');
+
+test(() => {
+ const elements = setupStickyTest('top', 50);
+ elements.scroller.scrollTop = 200;
+
+ // This math cancels to sticky.offsetTop == (scroller.scrollTop + 50), but
+ // for clarity the calculations are left explicit.
+ const nonStickyTopY = elements.container.offsetTop +
+ elements.filler.clientHeight;
+ const targetTopY = elements.scroller.scrollTop + 50;
+ const stickyOffset = targetTopY - nonStickyTopY;
+
+ assert_equals(elements.sticky.offsetTop, nonStickyTopY + stickyOffset);
+}, 'after reaching the sticking point the sticky box should be offset');
+
+test(() => {
+ const elements = setupStickyTest('top', 50);
+ elements.scroller.scrollTop = 300;
+ const maxOffsetInContainer = elements.container.offsetTop +
+ elements.container.clientHeight - elements.sticky.clientHeight;
+ assert_equals(elements.sticky.offsetTop, maxOffsetInContainer);
+}, 'the sticky box should not be pushed outside its containing block');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-transforms-translate.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-transforms-translate.html
new file mode 100644
index 0000000000..fb2ca6b85f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-transforms-translate.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<title>translations on position:sticky elements should apply after sticking</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that translations on position:sticky elements are carried out on their stuck position" />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script src="../resources/sticky-util.js"></script>
+
+<body style="margin: 0;"></body>
+
+<script>
+test(() => {
+ const elements = setupStickyTest('top', 50);
+ elements.sticky.style.transform = 'translateY(-100%)';
+ elements.scroller.scrollTop = 100;
+ // Transforms don't affect offsetTop, so use getBoundingClientRect.
+ assert_equals(elements.sticky.getBoundingClientRect().y,
+ elements.scroller.getBoundingClientRect().y);
+}, 'Translation transform can move sticky element past sticking point');
+
+test(() => {
+ const elements = setupStickyTest('top', 50);
+ elements.sticky.style.transform = 'translateY(50%)';
+ elements.scroller.scrollTop = 200;
+ // Transforms don't affect offsetTop, so use getBoundingClientRect.
+ const stickyElementOffset = elements.sticky.getBoundingClientRect().y -
+ elements.scroller.getBoundingClientRect().y;
+ assert_equals(stickyElementOffset, 100);
+}, 'Stuck elements can still be moved via translations');
+
+test(() => {
+ const elements = setupStickyTest('top', 50);
+ elements.container.style.transform = 'translateY(100px)';
+ elements.scroller.scrollTop = 200;
+ // Transforms don't affect offsetTop, so use getBoundingClientRect.
+ // Here the sticky element will originally have stuck at 50px from the top,
+ // but is then 'pulled' downwards by the 100px container transform.
+ const stickyElementOffset = elements.sticky.getBoundingClientRect().y -
+ elements.scroller.getBoundingClientRect().y;
+ assert_equals(stickyElementOffset, 150);
+}, 'The sticky element should stick before the container is offset by a ' +
+ 'translation');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-transforms.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-transforms.html
new file mode 100644
index 0000000000..080f05a4eb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-transforms.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<title>transforms on position:sticky elements should apply after sticking</title>
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that transforms on position:sticky elements are carried out on their stuck position" />
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script src="../resources/sticky-util.js"></script>
+
+<body style="margin: 0;"></body>
+
+<script>
+test(() => {
+ const elements = setupStickyTest('top', 50);
+ elements.sticky.style.transform = 'scale(2)';
+ elements.scroller.scrollTop = 200;
+
+ // Transforms don't affect offsetTop, so use getBoundingClientRect.
+ // Scaling the sticky element by 2 means its top-y moves (1/2 * height)
+ // upwards, in this case placing it at the top of the viewport.
+ const boundingRect = elements.sticky.getBoundingClientRect();
+ assert_equals(boundingRect.y, elements.scroller.getBoundingClientRect().y);
+}, 'Scale transforms are carried out on the stuck element position');
+
+test(() => {
+ const elements = setupStickyTest('top', 50);
+ elements.sticky.style.transform = 'rotateX(60deg)';
+ elements.scroller.scrollTop = 200;
+
+ // Transforms don't affect offsetTop, so use getBoundingClientRect.
+ // Rotating around the x-axis essentially 'squashes' it (from the camera's
+ // viewpoint), in this case shifting the offset to 75 rather than 50.
+ const stickyElementOffset = elements.sticky.getBoundingClientRect().y -
+ elements.scroller.getBoundingClientRect().y;
+ assert_equals(stickyElementOffset, 75);
+}, 'Rotate transforms are carried out on the stuck element position');
+
+test(() => {
+ const elements = setupStickyTest('top', 50);
+ elements.sticky.style.transform = 'perspective(3px) translateZ(1px)';
+ elements.scroller.scrollTop = 200;
+
+ // Transforms don't affect offsetTop, so use getBoundingClientRect.
+ const stickyElementOffset = elements.sticky.getBoundingClientRect().y -
+ elements.scroller.getBoundingClientRect().y;
+ assert_equals(stickyElementOffset, 25);
+}, 'Perspective transforms are carried out on the stuck element position');
+</script>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-writing-modes-ref.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-writing-modes-ref.html
new file mode 100644
index 0000000000..d55c22d953
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-writing-modes-ref.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<title>Reference for position:sticky constraints are independent of writing mode</title>
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+.group {
+ display: inline-block;
+ position: relative;
+ width: 180px;
+ height: 250px;
+}
+
+.scroller {
+ position: relative;
+ width: 130px;
+ height: 200px;
+ overflow: hidden;
+ font: 30px/1 Ahem;
+}
+
+.contents {
+ height: 500px;
+ width: 200px;
+}
+
+.indicator {
+ display: inline;
+ color: green;
+ position: relative;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 50;
+ document.getElementById('scroller1').scrollLeft = 20;
+ document.getElementById('scroller2').scrollTop = 50;
+ document.getElementById('scroller2').scrollLeft = -25;
+});
+</script>
+
+<div>You should see two green blocks below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller" style="writing-mode: vertical-lr;">
+ <div class="contents">
+ <div class="indicator" style="left: 40px; top: 100px;">XXX</div>
+ </div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller" style="writing-mode: vertical-rl;">
+ <div class="contents">
+ <div class="indicator" style="right: 45px; top: 100px;">XXX</div>
+ </div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/position-sticky-writing-modes.html b/testing/web-platform/tests/css/css-position/sticky/position-sticky-writing-modes.html
new file mode 100644
index 0000000000..98f50500b8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/position-sticky-writing-modes.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<title>position:sticky constraints are independent of writing mode</title>
+<link rel="match" href="position-sticky-writing-modes-ref.html" />
+<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
+<meta name="assert" content="This test checks that position:sticky constraints are independent of the writing mode" />
+
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+
+<script src="../resources/ref-rectangle.js"></script>
+
+<style>
+.group {
+ display: inline-block;
+ position: relative;
+ width: 180px;
+ height: 250px;
+}
+
+.scroller {
+ position: relative;
+ width: 130px;
+ height: 200px;
+ overflow: hidden;
+ font: 30px/1 Ahem;
+}
+
+.contents {
+ height: 500px;
+ width: 200px;
+}
+
+.indicator {
+ position: absolute;
+ color: red;
+}
+
+.sticky {
+ display: inline;
+ color: green;
+ position: sticky;
+ top: 50px;
+}
+</style>
+
+<script>
+window.addEventListener('load', function() {
+ document.getElementById('scroller1').scrollTop = 50;
+ document.getElementById('scroller1').scrollLeft = 20;
+ document.getElementById('scroller2').scrollTop = 50;
+ document.getElementById('scroller2').scrollLeft = -25;
+ createIndicatorForStickyElements(document.querySelectorAll('.sticky'));
+});
+</script>
+
+<div>You should see two green blocks below. No red or blue should be visible.</div>
+
+<div class="group">
+ <div id="scroller1" class="scroller" style="writing-mode: vertical-lr;">
+ <div class="indicator" style="left: 40px; top: 100px;">XXX</div>
+ <div class="contents">
+ <div class="sticky" style="left: 20px;">XXX</div>
+ </div>
+ </div>
+</div>
+
+<div class="group">
+ <div id="scroller2" class="scroller" style="writing-mode: vertical-rl;">
+ <div class="indicator" style="left: 55px; top: 100px;">XXX</div>
+ <div class="contents">
+ <div class="sticky" style="right: 20px;">XXX</div>
+ </div>
+ </div>
+</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-bottom-002-ref.html b/testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-bottom-002-ref.html
new file mode 100644
index 0000000000..253ca7eebe
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-bottom-002-ref.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reftest Reference</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ div.scrolling-container
+ {
+ display: inline-block;
+ height: 250px;
+ margin-right: 30px;
+ overflow: auto;
+ position: static;
+ width: 150px;
+ }
+
+ div.vertical-spacer-200
+ {
+ height: 200px;
+ }
+
+ div.sticky
+ {
+ background-color: green;
+ height: 100px;
+ position: relative;
+ width: 100px;
+ }
+
+ div#first-sticky
+ {
+ bottom: 100px;
+ }
+
+ div#second-sticky
+ {
+ bottom: 50px;
+ }
+ </style>
+
+ <body onload="document.getElementById(&quot;first-scrolling-container&quot;).scrollTop = 25; document.getElementById(&quot;second-scrolling-container&quot;).scrollTop = 100; document.getElementById(&quot;third-scrolling-container&quot;).scrollTop = 200;">
+
+ <p>Test passes if there are 3 filled green squares and <strong>no red</strong>.
+
+ <div id="first-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer-200"></div> <!-- 100w x 200h -->
+
+ <div id="first-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer-200"></div> <!-- 100w x 200h -->
+
+ </div>
+
+
+ <div id="second-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer-200"></div> <!-- 100w x 200h -->
+
+ <div id="second-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer-200"></div> <!-- 100w x 200h -->
+
+ </div>
+
+
+ <div id="third-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer-200"></div> <!-- 100w x 200h -->
+
+ <div id="third-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer-200"></div> <!-- 100w x 200h -->
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-fixed-ancestor-002-ref.html b/testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-fixed-ancestor-002-ref.html
new file mode 100644
index 0000000000..abdc1dbcfa
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-fixed-ancestor-002-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reference File</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ html, body, div
+ {
+ background-color: green;
+ color: white;
+ font-size: 40vh;
+ height: 100%;
+ margin: 0;
+ }
+ </style>
+
+ <div>PASS</div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-left-002-ref.html b/testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-left-002-ref.html
new file mode 100644
index 0000000000..75aa9a4c1f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-left-002-ref.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reftest Reference</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ div.scrolling-container
+ {
+ height: 150px;
+ margin-bottom: 30px;
+ overflow-y: hidden;
+ position: static;
+ white-space: nowrap;
+ width: 250px;
+ }
+
+ div.horizontal-spacer-200
+ {
+ display: inline-block;
+ height: 100%;
+ width: 200px;
+ }
+
+ div.sticky
+ {
+ background-color: green;
+ display: inline-block;
+ height: 100px;
+ position: relative;
+ vertical-align: top;
+ width: 100px;
+ }
+
+ div#first-sticky
+ {
+ left: 0px;
+ }
+
+ div#second-sticky
+ {
+ left: 50px;
+ }
+
+ div#third-sticky
+ {
+ left: 100px;
+ }
+ </style>
+
+ <body onload="document.getElementById(&quot;first-scrolling-container&quot;).scrollLeft = 50; document.getElementById(&quot;second-scrolling-container&quot;).scrollLeft = 150; document.getElementById(&quot;third-scrolling-container&quot;).scrollLeft = 300;">
+
+ <p>Test passes if there are 3 filled green squares and <strong>no red</strong>.
+
+ <div id="first-scrolling-container" class="scrolling-container">
+
+ <div class="horizontal-spacer-200"></div><div id="first-sticky" class="sticky"></div><div class="horizontal-spacer-200"></div>
+
+ </div>
+
+
+ <div id="second-scrolling-container" class="scrolling-container">
+
+ <div class="horizontal-spacer-200"></div><div id="second-sticky" class="sticky"></div><div class="horizontal-spacer-200"></div>
+
+ </div>
+
+ <div id="third-scrolling-container" class="scrolling-container">
+
+ <div class="horizontal-spacer-200"></div><div id="third-sticky" class="sticky"></div><div class="horizontal-spacer-200"></div>
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-right-002-ref.html b/testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-right-002-ref.html
new file mode 100644
index 0000000000..3230e476b5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-right-002-ref.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reftest Reference</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ div.scrolling-container
+ {
+ height: 150px;
+ margin-bottom: 30px;
+ overflow-y: hidden;
+ position: static;
+ white-space: nowrap;
+ width: 250px;
+ }
+
+ div.horizontal-spacer-200
+ {
+ display: inline-block;
+ height: 100%;
+ width: 200px;
+ }
+
+ div.sticky
+ {
+ background-color: green;
+ display: inline-block;
+ height: 100px;
+ position: relative;
+ vertical-align: top;
+ width: 100px;
+ }
+
+ div#first-sticky
+ {
+ right: 100px;
+ }
+
+ div#second-sticky
+ {
+ right: 50px;
+ }
+ </style>
+
+ <body onload="document.getElementById(&quot;first-scrolling-container&quot;).scrollLeft = 25; document.getElementById(&quot;second-scrolling-container&quot;).scrollLeft = 100; document.getElementById(&quot;third-scrolling-container&quot;).scrollLeft = 200;">
+
+ <p>Test passes if there are 3 filled green squares and <strong>no red</strong>.
+
+ <div id="first-scrolling-container" class="scrolling-container">
+
+ <div class="horizontal-spacer-200"></div><div id="first-sticky" class="sticky"></div><div class="horizontal-spacer-200"></div>
+
+ </div>
+
+ <div id="second-scrolling-container" class="scrolling-container">
+
+ <div class="horizontal-spacer-200"></div><div id="second-sticky" class="sticky"></div><div class="horizontal-spacer-200"></div>
+
+ </div>
+
+ <div id="third-scrolling-container" class="scrolling-container">
+
+ <div class="horizontal-spacer-200"></div><div id="third-sticky" class="sticky"></div><div class="horizontal-spacer-200"></div>
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-top-002-ref.html b/testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-top-002-ref.html
new file mode 100644
index 0000000000..4a95591a56
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-top-002-ref.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reftest Reference</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ div.scrolling-container
+ {
+ display: inline-block;
+ height: 250px;
+ margin-right: 30px;
+ overflow: auto;
+ position: static;
+ width: 150px;
+ }
+
+ div.vertical-spacer-200
+ {
+ height: 200px;
+ }
+
+ div.sticky
+ {
+ background-color: green;
+ height: 100px;
+ position: relative;
+ width: 100px;
+ }
+
+ div#first-sticky
+ {
+ top: 0px;
+ }
+
+ div#second-sticky
+ {
+ top: 100px;
+ }
+
+ div#third-sticky
+ {
+ top: 100px;
+ }
+ </style>
+
+ <body onload="document.getElementById(&quot;first-scrolling-container&quot;).scrollTop = 50; document.getElementById(&quot;second-scrolling-container&quot;).scrollTop = 200; document.getElementById(&quot;third-scrolling-container&quot;).scrollTop = 300;">
+
+ <p>Test passes if there are 3 filled green squares and <strong>no red</strong>.
+
+ <div id="first-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer-200"></div> <!-- 100w x 200h -->
+
+ <div id="first-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer-200"></div> <!-- 100w x 200h -->
+
+ </div>
+
+
+ <div id="second-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer-200"></div> <!-- 100w x 200h -->
+
+ <div id="second-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer-200"></div> <!-- 100w x 200h -->
+
+ </div>
+
+
+ <div id="third-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer-200"></div> <!-- 100w x 200h -->
+
+ <div id="third-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer-200"></div> <!-- 100w x 200h -->
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-top-and-bottom-003-ref.html b/testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-top-and-bottom-003-ref.html
new file mode 100644
index 0000000000..36af9a33bc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/reference/position-sticky-top-and-bottom-003-ref.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+
+ <meta charset="UTF-8">
+
+ <title>CSS Reftest Reference</title>
+
+ <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+ <style>
+ div.scrolling-container
+ {
+ display: inline-block;
+ height: 250px;
+ margin-right: 30px;
+ overflow: auto;
+ position: static;
+ width: 150px;
+ }
+
+ div.vertical-spacer
+ {
+ height: 200px;
+ }
+
+ div.sticky
+ {
+ background-color: green;
+ height: 100px;
+ position: relative;
+ width: 100px;
+ }
+
+ div#first-sticky
+ {
+ bottom: 25px;
+ }
+
+ div#second-sticky
+ {
+ top: 0px;
+ }
+
+ div#third-sticky
+ {
+ top: 75px;
+ }
+ </style>
+
+ <body onload="document.getElementById(&quot;first-scrolling-container&quot;).scrollTop = 50; document.getElementById(&quot;second-scrolling-container&quot;).scrollTop = 150; document.getElementById(&quot;third-scrolling-container&quot;).scrollTop = 250;">
+
+ <p>Test passes if there are 3 filled green squares and <strong>no red</strong>.
+
+ <div id="first-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer"></div> <!-- 100w x 200h -->
+
+ <div id="first-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer"></div> <!-- 100w x 200h -->
+
+ </div>
+
+
+ <div id="second-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer"></div> <!-- 100w x 200h -->
+
+ <div id="second-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer"></div> <!-- 100w x 200h -->
+
+ </div>
+
+
+ <div id="third-scrolling-container" class="scrolling-container"> <!-- 150w x 250h viewport -->
+
+ <div class="vertical-spacer"></div> <!-- 100w x 200h -->
+
+ <div id="third-sticky" class="sticky"></div> <!-- 100w x 100h -->
+
+ <div class="vertical-spacer"></div> <!-- 100w x 200h -->
+
+ </div>
diff --git a/testing/web-platform/tests/css/css-position/sticky/sticky-after-input.html b/testing/web-platform/tests/css/css-position/sticky/sticky-after-input.html
new file mode 100644
index 0000000000..9104aa3c5e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/sticky-after-input.html
@@ -0,0 +1,49 @@
+<!doctype html>
+<title>Sticky positioned element should reset the scroll position to unshifted position</title>
+<link rel="author" title="Seokho Song" href="mailto:0xdevssh@gmail.com">
+<link rel="help" href="https://crbug.com/664246">
+<link rel="help" href="https://crbug.com/1178622">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<div id="scrollEl" style="height:100px; overflow-y: auto; scroll-padding:20px 20px 20px 20px;">
+ <input id="stickyEl" type="text" style="position:sticky;top:0" />
+ <div>1</div>
+ <div>2</div>
+ <div>3</div>
+ <div>4</div>
+ <div>5</div>
+ <div>6</div>
+ <div>7</div>
+ <div>8</div>
+ <div>9</div>
+ <div>10</div>
+ <div>11</div>
+ <div>12</div>
+ <div>13</div>
+ <div>14</div>
+ <div>15</div>
+ <div>16</div>
+ <div>17</div>
+</div>
+</div>
+<script>
+
+async_test(t => {
+ var scrollEl = document.getElementById("scrollEl");
+ var stickyEl = document.getElementById("stickyEl");
+ stickyEl.focus()
+ scrollEl.scrollTo(0, scrollEl.scrollHeight);
+ scrollEl.addEventListener('input', ()=> {
+ requestAnimationFrame(t.step_func(()=>{
+ assert_equals(scrollEl.scrollTop, 0,
+ "should reset the scroll to unshifted sticky position");
+ t.done()
+ }))
+ })
+ test_driver.send_keys(stickyEl, "A")
+})
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-position/sticky/support/100x100-red.png b/testing/web-platform/tests/css/css-position/sticky/support/100x100-red.png
new file mode 100644
index 0000000000..57bf3ddc52
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/sticky/support/100x100-red.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-position/z-index-blend-will-change-overlapping-layers-ref.html b/testing/web-platform/tests/css/css-position/z-index-blend-will-change-overlapping-layers-ref.html
new file mode 100644
index 0000000000..883ffed46d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/z-index-blend-will-change-overlapping-layers-ref.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<div style="height: 100vh"></div>
+<div style="background: green; height: 100px"></div>
+<script>
+window.scrollTo(0, 100);
+</script>
diff --git a/testing/web-platform/tests/css/css-position/z-index-blend-will-change-overlapping-layers.html b/testing/web-platform/tests/css/css-position/z-index-blend-will-change-overlapping-layers.html
new file mode 100644
index 0000000000..7c43c33368
--- /dev/null
+++ b/testing/web-platform/tests/css/css-position/z-index-blend-will-change-overlapping-layers.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>z-index, will-change, mix-blend-mode on overlapping layers</title>
+<link rel="match" href="z-index-blend-will-change-overlapping-layers-ref.html">
+<link rel="help" href="https://www.w3.org/TR/CSS2/visuren.html#propdef-z-index">
+<link rel="help" href="https://drafts.csswg.org/css-will-change/#will-change">
+<link rel="help" href="https://www.w3.org/TR/compositing-1/#mix-blend-mode">
+<meta name="assert" content="Tests z-index, will-change and mix-blend-mode on overlapping layers.
+Passes if there is a green bar when the page is scrolled to the bottom.">
+<script src="/common/reftest-wait.js"></script>
+<div style="z-index: 1; position: relative; height: 100vh">
+ <div style="mix-blend-mode: multiply"></div>
+ <div style="will-change: transform; position: absolute; bottom: -100px; width: 100px; height: 100px; background: red">
+ </div>
+</div>
+<div style="z-index: 1; position: relative; background: green; height: 100px"></div>
+<script>
+requestAnimationFrame(()=>{
+ requestAnimationFrame(()=>{
+ window.scrollBy(0, 100);
+ takeScreenshot();
+ });
+});
+</script>
+</html>