Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support small/large/dynamic/logical viewport units
This CL adds support for new units: * svw, svh (etc): Resolves against the viewport as it would be with browser controls fully expanded. * lvw, lvh (etc): Resolves against the viewport as it would be with browser controls fully minimized. * dvw, dvh (etc): Resolves against the viewport as it presently appears given the current state of browser controls. * vi, vb: Resolves against vw/vh depending on the writing-mode of the target element. Note that dv* units are deliberately not responsive to browser control animations, and will always resolve to either sv* or lv* (not some value in between). This is to avoid excessive scroll-driven relayouts on mobile devices. This CL uses the existing system/bits for invalidation of viewport units. Targeted invalidation of dynamic units will come in a subsequent CL. Bug: 1093055 Change-Id: I3ba55a86de53514f2020a2d5bdda579f06dd9d0a Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3344791 Reviewed-by: Xiaocheng Hu <xiaochengh@chromium.org> Reviewed-by: David Bokan <bokan@chromium.org> Commit-Queue: Anders Hartvoll Ruud <andruud@chromium.org> Cr-Commit-Position: refs/heads/main@{#967475}
- Loading branch information
1 parent
c1a9ac2
commit a78117e
Showing
5 changed files
with
341 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
<!DOCTYPE html> | ||
<title>Resolving viewport units</title> | ||
<link rel="help" href="https://drafts.csswg.org/css-values-4/#viewport-relative-lengths"> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
|
||
<style> | ||
iframe { | ||
width: 200px; | ||
height: 100px; | ||
} | ||
</style> | ||
|
||
<iframe id=iframe></iframe> | ||
|
||
<script> | ||
|
||
const doc = iframe.contentDocument; | ||
const win = iframe.contentWindow; | ||
|
||
function test_computed_value(value, expected) { | ||
test((t) => { | ||
t.add_cleanup(() => { doc.body.innerHTML = ''; }); | ||
doc.body.innerHTML = ` | ||
<style> | ||
* { margin: 0; } | ||
div { height: ${value}; } | ||
</style> | ||
<div></div> | ||
`; | ||
let div = doc.querySelector('div'); | ||
assert_equals(win.getComputedStyle(div).height, expected); | ||
}, `${value} computes to ${expected}`); | ||
} | ||
|
||
test_computed_value('100vw', '200px'); | ||
test_computed_value('100vi', '200px'); | ||
test_computed_value('100vmax', '200px'); | ||
test_computed_value('100svw', '200px'); | ||
test_computed_value('100svi', '200px'); | ||
test_computed_value('100svmax', '200px'); | ||
test_computed_value('100lvw', '200px'); | ||
test_computed_value('100lvi', '200px'); | ||
test_computed_value('100lvmax', '200px'); | ||
test_computed_value('100dvw', '200px'); | ||
test_computed_value('100dvi', '200px'); | ||
test_computed_value('100dvmax', '200px'); | ||
|
||
test_computed_value('100vh', '100px'); | ||
test_computed_value('100vb', '100px'); | ||
test_computed_value('100vmin', '100px'); | ||
test_computed_value('100svh', '100px'); | ||
test_computed_value('100svb', '100px'); | ||
test_computed_value('100svmin', '100px'); | ||
test_computed_value('100lvh', '100px'); | ||
test_computed_value('100lvb', '100px'); | ||
test_computed_value('100lvmin', '100px'); | ||
test_computed_value('100dvh', '100px'); | ||
test_computed_value('100dvb', '100px'); | ||
test_computed_value('100dvmin', '100px'); | ||
|
||
test_computed_value('1dvw', '2px'); | ||
test_computed_value('10dvw', '20px'); | ||
test_computed_value('1dvh', '1px'); | ||
test_computed_value('10dvh', '10px'); | ||
|
||
test_computed_value('calc(1dvw + 1dvw)', '4px'); | ||
test_computed_value('calc(1dvw + 1dvh)', '3px'); | ||
test_computed_value('calc(1dvw + 100px)', '102px'); | ||
test_computed_value('max(1svw, 1svh)', '2px'); | ||
test_computed_value('min(1lvw, 1lvh)', '1px'); | ||
test_computed_value('calc(1dvw + 10%)', '12px'); | ||
|
||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
<!DOCTYPE html> | ||
<title>Invalidation of viewport units</title> | ||
<link rel="help" href="https://drafts.csswg.org/css-values-4/#viewport-relative-lengths"> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
|
||
<style> | ||
iframe { | ||
width: 200px; | ||
height: 100px; | ||
} | ||
|
||
iframe.resize { | ||
width: 400px; | ||
height: 300px; | ||
} | ||
</style> | ||
|
||
<iframe id=iframe></iframe> | ||
|
||
<script> | ||
|
||
const doc = iframe.contentDocument; | ||
const win = iframe.contentWindow; | ||
|
||
function test_invalidation_value(value, expected_pre, expected_post) { | ||
test((t) => { | ||
t.add_cleanup(() => { doc.body.innerHTML = ''; }); | ||
doc.body.innerHTML = `<div style="height: ${value};"></div>`; | ||
let div = doc.querySelector('div'); | ||
assert_equals(win.getComputedStyle(div).height, expected_pre); | ||
|
||
t.add_cleanup(() => { iframe.classList.remove('resize'); }) | ||
iframe.classList.add('resize'); | ||
assert_equals(win.getComputedStyle(div).height, expected_post); | ||
}, `${value} computes to ${expected_post} after frame resize`); | ||
} | ||
|
||
test_invalidation_value('100vw', '200px', '400px'); | ||
test_invalidation_value('100vi', '200px', '400px'); | ||
test_invalidation_value('100vmax', '200px', '400px'); | ||
test_invalidation_value('100svw', '200px', '400px'); | ||
test_invalidation_value('100svi', '200px', '400px'); | ||
test_invalidation_value('100svmax', '200px', '400px'); | ||
test_invalidation_value('100lvw', '200px', '400px'); | ||
test_invalidation_value('100lvi', '200px', '400px'); | ||
test_invalidation_value('100lvmax', '200px', '400px'); | ||
test_invalidation_value('100dvw', '200px', '400px'); | ||
test_invalidation_value('100dvi', '200px', '400px'); | ||
test_invalidation_value('100dvmax', '200px', '400px'); | ||
|
||
test_invalidation_value('100vh', '100px', '300px'); | ||
test_invalidation_value('100vb', '100px', '300px'); | ||
test_invalidation_value('100vmin', '100px', '300px'); | ||
test_invalidation_value('100svh', '100px', '300px'); | ||
test_invalidation_value('100svb', '100px', '300px'); | ||
test_invalidation_value('100svmin', '100px', '300px'); | ||
test_invalidation_value('100lvh', '100px', '300px'); | ||
test_invalidation_value('100lvb', '100px', '300px'); | ||
test_invalidation_value('100lvmin', '100px', '300px'); | ||
test_invalidation_value('100dvh', '100px', '300px'); | ||
test_invalidation_value('100dvb', '100px', '300px'); | ||
test_invalidation_value('100dvmin', '100px', '300px'); | ||
|
||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
<!DOCTYPE html> | ||
<title>Viewport units in @keyframes</title> | ||
<link rel="help" href="https://drafts.csswg.org/css-values-4/#viewport-relative-lengths"> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
|
||
<style> | ||
iframe { | ||
width: 200px; | ||
height: 100px; | ||
} | ||
</style> | ||
|
||
<iframe id=iframe></iframe> | ||
|
||
<script> | ||
|
||
const doc = iframe.contentDocument; | ||
const win = iframe.contentWindow; | ||
|
||
function test_interpolated_value(from, to, expected) { | ||
test((t) => { | ||
t.add_cleanup(() => { doc.body.innerHTML = ''; }); | ||
doc.body.innerHTML = ` | ||
<style> | ||
@keyframes anim { | ||
from { height: ${from}; } | ||
to { height: ${to}} | ||
} | ||
div { animation: anim linear 10s -5s paused; } | ||
</style> | ||
<div></div> | ||
`; | ||
let div = doc.querySelector('div'); | ||
assert_equals(win.getComputedStyle(div).height, expected); | ||
}, `Interpolation from ${from} to ${to} is ${expected} at 50%`); | ||
} | ||
|
||
test_interpolated_value('0px', '100vw', '100px'); | ||
test_interpolated_value('0px', '100vi', '100px'); | ||
test_interpolated_value('0px', '100vmax', '100px'); | ||
test_interpolated_value('0px', '100svw', '100px'); | ||
test_interpolated_value('0px', '100svi', '100px'); | ||
test_interpolated_value('0px', '100svmax', '100px'); | ||
test_interpolated_value('0px', '100lvw', '100px'); | ||
test_interpolated_value('0px', '100lvi', '100px'); | ||
test_interpolated_value('0px', '100lvmax', '100px'); | ||
test_interpolated_value('0px', '100dvw', '100px'); | ||
test_interpolated_value('0px', '100dvi', '100px'); | ||
test_interpolated_value('0px', '100dvmax', '100px'); | ||
|
||
test_interpolated_value('0px', '100vh', '50px'); | ||
test_interpolated_value('0px', '100vb', '50px'); | ||
test_interpolated_value('0px', '100vmin', '50px'); | ||
test_interpolated_value('0px', '100svh', '50px'); | ||
test_interpolated_value('0px', '100svb', '50px'); | ||
test_interpolated_value('0px', '100svmin', '50px'); | ||
test_interpolated_value('0px', '100lvh', '50px'); | ||
test_interpolated_value('0px', '100lvb', '50px'); | ||
test_interpolated_value('0px', '100lvmin', '50px'); | ||
test_interpolated_value('0px', '100dvh', '50px'); | ||
test_interpolated_value('0px', '100dvb', '50px'); | ||
test_interpolated_value('0px', '100dvmin', '50px'); | ||
|
||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
<!DOCTYPE html> | ||
<title>Viewport units in @media</title> | ||
<link rel="help" href="https://drafts.csswg.org/css-values-4/#viewport-relative-lengths"> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
|
||
<style> | ||
iframe { | ||
width: 200px; | ||
height: 100px; | ||
} | ||
</style> | ||
|
||
<iframe id=iframe></iframe> | ||
|
||
<script> | ||
|
||
const doc = iframe.contentDocument; | ||
const win = iframe.contentWindow; | ||
|
||
function test_media_query(feature, result, description) { | ||
test((t) => { | ||
t.add_cleanup(() => { doc.body.innerHTML = ''; }) | ||
doc.body.innerHTML = ` | ||
<style> | ||
body { | ||
color: red; | ||
} | ||
@media (${feature}) { | ||
body { | ||
color: green; | ||
} | ||
} | ||
</style> | ||
`; | ||
assert_equals(win.getComputedStyle(doc.body).color, result); | ||
}, description); | ||
} | ||
|
||
function test_media_query_applies(feature) { | ||
test_media_query(feature, 'rgb(0, 128, 0)', `@media(${feature}) applies`); | ||
} | ||
|
||
function test_media_query_does_not_apply(feature) { | ||
test_media_query(feature, 'rgb(255, 0, 0)', `@media(${feature}) does not apply`); | ||
} | ||
|
||
test_media_query_applies('width:100vw'); | ||
test_media_query_applies('width:100vi'); | ||
test_media_query_applies('width:100vmax'); | ||
test_media_query_applies('width:100svw'); | ||
test_media_query_applies('width:100svi'); | ||
test_media_query_applies('width:100svmax'); | ||
test_media_query_applies('width:100lvw'); | ||
test_media_query_applies('width:100lvi'); | ||
test_media_query_applies('width:100lvmax'); | ||
test_media_query_applies('width:100dvw'); | ||
test_media_query_applies('width:100dvi'); | ||
test_media_query_applies('width:100dvmax'); | ||
|
||
test_media_query_applies('height:100vh'); | ||
test_media_query_applies('height:100vb'); | ||
test_media_query_applies('height:100vmin'); | ||
test_media_query_applies('height:100svh'); | ||
test_media_query_applies('height:100svb'); | ||
test_media_query_applies('height:100svmin'); | ||
test_media_query_applies('height:100lvh'); | ||
test_media_query_applies('height:100lvb'); | ||
test_media_query_applies('height:100lvmin'); | ||
test_media_query_applies('height:100dvh'); | ||
test_media_query_applies('height:100dvb'); | ||
test_media_query_applies('height:100dvmin'); | ||
|
||
test_media_query_does_not_apply('width:90vw'); | ||
test_media_query_does_not_apply('height:90vh'); | ||
|
||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
<!DOCTYPE html> | ||
<title>Viewport units are responsive to writing-mode changes</title> | ||
<link rel="help" href="https://drafts.csswg.org/css-values-4/#viewport-relative-lengths"> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
|
||
<style> | ||
iframe { | ||
width: 200px; | ||
height: 100px; | ||
} | ||
</style> | ||
|
||
<iframe id=iframe></iframe> | ||
|
||
<script> | ||
|
||
const doc = iframe.contentDocument; | ||
const win = iframe.contentWindow; | ||
|
||
function test_writing_mode(value, expected_pre, expected_post) { | ||
test((t) => { | ||
t.add_cleanup(() => { doc.body.innerHTML = ''; }); | ||
doc.body.innerHTML = ` | ||
<style> | ||
div { | ||
writing-mode: initial; | ||
height: ${value}; | ||
} | ||
.vertical { | ||
writing-mode: vertical-rl; | ||
} | ||
</style> | ||
<div></div> | ||
`; | ||
let div = doc.querySelector('div'); | ||
assert_equals(win.getComputedStyle(div).height, expected_pre); | ||
|
||
// The writing-mode of the document element does not matter. | ||
t.add_cleanup(() => { doc.documentElement.classList.remove('vertical'); }) | ||
doc.documentElement.classList.add('vertical'); | ||
assert_equals(win.getComputedStyle(div).height, expected_pre); | ||
|
||
// The writing-mode of the target element is what matters. | ||
div.classList.add('vertical'); | ||
assert_equals(win.getComputedStyle(div).height, expected_post); | ||
}, `${value} computes to ${expected_post} with vertical writing-mode`); | ||
} | ||
|
||
test_writing_mode('100vi', '200px', '100px'); | ||
test_writing_mode('100svi', '200px', '100px'); | ||
test_writing_mode('100lvi', '200px', '100px'); | ||
test_writing_mode('100dvi', '200px', '100px'); | ||
|
||
test_writing_mode('100vb', '100px', '200px'); | ||
test_writing_mode('100svb', '100px', '200px'); | ||
test_writing_mode('100lvb', '100px', '200px'); | ||
test_writing_mode('100dvb', '100px', '200px'); | ||
|
||
</script> |