Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-viewport] [cssom-view-1] Add a definition of the zoom CSS property #9699

Merged
merged 34 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
87ef4cb
Add definition of the zoom css property
chrishtr Dec 12, 2023
60e6b37
Spell out the complete spec
chrishtr Dec 20, 2023
949b515
none
chrishtr Dec 20, 2023
44b4fdf
Avoid zero
chrishtr Dec 20, 2023
b150914
Further clarifications
chrishtr Dec 20, 2023
75dce70
Add zoom in more places
chrishtr Dec 21, 2023
120441e
Fixes to formatting
chrishtr Jan 4, 2024
aa8c478
Fixes to formatting
chrishtr Jan 4, 2024
abfba55
Replace 'or zoom' with 'unscaled'
chrishtr Jan 4, 2024
11ee897
Fix formatting and add alt text
chrishtr Jan 4, 2024
5c144b6
Shorten notes
chrishtr Jan 4, 2024
ec234ea
Shorten heading
chrishtr Jan 4, 2024
2fdbf35
Add background images
chrishtr Jan 4, 2024
56a6b7d
Omit fenced frames; clarify note about iframes
chrishtr Jan 4, 2024
bf27c4b
Fix spec reference type
chrishtr Jan 4, 2024
0ba0eed
Fix spaces and tabs
chrishtr Jan 4, 2024
78a456c
Fix some lint issues
chrishtr Jan 4, 2024
7b4e3d3
Remove stray character
chrishtr Jan 4, 2024
9471f9d
Remove more 'and zoom'
chrishtr Jan 4, 2024
665e588
fix unscaled
chrishtr Jan 4, 2024
742955c
Fix newlines
chrishtr Jan 4, 2024
a7612a6
Special-case 0 and 0%
chrishtr Jan 10, 2024
9fa4adf
HTMLImageElement.{x,y} should be scaled
chrishtr Jan 12, 2024
65cfc7d
Address code review feedback
chrishtr Jan 17, 2024
51a2dfc
Address code review comments
chrishtr Jan 17, 2024
75ba05b
Fix flat tree
chrishtr Jan 17, 2024
3729a02
Add notes about web compat
chrishtr Jan 17, 2024
8cce793
Fix references that should say 'scaled'
chrishtr Jan 17, 2024
652f315
Clarify effective zoom
chrishtr Jan 17, 2024
1f6d09a
Fix typo
chrishtr Jan 18, 2024
92d9734
Switch to used value instead of computed style
chrishtr Jan 23, 2024
e5a842f
Merge branch 'zoom' of https://github.com/chrishtr/csswg-drafts into …
chrishtr Jan 23, 2024
ce7628c
define used value instead of claiming it as a consequence
chrishtr Jan 23, 2024
993c701
Clarify flat tree ancestors
chrishtr Jan 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions css-viewport/Overview.bs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ spec: virtual-keyboard; urlPrefix: https://w3c.github.io/virtual-keyboard
type: attribute; text: overlaysContent; for: VirtualKeyboard; url: dom-virtualkeyboard-overlayscontent
</pre>

<pre class="anchors">
spec: fenced-frames; urlPrefix: https://wicg.github.io/fenced-frame/
type: interface; text: FencedFrames
</pre>

<h2 id="intro">
Introduction</h2>
Expand Down Expand Up @@ -356,6 +360,157 @@ only the value previously set to it.
}
</pre>

<h2 id='zoom-property'>
The 'zoom' property
</h2>

An element becomes zoomed when the 'zoom' property has a positive computed value different than 1 (or when a flat tree ancestor has zoom).
'zoom' affects computed property values and inherited property values.
chrishtr marked this conversation as resolved.
Show resolved Hide resolved
The computed value of 'zoom' is applied as a scalar to the used value of <<length>> CSS properties for the element and its descendants
chrishtr marked this conversation as resolved.
Show resolved Hide resolved
(including inherited properties such as 'line-height' or 'font-size'),
plus intrinsic sizing of all replaced elements,
background images,
and nested frames (except for fenced frames [[!FENCED-FRAME]]),
resulting in a magnification or minification effect.

Nested values of 'zoom' multiply, resulting in additional scaling of <<length>> values.
chrishtr marked this conversation as resolved.
Show resolved Hide resolved
This means that the used value for zoom is always its [=effective zoom=].

The 'zoom' property has no effect on <<length>> property values with computed values that are 'auto' or <<percentage>>.

Note: Unlike 'transform',
scaling the 'zoom' property affects layout.

Note: The computed value of 'font-size' is never <<percentage>>;
thus 'zoom' always applies.

Note: 'zoom' does not affect or prevent 'transform' scaling.

<pre class="propdef">
Name: zoom
Value: <<number>> || <<percentage>>
Initial: 1
Applies to: all <<length>> property values of all elements
Inherited: no
Percentages: Converted to <<number>>
Media: visual
Computed value: as specified, but with <<percentage>> converted to the equivalent <<number>>
Animation type: not animatable
</pre>

The values of this property have the following meanings:

<dl dfn-for="zoom" dfn-type=value>
<dt><dfn><<number>></dfn>
<dd>
Positive floating point number indicating a zoom factor.
Numbers smaller than 1.0 indicate a "zoom out" or minification effect,
while numbers greater than 1.0 indicate a "zoom in" or magnification effect.
A 0 value is treated as if it was 1.
chrishtr marked this conversation as resolved.
Show resolved Hide resolved

Note: The treatment of 0 is a web compatibility quirk.

<dt><dfn><<percentage>></dfn>
<dd>
Positive floating point number,
followed by a percentage character ("%") which indicates a zoom factor multiplied by 100.
A 0 percentage is treated as if it was 100%.
chrishtr marked this conversation as resolved.
Show resolved Hide resolved

Note: The treatment of 0 is a web compatibility quirk.

</dl>

Negative values for 'zoom' are illegal.

<div class="example">
Example of the 'zoom' property applied during hover for magnification effect.

<pre>
&lt;div class="messageBox"&gt;
&lt;div class="label"&gt;Text of the label&lt;/div&gt;
&lt;/div&gt;

&lt;style&gt;
.messageBox {
width: 10em;
padding: 2em;
border: medium solid lightblue;
}

.messageBox:hover {
zoom: 150%;
}

.label {
background: lightgrey;
padding: 1em;
text-align: center;
}
&lt;/style&gt;
</pre>

Here is an llustration of the before and after hover state of the message box element:
<img src="css_zoom_hover_example.png" alt="Two images,
showing the zooming effect before and after zoom has applied. The second is 1.5 larger.">
</div>

<div class="example">
Example of nested zoom.
In this example, "Inner text" is 4x as large as "Outer text",
and "Middle text" is 2x as large as "Outer text".

<pre>
&lt;div style="zoom: 2"&gt;
Middle text
&lt;div style="zoom: 2"&gt;
Inner text
&lt;div&gt;
&lt;div&gt;
Outer text
</pre>
</div>

<div class="example">
Example of replaced elements. In this example,
the image and iframe will be twice as large as their default sizing.

<pre>
&lt;div style="zoom: 2"&gt;
&lt;img src="..."&gt;
&lt;iframe src="..."&gt;&lt;/iframe&gt;
&lt;div&gt;
</pre>
</div>

The <dfn>effective zoom</dfn> of an element is the product of its computed
value of 'zoom' and all ancestors' computed values of 'zoom'.
chrishtr marked this conversation as resolved.
Show resolved Hide resolved
chrishtr marked this conversation as resolved.
Show resolved Hide resolved

The <dfn export>scaled</dfn> value of a CSS length is the used value of that length;
in particular it includes zoom.

The <dfn export>unscaled</dfn> value of a CSS length relative to an element is the [=scaled=] value divided by the element's [=effective zoom=].

<div class="note">
The [=effective zoom=] of an element in a nested frame may be a value other than 1 even if 'zoom' is never set on an element in that frame. This can be observed by authors via APIs such as {{Window/devicePixelRatio}} and {{Element/getBoundingClientRect}}.
</div>

<h3 id='zoom-om'>
DOM and CSSOM interaction
</h3>

Computed style APIs (i.e., all values returned by {{getComputedStyle()}}) that are non-auto and non-percentage lengths must be [=unscaled=].
lilles marked this conversation as resolved.
Show resolved Hide resolved

The {{Element/getBoundingClientRect}},
{{Element/getClientRects}},
and {{IntersectionObserver}} APIs must return rects with [=scaled=]
lengths.

All other APIs related to element geometries must return [=unscaled=] lengths.
This is explained in detail in [[cssom-view#extensions-to-the-htmlelement-interface]].

The {{Window/devicePixelRatio}} of a frame is multiplied by the [=effective zoom=] inherited by its parent frame.
chrishtr marked this conversation as resolved.
Show resolved Hide resolved
</h3>

<h2 class="no-num" id="changes">Appendix A. Changes</h2>

This appendix is <em>informative</em>.
Expand Down
Binary file added css-viewport/css_zoom_hover_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 16 additions & 15 deletions cssom-view-1/Overview.bs
Original file line number Diff line number Diff line change
Expand Up @@ -1141,7 +1141,7 @@ aborting on the first step that returns a value:
1. Return the {{DOMRect}} object in <var>list</var> at index 0.
1. If <a>caret node</a> is a text entry widget that is a replaced element,
and that is in the document,
return a {{DOMRect}} object for the caret in the widget
return a [=scaled=] {{DOMRect}} object for the caret in the widget
as represented by the <a>caret offset</a> value.
The <a>transforms</a> that apply to the element and its ancestors are applied.
1. Return null.
Expand Down Expand Up @@ -1190,7 +1190,7 @@ partial interface Element {
The <dfn method for=Element>getClientRects()</dfn> method, when invoked, must return the result of the following algorithm:

1. If the element on which it was invoked does not have an associated [=CSS/box=] return an empty {{DOMRectList}} object and stop this algorithm.
1. If the element has an associated <a>SVG layout box</a> return a {{DOMRectList}} object containing a single {{DOMRect}} object that describes the bounding box of the element as defined by the SVG specification, applying the <a>transforms</a> that apply to the element and its ancestors.
1. If the element has an associated <a>SVG layout box</a> return a [=scaled=] {{DOMRectList}} object containing a single {{DOMRect}} object that describes the bounding box of the element as defined by the SVG specification, applying the <a>transforms</a> that apply to the element and its ancestors.
1. Return a {{DOMRectList}} object containing {{DOMRect}} objects in content order, one for each <a spec=css-break>box fragment</a>, describing its border area (including those with a height or width of zero) with the following constraints:

* Apply the <a>transforms</a> that apply to the element and its ancestors.
Expand Down Expand Up @@ -1401,24 +1401,24 @@ The <dfn attribute for=Element>scrollHeight</dfn> attribute must return the resu
The <dfn attribute for=Element>clientTop</dfn> attribute must run these steps:

1. If the element has no associated [=CSS/box=] or if the [=CSS/box=] is inline, return zero.
1. Return the computed value of the 'border-top-width' property plus the height of any scrollbar rendered between the top <a>padding edge</a> and the top <a>border edge</a>, ignoring any <a>transforms</a> that apply to the element and its ancestors.
1. Return the [=unscaled=] computed value of the 'border-top-width' property plus the height of any scrollbar rendered between the top <a>padding edge</a> and the top <a>border edge</a>, ignoring any <a>transforms</a> that apply to the element and its ancestors.

The <dfn attribute for=Element>clientLeft</dfn> attribute must run these steps:

1. If the element has no associated [=CSS/box=] or if the [=CSS/box=] is inline, return zero.
1. Return the computed value of the 'border-left-width' property plus the width of any scrollbar rendered between the left <a>padding edge</a> and the left <a>border edge</a>, ignoring any <a>transforms</a> that apply to the element and its ancestors.
1. Return the [=unscaled=] computed value of the 'border-left-width' property plus the width of any scrollbar rendered between the left <a>padding edge</a> and the left <a>border edge</a>, ignoring any <a>transforms</a> that apply to the element and its ancestors.

The <dfn attribute for=Element>clientWidth</dfn> attribute must run these steps:

1. If the element has no associated [=CSS/box=] or if the [=CSS/box=] is inline, return zero.
1. If the element is the [=root element=] and the element's <a>node document</a> is not in <a>quirks mode</a>, or if the element is <a>the <code>body</code> element</a> and the element's <a>node document</a> <em>is</em> in <a>quirks mode</a>, return the <a>viewport</a> width excluding the size of a rendered scroll bar (if any).
1. Return the width of the <a>padding edge</a> excluding the width of any rendered scrollbar between the <a>padding edge</a> and the <a>border edge</a>, ignoring any <a>transforms</a> that apply to the element and its ancestors.
1. Return the [=unscaled=] width of the <a>padding edge</a> excluding the width of any rendered scrollbar between the <a>padding edge</a> and the <a>border edge</a>, ignoring any <a>transforms</a> or that apply to the element and its ancestors.

The <dfn attribute for=Element>clientHeight</dfn> attribute must run these steps:

1. If the element has no associated [=CSS/box=] or if the [=CSS/box=] is inline, return zero.
1. If the element is the [=root element=] and the element's <a>node document</a> is not in <a>quirks mode</a>, or if the element is <a>the <code>body</code> element</a> and the element's <a>node document</a> <em>is</em> in <a>quirks mode</a>, return the <a>viewport</a> height excluding the size of a rendered scroll bar (if any).
1. Return the height of the <a>padding edge</a> excluding the height of any rendered scrollbar between the <a>padding edge</a> and the <a>border edge</a>, ignoring any <a>transforms</a> that apply to the element and its ancestors.
1. Return the [=unscaled=] height of the <a>padding edge</a> excluding the height of any rendered scrollbar between the <a>padding edge</a> and the <a>border edge</a>, ignoring any <a>transforms</a> that apply to the element and its ancestors.


<h3 id=element-scrolling-members>{{Element}} Scrolling Members</h3>
Expand Down Expand Up @@ -1536,6 +1536,7 @@ The <dfn attribute for=HTMLElement>offsetParent</dfn> attribute must return the
1. If <var>ancestor</var> is <a>closed-shadow-hidden</a> from the element and its computed value of the 'position' property is ''position/fixed'', terminate this algorithm and return null.
1. If <var>ancestor</var> is not <a>closed-shadow-hidden</a> from the element and satisfies at least one of the following, terminate this algorithm and return <var>ancestor</var>.
* The element is a containing block of absolutely-positioned descendants (regardless of whether there are any absolutely-positioned descendants).
* The element has a non-default used value of 'zoom'.
* It is <a>the <code>body</code> element</a>.
* The computed value of the 'position' property of the element is ''static'' and the ancestor is one of the following <a>HTML elements</a>: <code>td</code>, <code>th</code>, or <code>table</code>.
1. If there is no more parent of <var>ancestor</var> in the <a>flat tree</a>, terminate this algorithm and return null.
Expand All @@ -1544,8 +1545,8 @@ The <dfn attribute for=HTMLElement>offsetParent</dfn> attribute must return the
The <dfn attribute for=HTMLElement>offsetTop</dfn> attribute must return the result of running these steps:

1. If the element is <a>the <code>body</code> element</a> or does not have any associated [=CSS/box=] return zero and terminate this algorithm.
1. If the {{HTMLElement/offsetParent}} of the element is null return the y-coordinate of the top <a>border edge</a> of the first [=CSS/box=] associated with the element, relative to the <a>initial containing block</a> origin, ignoring any <a>transforms</a> that apply to the element and its ancestors, and terminate this algorithm.
1. Return the result of subtracting the y-coordinate of the top <a>padding edge</a>
1. If the {{HTMLElement/offsetParent}} of the element is null return the [=unscaled=] y-coordinate of the top <a>border edge</a> of the first [=CSS/box=] associated with the element, relative to the <a>initial containing block</a> origin, ignoring any <a>transforms</a>that apply to the element and its ancestors and terminate this algorithm.
1. Return the [=unscaled=] result of subtracting the y-coordinate of the top <a>padding edge</a>
of the first [=CSS/box=] associated with the {{HTMLElement/offsetParent}} of the element
from the y-coordinate of the top <a>border edge</a>
of the first [=CSS/box=] associated with the element,
Expand All @@ -1557,13 +1558,13 @@ The <dfn attribute for=HTMLElement>offsetTop</dfn> attribute must return the res
The <dfn attribute for=HTMLElement>offsetLeft</dfn> attribute must return the result of running these steps:

1. If the element is <a>the <code>body</code> element</a> or does not have any associated [=CSS/box=] return zero and terminate this algorithm.
1. If the {{HTMLElement/offsetParent}} of the element is null return the x-coordinate of the left <a>border edge</a> of the first [=CSS/box=] associated with the element, relative to the <a>initial containing block</a> origin, ignoring any <a>transforms</a> that apply to the element and its ancestors, and terminate this algorithm.
1. Return the result of subtracting the x-coordinate of the left <a>padding edge</a> of the first [=CSS/box=] associated with the {{HTMLElement/offsetParent}} of the element from the x-coordinate of the left <a>border edge</a> of the first [=CSS/box=] associated with the element, relative to the <a>initial containing block</a> origin, ignoring any <a>transforms</a> that apply to the element and its ancestors.
1. If the {{HTMLElement/offsetParent}} of the element is null return the [=unscaled=] x-coordinate of the left <a>border edge</a> of the first [=CSS/box=] associated with the element, relative to the <a>initial containing block</a> origin, ignoring any <a>transforms</a> that apply to the element and its ancestors, and terminate this algorithm.
1. Return the [=unscaled=] result of subtracting the x-coordinate of the left <a>padding edge</a> of the first [=CSS/box=] associated with the {{HTMLElement/offsetParent}} of the element from the x-coordinate of the left <a>border edge</a> of the first [=CSS/box=] associated with the element, relative to the <a>initial containing block</a> origin, ignoring any <a>transforms</a> that apply to the element and its ancestors.

The <dfn attribute for=HTMLElement>offsetWidth</dfn> attribute must return the result of running these steps:

1. If the element does not have any associated [=CSS/box=] return zero and terminate this algorithm.
1. Return the width of the axis-aligned bounding box
1. Return the [=unscaled=] width of the axis-aligned bounding box
of the [=border boxes=]
of all fragments generated by the element's [=principal box=],
ignoring any <a>transforms</a> that apply to the element and its ancestors.
Expand All @@ -1576,7 +1577,7 @@ The <dfn attribute for=HTMLElement>offsetWidth</dfn> attribute must return the r
The <dfn attribute for=HTMLElement>offsetHeight</dfn> attribute must return the result of running these steps:

1. If the element does not have any associated [=CSS/box=] return zero and terminate this algorithm.
1. Return the height of the axis-aligned bounding box
1. Return the [=unscaled=] height of the axis-aligned bounding box
of the [=border boxes=]
of all fragments generated by the element's [=principal box=],
ignoring any <a>transforms</a> that apply to the element and its ancestors.
Expand All @@ -1596,11 +1597,11 @@ partial interface HTMLImageElement {
};
</pre>

The <dfn attribute for=HTMLImageElement>x</dfn> attribute, on getting, must return the x-coordinate of the left <a>border edge</a> of the
The <dfn attribute for=HTMLImageElement>x</dfn> attribute, on getting, must return the [=scaled=] x-coordinate of the left <a>border edge</a> of the
first [=CSS/box=] associated with the element, relative to the <a>initial containing block</a> origin, ignoring any
<a>transforms</a> that apply to the element and its ancestors, or zero if there is no [=CSS/box=].
chrishtr marked this conversation as resolved.
Show resolved Hide resolved

The <dfn attribute for=HTMLImageElement>y</dfn> attribute, on getting, must return the y-coordinate of the top <a>border edge</a> of the
The <dfn attribute for=HTMLImageElement>y</dfn> attribute, on getting, must return the [=scaled=] y-coordinate of the top <a>border edge</a> of the
first [=CSS/box=] associated with the element, relative to the <a>initial containing block</a> origin, ignoring any
<a>transforms</a> that apply to the element and its ancestors, or zero if there is no [=CSS/box=].

Expand All @@ -1620,7 +1621,7 @@ containing a list of {{DOMRect}} objects in content order that matches the follo

* For each element selected by the range, whose parent is not selected by the range, include the border areas returned by invoking {{Element/getClientRects()}} on the element.
* For each {{Text}} node selected or partially selected by the range (including when the
boundary-points are identical), include a {{DOMRect}} object (for the part that is selected, not
boundary-points are identical), include [=scaled=] {{DOMRect}} object (for the part that is selected, not
the whole line box). The bounds of these {{DOMRect}} objects are computed using font metrics;
thus, for horizontal writing, the vertical dimension of each box is determined by the font
ascent and descent, and the horizontal dimension by the text advance width. If the range covers
Expand Down