Skip to content

Commit

Permalink
Support small/large/dynamic/logical viewport units
Browse files Browse the repository at this point in the history
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
andruud authored and chromium-wpt-export-bot committed Feb 5, 2022
1 parent c1a9ac2 commit a78117e
Show file tree
Hide file tree
Showing 5 changed files with 341 additions and 0 deletions.
74 changes: 74 additions & 0 deletions css/css-values/viewport-units-compute.html
@@ -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>
65 changes: 65 additions & 0 deletions css/css-values/viewport-units-invalidation.html
@@ -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>
65 changes: 65 additions & 0 deletions css/css-values/viewport-units-keyframes.html
@@ -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>
77 changes: 77 additions & 0 deletions css/css-values/viewport-units-media-queries.html
@@ -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>
60 changes: 60 additions & 0 deletions css/css-values/viewport-units-writing-mode.html
@@ -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>

0 comments on commit a78117e

Please sign in to comment.