diff --git a/files/en-us/web/api/viewport/index.md b/files/en-us/web/api/viewport/index.md new file mode 100644 index 000000000000000..c93166121b0f7a6 --- /dev/null +++ b/files/en-us/web/api/viewport/index.md @@ -0,0 +1,35 @@ +--- +title: Viewport +slug: Web/API/Viewport +page-type: web-api-interface +status: + - experimental +browser-compat: api.Viewport +--- + +{{APIRef("Viewport Segments API")}}{{SeeCompatTable}} + +The **`Viewport`** interface of the {{domxref("Viewport Segments API", "Viewport Segments API", "", "nocode")}} represents the device's {{glossary("viewport")}}. + +{{InheritanceDiagram}} + +## Instance properties + +- {{domxref("Viewport.segments", "segments")}} {{ReadOnlyInline}} {{Experimental_Inline}} + - : Returns an array of {{domxref("DOMRect")}} objects representing the position and dimensions of each viewport segment within the overall display. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Using the Viewport Segments API](/en-US/docs/Web/API/Viewport_segments_API/Using) +- [Viewport Segments API](/en-US/docs/Web/API/Viewport_segments_API) +- [Visual Viewport API](/en-US/docs/Web/API/Visual_Viewport_API) +- [Device Posture API](/en-US/docs/Web/API/Device_Posture_API) +- [Origin trial for Foldable APIs](https://developer.chrome.com/blog/foldable-apis-ot) via developer.chrome.com (2024) diff --git a/files/en-us/web/api/viewport/segments/index.md b/files/en-us/web/api/viewport/segments/index.md new file mode 100644 index 000000000000000..fc60c696bd3ccd0 --- /dev/null +++ b/files/en-us/web/api/viewport/segments/index.md @@ -0,0 +1,47 @@ +--- +title: "Viewport: segments property" +short-title: segments +slug: Web/API/Viewport/segments +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.Viewport.segments +--- + +{{APIRef("Viewport Segments API")}}{{SeeCompatTable}} + +The **`segments`** read-only property of the {{domxref("Viewport")}} interface returns an array of {{domxref("DOMRect")}} objects representing the position and dimensions of each viewport segment within the overall display. + +## Value + +An array of {{domxref("DOMRect")}} objects. + +## Examples + +### Basic `Viewport.segments` usage + +This snippet will loop through each segment in the viewport, and log a string to the console detailing the index number, width, and height. + +```js +const segments = window.viewport.segments; + +segments.forEach((segment) => + console.log( + `Segment ${segments.indexOf(segment)} is ${segment.width}px x ${segment.height}px`, + ), +); +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Viewport Segments API](/en-US/docs/Web/API/Viewport_segments_API) +- [Visual viewport API](/en-US/docs/Web/API/Visual_Viewport_API) +- [Origin trial for Foldable APIs](https://developer.chrome.com/blog/foldable-apis-ot) via developer.chrome.com (2024) diff --git a/files/en-us/web/api/viewport_segments_api/index.md b/files/en-us/web/api/viewport_segments_api/index.md new file mode 100644 index 000000000000000..3f116abfbcfb6fa --- /dev/null +++ b/files/en-us/web/api/viewport_segments_api/index.md @@ -0,0 +1,61 @@ +--- +title: Viewport Segments API +slug: Web/API/Viewport_segments_API +page-type: web-api-overview +status: + - experimental +browser-compat: api.Viewport.segments +--- + +{{DefaultAPISidebar("Viewport segments API")}}{{seecompattable}} + +The **Viewport Segments API** allows developers to access the position and dimensions of logically separate viewport segments using CSS and JavaScript. _Viewport segments_ are created when the viewport is split by one or more hardware features such as a fold or a hinge between separate displays. With the Viewport Segments API, developers can create responsive designs optimized for different viewport segment sizes and arrangements. + +## Concepts and usage + +Devices with multiple displays that are intended to act as different segments of the same display surface (think foldable or hinged screen smartphones) present some unique design challenges to developers. You can optimize your layout for the display as a single entity, but how can you ensure that design elements fit snugly on the different segments and are not cut into two pieces? And how can you prevent content from being hidden by the physical fold/join? + +It may be important to know whether a user's device screen has a fold or join, what size the different segments are, whether they are the same size, and the orientation of the segments (whether they are side-by-side or top-to-bottom). The Viewport Segments API enables accessing the user's segmented device information with CSS and JavaScript features that provide access to the position and dimensions of each viewport segment within a display, including {{cssxref("@media")}} features to detect different horizontal and vertical region layouts. + +For an explanation of how the API works, see [Using the Viewport Segments API](/en-US/docs/Web/API/Viewport_segments_API/Using). + +## Interfaces + +- {{domxref("Viewport")}} + - : Represents the device's viewport. Provides access to the {{domxref("Viewport.segments")}} property, which returns an array of {{domxref("DOMRect")}} objects representing the position and dimensions of each viewport segment within a segmented display. + +### Extensions to other interfaces + +- {{domxref("Window.viewport")}} + - : Returns a `Viewport` object instance, which provides information about the current state of the device's viewport. + +## CSS features + +- {{cssxref("@media/horizontal-viewport-segments", "horizontal-viewport-segments")}} `@media` feature + - : Detects whether the device has a specified number of viewport segments laid out horizontally. +- {{cssxref("@media/vertical-viewport-segments", "vertical-viewport-segments")}} `@media` feature + - : Detects whether the device has a specified number of viewport segments laid out vertically. +- [Viewport segment environment variables](/en-US/docs/Web/CSS/env#viewport-segment-width) + - : These [environment variables](/en-US/docs/Web/CSS/CSS_environment_variables/Using_environment_variables) provide access to the edge coordinates and dimensions of each viewport segment. + +## Examples + +You can find a complete example demonstrating usage of the above features in the [Viewport segment API demo](https://mdn.github.io/dom-examples/viewport-segment-api/). + +If possible, you should view the demo on a foldable device. Current browser developer tools enable emulating foldable devices, but don't include emulation of the different physical segments. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Using the Viewport Segments API](/en-US/docs/Web/API/Viewport_segments_API/Using) +- [Viewport API](/en-US/docs/Web/API/Viewport_API) +- [Device Posture API](/en-US/docs/Web/API/Device_Posture_API) +- [CSS environment variables](/en-US/docs/Web/CSS/CSS_environment_variables) module +- [Origin trial for Foldable APIs](https://developer.chrome.com/blog/foldable-apis-ot) via developer.chrome.com (2024) diff --git a/files/en-us/web/api/viewport_segments_api/using/env-var-indices.png b/files/en-us/web/api/viewport_segments_api/using/env-var-indices.png new file mode 100644 index 000000000000000..ddb1aea08da7dde Binary files /dev/null and b/files/en-us/web/api/viewport_segments_api/using/env-var-indices.png differ diff --git a/files/en-us/web/api/viewport_segments_api/using/index.md b/files/en-us/web/api/viewport_segments_api/using/index.md new file mode 100644 index 000000000000000..33db1df88b3167e --- /dev/null +++ b/files/en-us/web/api/viewport_segments_api/using/index.md @@ -0,0 +1,340 @@ +--- +title: Using the Viewport Segments API +slug: Web/API/Viewport_segments_API/Using +page-type: guide +--- + +{{DefaultAPISidebar("Viewport segments API")}} + +This article explains how to use the [Viewport Segments API](/en-US/docs/Web/API/Viewport_segments_API) to create responsive designs optimized for different viewport segment sizes and arrangements. + +## The problem with foldable devices + +Foldable devices include smartphones, tablets, and laptops. Some fold inward, with the display folding into the interior of the device, and some fold outward, with the display wrapping around the device. Foldable devices come in a variety of forms: some have an actual folding screen, whereas some have separate screens with a physical hinge in the middle. They may be used in landscape orientation, with two screens side-by-side, and portrait orientation, with a top and a bottom screen. + +Whatever the case, foldable device displays are intended to act as different segments of the same display surface. While one person's foldable device may appear seemless and be used fully flat, similar to a single-segmented viewport, another may have an apparent seam be used at an angle that is less than a fully open, flat screen. This presents some unique challenges. You can optimize your layout for the display as a single entity, but how can you ensure that design elements fit snugly on the different segments and are not cut into two pieces? And how can you prevent content from being hidden by the physical fold/join? + +The viewport segments API provides features that allow you to detect (in CSS and JavaScript) whether the user's device screen has a fold or join, what size the different segments are, whether they are the same size, and what orientation they are in (side-by-side or top-to-bottom). We'll introduce you to these features in the following sections, then walk through a complete example to show them in action. + +## Viewport segment media features + +Two [media query](/en-US/docs/Web/CSS/CSS_media_queries) features are available that enable testing whether a device has a specific number of viewport segments laid out horizontally or vertically. These look like so: + +```css +/* Segments are laid out horizontally. */ +@media (horizontal-viewport-segments: 2) { + .wrapper { + flex-direction: row; + } + + /* ... */ +} + +/* Segments are laid out vertically. */ +@media (vertical-viewport-segments: 2) { + .wrapper { + flex-direction: column; + } + + /* ... */ +} +``` + +The {{cssxref("@media/horizontal-viewport-segments")}} media feature detects whether the device has a specified number of viewport segments laid out horizontally, whereas the {{cssxref("@media/vertical-viewport-segments")}} media feature detects whether the device has a specified number of viewport segments laid out vertically. + +## Viewport segment environment variables + +To be fit a layout precisely into the available viewport segments, the [viewport segment environment variables](/en-US/docs/Web/CSS/env#viewport-segment-width) provide access to each segments dimensions and placement inside the overall viewport. The browser provides [environment variables] enabling access to each segment's width and height and the offset positions of its top, right, bottom, and left edges: + +- `viewport-segment-width` +- `viewport-segment-height` +- `viewport-segment-top` +- `viewport-segment-right` +- `viewport-segment-bottom` +- `viewport-segment-left` + +The {{cssxref("env()")}} function is used to access these variables, with the name of the variable and two integers representing the indices of the segment to return the value for. For example: + +```css +/* Return the width of the top/left segment */ +env(viewport-segment-width 0 0) + +/* Return the width of the right segment */ +env(viewport-segment-width 1 0) + +/* Return the width of the bottom segment */ +env(viewport-segment-width 0 1) +``` + +The indices are both integers of `0` or greater. The first value represents the horizontal index value of the segment, and the second value represents the vertical index value of the segment: + +![Two device segment layouts; in a horizontal layout, 0 0 is the first segment and 1 0 is the second segment. In a vertical layout, the indices are 0 0 and 0 1](env-var-indices.png) + +- In a horizontal side-by-side layout, the left segment is represented by `0 0`, and the right segment is represented by `1 0`. +- In a vertical top to bottom layout, the top segment is represented by `0 0`, and the bottom segment is represented by `0 1`. + +In a layout, you can use these variables to set your containers to fit neatly into the available segments. For example: + +```css +@media (horizontal-viewport-segments: 2) { + .wrapper { + display: grid; + grid-template: "left fold right"; + grid-columns: env(viewport-segment-width 0 0) + env(viewport-segment-width 1 0); + } + .firstSection { + grid-area: left; + } + .secondSection { + grid-area: right; + } +} + +@media (vertical-viewport-segments: 2) { + .wrapper { + display: grid; + grid-template: + "top" + "bottom"; + grid-rows: env(viewport-segment-height 0 1) env(viewport-segment-width 0 0); + } + .firstSection { + grid-area: top; + } + .secondSection { + grid-area: bottom; + } +} +``` + +Here, we are setting the outer wrapper to be either a horizontal or vertical grid layout, based on whether the viewport segments are laid out horizontally or vertically. We then set the left and top cells to be the first segments, and place the second section in the right or bottom grid cells. + +We could add an empty middle "fold" cell to stop content being obscured by the fold. We could calculate its thickness by subtracting the combined widths or heights of the two sides from the full viewport size, or set the middle cell to `1fr`. + +```css +@media (horizontal-viewport-segments: 2) { + .wrapper { + grid-template: "left fold right"; + grid-columns: + env(viewport-segment-width 0 0) + calc(100vw - (env(viewport-segment-width 0 0) + env(viewport-segment-width 1 0)) + env(viewport-segment-width 1 0); + } +} + +@media (vertical-viewport-segments: 2) { + .wrapper { + grid-template: + "top" + "fold" + "bottom"; + grid-rows: env(viewport-segment-height 0 1) 1fr env(viewport-segment-width 0 0); + + } +} +``` + +## Accessing segment information in JavaScript + +You can access segment information in JavaScript using the {{domxref("Viewport.segments", "window.viewport.segments")}} property, which returns an array of {{domxref("DOMRect")}} objects providing access to each segment's `x` and `y` coordinates inside the overall viewport, and their `width` and `height`. + +For example, this snippet will loop through each segment in the viewport and log a string to the console detailing the index number, width, and height. + +```js +const segments = window.viewport.segments; + +segments.forEach((segment) => + console.log( + `Segment ${segments.indexOf(segment)} is ${segment.width}px x ${segment.height}px`, + ), +); +``` + +## A complete example + +Let's look at the Viewport Segment API features in action in a real example. You can see our example running live at [Viewport segment API demo](https://mdn.github.io/dom-examples/viewport-segment-api/) (see the full [source code](https://github.com/mdn/dom-examples/tree/main/viewport-segment-api) also). If possible, view the demo on a real foldable device. Browser developer tools that enable visually emulating the multiple segments of foldable devices generally don't include emulation of the physical segmentation. + +> [!NOTE] +> This example is adapted from [Origin trial for Foldable APIs](https://developer.chrome.com/blog/foldable-apis-ot) by Alexis Menard and Thomas Steiner, originally published on `developer.chrome.com` in 2024 under the [Creative Commons Attribution 4.0 License](https://creativecommons.org/licenses/by/4.0/). + +We'll run through the source code in the following sections. + +### HTML structure + +The markup features a wrapper {{htmlelement("div")}} containing two {{htmlelement("section")}} elements representing a basic list view and detail view, and a fold `
` representing the fold between the two segments on a foldable device. + +```html +
+
+ +
+
+
+ +
+
+``` + +### Selectively applying layouts for different segment orientations + +In our CSS, we use a combination of media queries and environment variables to create responsive layouts that will fit comfortably into the available segments. + +First of all, we use {{cssxref("@media/orientation", "orientation")}} media query tests to set an appropriate flexbox layout for the wrapper `
` children in each eventuality — a `row` for `landscape` viewports, and a `column` for `portrait` viewports. Note how we've also set the fold `
` to a thin strip in these cases to act as a divider between the two content containers — `20px` wide in the `landscape` layout, and `20px` high in the `portrait` layout. + +```css +.wrapper { + height: 100%; + display: flex; +} + +@media (orientation: landscape) { + .wrapper { + flex-direction: row; + } + + .list-view, + .detail-view { + flex: 1; + } + + .fold { + height: 100%; + width: 20px; + } +} + +@media (orientation: portrait) { + .wrapper { + flex-direction: column; + } + + .list-view, + .detail-view { + flex: 1; + } + + .fold { + height: 20px; + } +} +``` + +Next, we use a {{cssxref("@media/horizontal-viewport-segments")}} media query to handle the case of foldable devices where the segments are side-by-side. + +We set the outer wrapper to have a horizontal flexbox layout when the viewport segments are laid out horizontally. We set the left container to have a width equal to the left segment width (`env(viewport-segment-width 0 0)`), and the right container to have a width equal to the right segment width (`env(viewport-segment-width 1 0)`). To calculate how much width the fold takes up in between the two, we subtract the left edge offset of the right container from the right edge offset of the left container (`calc(env(viewport-segment-left 1 0) - env(viewport-segment-right 0 0));`). + +```css +@media (horizontal-viewport-segments: 2) { + .wrapper { + flex-direction: row; + } + + .list-view { + width: env(viewport-segment-width 0 0); + } + + .fold { + width: calc( + env(viewport-segment-left 1 0) - env(viewport-segment-right 0 0) + ); + background-color: black; + height: 100%; + } + + .detail-view { + width: env(viewport-segment-width 1 0); + } +} +``` + +Finally, we use a {{cssxref("@media/vertical-viewport-segments")}} media query to handle the case of foldable devices where the segments are top-to-bottom. This uses the same approach as the previous code snippet, except that we are setting heights rather than widths, and using height/top/bottom environment variables to return the required values. + +```css +@media (vertical-viewport-segments: 2) { + .wrapper { + flex-direction: column; + } + + .list-view { + height: env(viewport-segment-height 0 0); + } + + .fold { + width: 100%; + height: calc( + env(viewport-segment-top 0 1) - env(viewport-segment-bottom 0 0) + ); + background-color: black; + } + + .detail-view { + height: env(viewport-segment-height 0 1); + } +} +``` + +### Reporting the segment size using JavaScript + +We also report the dimensions of each segment, changing the values as the screen is resized, or the [device posture](/en-US/docs/Web/API/Device_Posture_API) or orientation changes. + +First of all, we grab references to the wrapper `
` and its two `
` element children (these are the two containers we've placed inside the two segments with CSS). + +```js +const wrapperElem = document.querySelector(".wrapper"); +const listViewElem = document.querySelector(".list-view"); +const detailViewElem = document.querySelector(".detail-view"); +``` + +Next, we define an `addSegmentOutput()` function which takes a `segments` array, an index number, and an element reference as arguments. This function appends a segment output `
` to the referenced element. The output includes a heading with the index number of viewport segment and the dimensions of that segment. + +```js +function addSegmentOutput(segments, i, elem) { + const segment = segments[i]; + + const divElem = document.createElement("div"); + divElem.className = "segment-output"; + + elem.appendChild(divElem); + + divElem.innerHTML = `

Viewport segment ${i}

+

${segment.width}px x ${segment.height}px

`; +} +``` + +Next, we define a `reportSegments()` function which removes any previously appended segment output `
` elements, clearing the `
`, then it calls the previously defined `addSegmentOutput()` function based on the array of the device's segments retrieved using {{domxref("Viewport.segments", "window.viewport.segments")}}. We check the number of segments present: + +- If only one segment is present, we run `addSegmentOutput()` once, adding a segment output `
` to the wrapper `
`. This will report the dimensions of the entire viewport. +- If two segments are present, we run `addSegmentOutput()` twice, adding a segment output `
` to each of the `
` elements. These will report the dimensions of each segment output `
`'s segment parent. + +```js +function reportSegments() { + // Remove all previous segment output elements before adding more + document.querySelectorAll(".segment-output").forEach((elem) => elem.remove()); + + const segments = window.viewport.segments; + + if (segments.length === 1) { + addSegmentOutput(segments, 0, wrapperElem); + } else { + addSegmentOutput(segments, 0, listViewElem); + addSegmentOutput(segments, 1, detailViewElem); + } +} +``` + +Finally, we call the `reportSegments()` function and add event listeners to run it in a couple of different contexts: + +- We run it once in the global scope so that the segment reports are added to the page as soon as the page loads. +- We run it based on the [`resize`](/en-US/docs/Web/API/Window/resize_event) event to update the segment reports when the window is resized (which includes orientation changes). + - We run it based on the `DevicePosture`'s [`change`](/en-US/docs/Web/API/DevicePosture/change_event) event, to update the segment reports when the device posture changes. + +```js +reportSegments(); +window.addEventListener("resize", reportSegments); +navigator.devicePosture.addEventListener("change", reportSegments); +``` + +## See also + +- [Device Posture API](/en-US/docs/Web/API/Device_Posture_API) diff --git a/files/en-us/web/api/window/index.md b/files/en-us/web/api/window/index.md index 87d7a57e850cb0c..4bf8e79950cc722 100644 --- a/files/en-us/web/api/window/index.md +++ b/files/en-us/web/api/window/index.md @@ -141,6 +141,8 @@ Note that properties which are objects (e.g., for overriding the prototype of bu - : Returns a reference to the topmost window in the window hierarchy. This property is read only. - {{domxref("Window.trustedTypes")}} {{ReadOnlyInline}} - : Returns the {{domxref("TrustedTypePolicyFactory")}} object associated with the global object, providing the entry point for using the {{domxref("Trusted Types API", "", "", "nocode")}}. +- {{domxref("Window.viewport")}} {{Experimental_inline}} {{ReadOnlyInline}} + - : Returns a {{domxref("Viewport")}} object instance, which provides information about the current state of the device's viewport. - {{domxref("Window.visualViewport")}} {{ReadOnlyInline}} - : Returns a {{domxref("VisualViewport")}} object which represents the visual viewport for a given window. - {{domxref("Window.window")}} {{ReadOnlyInline}} diff --git a/files/en-us/web/api/window/viewport/index.md b/files/en-us/web/api/window/viewport/index.md new file mode 100644 index 000000000000000..44ee8731cf6b6c2 --- /dev/null +++ b/files/en-us/web/api/window/viewport/index.md @@ -0,0 +1,48 @@ +--- +title: "Window: viewport property" +short-title: viewport +slug: Web/API/Window/viewport +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.Window.viewport +--- + +{{APIRef("Viewport Segments API")}}{{SeeCompatTable}} + +The `viewport` read-only property of the {{domxref("Window")}} interface returns a {{domxref("Viewport")}} object instance, which provides information about the current state of the device's viewport. + +See the {{domxref("Viewport")}} API for all available properties. + +## Value + +A {{domxref("Viewport")}} object instance. + +## Examples + +### Basic `viewport` usage + +```js +const currentViewport = window.viewport; +const segments = window.viewport.segments; +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- {{domxref("Viewport.segments")}} property +- {{domxref("Viewport")}} interface +- {{domxref("VisualViewport")}} interface +- [Viewport API](/en-US/docs/Web/API/Viewport_API) +- [Viewport Segments API](/en-US/docs/Web/API/Viewport_segments_API) +- [Visual Viewport API](/en-US/docs/Web/API/Visual_Viewport_API) +- [Viewport concepts](/en-US/docs/Web/CSS/CSSOM_view/Viewport_concepts) +- [CSS viewport](/en-US/docs/Web/CSS/CSS_viewport) module +- [CSSOM view](/en-US/docs/Web/CSS/CSSOM_view) module diff --git a/files/en-us/web/css/@media/horizontal-viewport-segments/index.md b/files/en-us/web/css/@media/horizontal-viewport-segments/index.md new file mode 100644 index 000000000000000..4196de16a74e91d --- /dev/null +++ b/files/en-us/web/css/@media/horizontal-viewport-segments/index.md @@ -0,0 +1,77 @@ +--- +title: horizontal-viewport-segments +slug: Web/CSS/@media/horizontal-viewport-segments +page-type: css-media-feature +browser-compat: css.at-rules.media.horizontal-viewport-segments +sidebar: cssref +--- + +The **`horizontal-viewport-segments`** [CSS](/en-US/docs/Web/CSS) [media feature](/en-US/docs/Web/CSS/@media#media_features) detects whether the device has a specified number of viewport segments laid out horizontally (side by side). + +Related to the [Viewport Segments API](/en-US/docs/Web/API/Viewport_segments_API), the `vertical-viewport-segments` feature can be used to create responsive designs that work well on multi-viewport devices — devices with a display that is divided into logically separate viewport segments, such as foldable or hinged devices. + +## Syntax + +The `horizontal-viewport-segments` feature is specified as an {{cssxref("integer")}} value of `1` or greater, representing the number of horizontal viewport segments the device has. + +- The value will be `1` for: + - A non-foldable device (for example, a standard single-screen smartphone or tablet) + - A foldable device that is either unfolded or closed (in the [`continuous` device posture](/en-US/docs/Web/API/Device_Posture_API#continuous)). + - A two-screen hinged device or a foldable device that is currently folded and is oriented vertically so the segments are on top of each other. +- The value will be `2` for a two-screen hinged device or a foldable device that is currently folded (in the [`folded` device posture](/en-US/docs/Web/API/Device_Posture_API#folded)) and is oriented horizontally so the segments are side by side. +- The value may be greater than `2` for foldable devices with more than one fold. + +## Examples + +### Basic `horizontal-viewport-segments` usage + +In this snippet we use a `horizontal-viewport-segments` media query to handle the case of foldable devices where the segments are side-by-side. + +We set the left container to have a width equal to the left segment width (`env(viewport-segment-width 0 0)`), and the right container to have a width equal to the right segment width (`env(viewport-segment-width 1 0)`). + +To calculate how much width the fold takes up in between the two, we subtract the left edge offset of the right container from the right edge offset of the left container (`calc(env(viewport-segment-left 1 0) - env(viewport-segment-right 0 0));`). + +```css +.wrapper { + height: 100%; + display: flex; +} + +@media (horizontal-viewport-segments: 2) { + .wrapper { + flex-direction: row; + } + + .list-view { + width: env(viewport-segment-width 0 0); + } + + .fold { + width: calc( + env(viewport-segment-left 1 0) - env(viewport-segment-right 0 0) + ); + background-color: black; + height: 100%; + } + + .detail-view { + width: env(viewport-segment-width 1 0); + } +} +``` + +See our [Viewport segment API demo](https://mdn.github.io/dom-examples/viewport-segment-api/) for a full working demo ([source code](https://github.com/mdn/dom-examples/tree/main/viewport-segment-api)). Also check out [Using the Viewport Segments API](/en-US/docs/Web/API/Viewport_segments_API/Using) for a full demo explanation. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- {{cssxref("@media/vertical-viewport-segments", "vertical-viewport-segments")}} `@media` feature +- [Viewport Segments API](/en-US/docs/Web/API/Viewport_segments_API) +- [Origin trial for Foldable APIs](https://developer.chrome.com/blog/foldable-apis-ot) via developer.chrome.com (2024) diff --git a/files/en-us/web/css/@media/index.md b/files/en-us/web/css/@media/index.md index 32668b6a7a08802..a5bb1075ad9218a 100644 --- a/files/en-us/web/css/@media/index.md +++ b/files/en-us/web/css/@media/index.md @@ -122,6 +122,8 @@ Media feature expressions test for their presence, value, or range of values, an - : Does the device use a grid or bitmap screen? - {{cssxref("@media/height", "height")}} - : Height of the viewport. +- {{cssxref("@media/horizontal-viewport-segments", "horizontal-viewport-segments")}} + - : Detects whether the device has a specified number of viewport segments laid out horizontally. - {{cssxref("@media/hover", "hover")}} - : Does the primary input mechanism allow the user to hover over elements? - {{cssxref("@media/inverted-colors", "inverted-colors")}} @@ -161,6 +163,8 @@ Media feature expressions test for their presence, value, or range of values, an - : Detects the shape of the device to distinguish rectangular and round displays. - {{cssxref("@media/update", "update")}} - : How frequently the output device can modify the appearance of content. +- {{cssxref("@media/vertical-viewport-segments", "vertical-viewport-segments")}} + - : Detects whether the device has a specified number of viewport segments laid out vertically. Added in Media Queries Level 5. - {{cssxref("@media/video-dynamic-range", "video-dynamic-range")}} - : Combination of brightness, contrast ratio, and color depth that are supported by the video plane of user agent and the output device. Added in Media Queries Level 5. - {{cssxref("@media/width", "width")}} diff --git a/files/en-us/web/css/@media/vertical-viewport-segments/index.md b/files/en-us/web/css/@media/vertical-viewport-segments/index.md new file mode 100644 index 000000000000000..cde0eeb9d91c799 --- /dev/null +++ b/files/en-us/web/css/@media/vertical-viewport-segments/index.md @@ -0,0 +1,77 @@ +--- +title: vertical-viewport-segments +slug: Web/CSS/@media/vertical-viewport-segments +page-type: css-media-feature +browser-compat: css.at-rules.media.vertical-viewport-segments +sidebar: cssref +--- + +The **`vertical-viewport-segments`** [CSS](/en-US/docs/Web/CSS) [media feature](/en-US/docs/Web/CSS/@media#media_features) detects whether the device has a specified number of viewport segments laid out vertically (top to bottom). + +Related to the [Viewport Segments API](/en-US/docs/Web/API/Viewport_segments_API), the `vertical-viewport-segments` feature can be used to create responsive designs that work well on multi-viewport devices — devices with a display that is divided into logically separate viewport segments, such as foldable or hinged devices. + +## Syntax + +The `vertical-viewport-segments` feature is specified as an {{cssxref("integer")}} value of `1` or greater, representing the number of vertical viewport segments the device has. + +- The value will be `1` for: + - A non-foldable device (for example, a standard single-screen smartphone or tablet). + - A foldable device that is either unfolded or closed (in the [`continuous` device posture](/en-US/docs/Web/API/Device_Posture_API#continuous)). + - A two-screen hinged device or a foldable device that is currently folded and is oriented horizontally so the segments are side by side. +- The value will be `2` for a two-screen hinged device or a foldable device that is currently folded (in the [`folded` device posture](/en-US/docs/Web/API/Device_Posture_API#folded)) and is oriented vertically so the segments are on top of one another. +- The value may be greater than `2` for foldable devices with more than one fold. + +## Examples + +### Basic `vertical-viewport-segments` usage + +In this snippet we use a `vertical-viewport-segments` media query to handle the case of foldable devices where the segments are top-to-bottom. + +We set the top container to have a height equal to the top segment height (`env(viewport-segment-height 0 0)`), and the bottom container to have a height equal to the bottom segment height (`env(viewport-segment-height 0 1)`). + +To calculate how much height the fold takes up in between the two, we subtract the bottom edge offset of the top container from the top edge offset of the bottom container (`calc(env(viewport-segment-top 0 1) - env(viewport-segment-bottom 0 0));`). + +```css +.wrapper { + height: 100%; + display: flex; +} + +@media (vertical-viewport-segments: 2) { + .wrapper { + flex-direction: column; + } + + .list-view { + height: env(viewport-segment-height 0 0); + } + + .fold { + width: 100%; + height: calc( + env(viewport-segment-top 0 1) - env(viewport-segment-bottom 0 0) + ); + background-color: black; + } + + .detail-view { + height: env(viewport-segment-height 0 1); + } +} +``` + +See our [Viewport segment API demo](https://mdn.github.io/dom-examples/viewport-segment-api/) for a full working demo ([source code](https://github.com/mdn/dom-examples/tree/main/viewport-segment-api)). Also check out [Using the Viewport Segments API](/en-US/docs/Web/API/Viewport_segments_API/Using) for a full demo explanation. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- {{cssxref("@media/horizontal-viewport-segments", "horizontal-viewport-segments")}} `@media` feature +- [Viewport Segments API](/en-US/docs/Web/API/Viewport_segments_API) +- [Origin trial for Foldable APIs](https://developer.chrome.com/blog/foldable-apis-ot) via developer.chrome.com (2024) diff --git a/files/en-us/web/css/css_environment_variables/index.md b/files/en-us/web/css/css_environment_variables/index.md index 43d4b6feea04927..0ec49b8c29d42b4 100644 --- a/files/en-us/web/css/css_environment_variables/index.md +++ b/files/en-us/web/css/css_environment_variables/index.md @@ -27,9 +27,12 @@ Environment variables provide values that can be used on the page based on infor ## Related concepts +- [CSS media queries](/en-US/docs/Web/CSS/CSS_media_queries) module - [custom properties](/en-US/docs/Web/CSS/--*) - {{cssxref("var")}} - {{domxref("VirtualKeyboard")}} interface +- [`display_override`](/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/display_override) manifest field + [Window Controls Overlay API](/en-US/docs/Web/API/Window_Controls_Overlay_API) and {{domxref("WindowControlsOverlay"))}} interface ## Specifications diff --git a/files/en-us/web/css/css_fragmentation/index.md b/files/en-us/web/css/css_fragmentation/index.md index 646e682cfa875e3..0df029a9b16b342 100644 --- a/files/en-us/web/css/css_fragmentation/index.md +++ b/files/en-us/web/css/css_fragmentation/index.md @@ -56,5 +56,5 @@ When content is physically printed or displayed as a print preview, there are pa ## See also - [`horizontal-viewport-segments`](/en-US/docs/Web/CSS/@media/horizontal-viewport-segments) and [`vertical-viewport-segments`](/en-US/docs/Web/CSS/@media/vertical-viewport-segments) `@media` descriptors -- [Viewport segments API](/en-US/docs/Web/API/Viewport_segments_API) +- [Viewport Segments API](/en-US/docs/Web/API/Viewport_segments_API) - [CSS multi-column layout](/en-US/docs/Web/CSS/CSS_multicol_layout) module diff --git a/files/en-us/web/css/css_media_queries/index.md b/files/en-us/web/css/css_media_queries/index.md index 87cda893244ced8..2152efc241b44e9 100644 --- a/files/en-us/web/css/css_media_queries/index.md +++ b/files/en-us/web/css/css_media_queries/index.md @@ -42,6 +42,7 @@ When designing reusable HTML components, you may also use [container queries](/e - {{cssxref("@media/forced-colors", "forced-colors")}} - {{cssxref("@media/grid", "grid")}} - {{cssxref("@media/height", "height")}} +- {{cssxref("@media/horizontal-viewport-segments", "horizontal-viewport-segments")}} - {{cssxref("@media/hover", "hover")}} - {{cssxref("@media/inverted-colors", "inverted-colors")}} - {{cssxref("@media/monochrome", "monochrome")}} @@ -58,10 +59,11 @@ When designing reusable HTML components, you may also use [container queries](/e - {{cssxref("@media/scan", "scan")}} - {{cssxref("@media/scripting", "scripting")}} - {{cssxref("@media/update", "update")}} +- {{cssxref("@media/vertical-viewport-segments", "vertical-viewport-segments")}} - {{cssxref("@media/video-dynamic-range", "video-dynamic-range")}} - {{cssxref("@media/width", "width")}} -The CSS media queries level 5 module also introduces the `environment-blending`, `horizontal-viewport-segments`, `nav-controls`, `vertical-viewport-segments`, and `video-color-gamut` `@media` descriptors. Currently, no browsers support these features. +The CSS media queries level 5 module also introduces the `environment-blending`, `nav-controls`, and `video-color-gamut` `@media` descriptors. Currently, no browsers support these features. > [!NOTE] > CSS media queries level 4 deprecated three `@media` descriptors: {{cssxref("@media/device-aspect-ratio", "device-aspect-ratio")}}, {{cssxref("@media/device-height", "device-height")}}, and {{cssxref("@media/device-width", "device-width")}}. @@ -107,6 +109,8 @@ The CSS media queries level 5 module also introduces the `environment-blending`, - [CSS conditional rules](/en-US/docs/Web/CSS/CSS_conditional_rules) module - {{cssxref("@supports")}} at-rule - [Using feature queries](/en-US/docs/Web/CSS/CSS_conditional_rules/Using_feature_queries) +- [CSS environment variables](/en-US/docs/Web/CSS/CSS_environment_variables) + - {{cssxref("env()")}} function - [CSS paged media](/en-US/docs/Web/CSS/CSS_paged_media) module - {{cssxref("@page")}} at-rule - [CSS object model](/en-US/docs/Web/API/CSS_Object_Model) module diff --git a/files/en-us/web/css/env/env-var-indices.png b/files/en-us/web/css/env/env-var-indices.png new file mode 100644 index 000000000000000..ddb1aea08da7dde Binary files /dev/null and b/files/en-us/web/css/env/env-var-indices.png differ diff --git a/files/en-us/web/css/env/index.md b/files/en-us/web/css/env/index.md index e3cda601eea3ac6..25a87d1dcedf0fc 100644 --- a/files/en-us/web/css/env/index.md +++ b/files/en-us/web/css/env/index.md @@ -6,84 +6,95 @@ browser-compat: css.types.env sidebar: cssref --- -The **`env()`** [CSS](/en-US/docs/Web/CSS) [function](/en-US/docs/Web/CSS/CSS_Values_and_Units/CSS_Value_Functions) can be used to insert the value of a user-agent defined environment variable into your CSS. +The **`env()`** [CSS](/en-US/docs/Web/CSS) [function](/en-US/docs/Web/CSS/CSS_Values_and_Units/CSS_Value_Functions) can be used to insert the value of a user-agent defined [environment variable](/en-US/docs/Web/CSS/CSS_environment_variables/Using_environment_variables) into your CSS. ## Syntax ```css -/* Using the four safe area inset values with no fallback values */ +/* Without a fallback value */ env(safe-area-inset-top); -env(safe-area-inset-right); -env(safe-area-inset-bottom); -env(safe-area-inset-left); +env(titlebar-area-width); +env(viewport-segment-right 0 0); -/* Using them with fallback values */ -env(safe-area-inset-top, 20px); +/* With a fallback value */ env(safe-area-inset-right, 1em); -env(safe-area-inset-bottom, 0.5vh); -env(safe-area-inset-left, 1.4rem); +env(titlebar-area-y, 40px); +env(viewport-segment-width 0 0, 40%); ``` ### Parameters -The `env()` function's syntax is as follows: +The `env( , )` function accepts the following parameters: -```plain -env(, ) -``` +- [``](/en-US/docs/Web/CSS/CSS_environment_variables/Using_environment_variables#browser-defined_environment_variables) + - : A {{cssxref("<custom-ident>")}} specifying the name of the environment variable to be inserted. If the name provided represents an array-like environment variable, the name is followed by {{cssxref("<integer>")}} values identifying the specific instance the name is referencing. The case-sensitive environment variable name can be one of the following: + - `safe-area-inset-top`, `safe-area-inset-right`, `safe-area-inset-bottom`, `safe-area-inset-left` + - : The safe distance from the top, right, bottom, or left inset edge of the viewport, defining where it is safe to place content into without risking it being cut off by the shape of a non‑rectangular display. The four values form a rectangle, inside which all content is visible. The values are `0` if the viewport is a rectangle and no features — such as toolbars or dynamic keyboards — are occupying viewport space; otherwise, it is a `px` value greater than `0`. + - `safe-area-max-inset-top`, `safe-area-max-inset-right`, `safe-area-max-inset-bottom`, `safe-area-max-inset-left` + - : The static maximum values of their dynamic `safe-area-inset-*` variable counterparts when all dynamic user interface features are retracted. While the `safe-area-inset-*` values change as the currently-visible content area changes, the `safe-area-max-inset-*` values are constants. + - `titlebar-area-x`, `titlebar-area-y`, `titlebar-area-width`, `titlebar-area-height` + - : The dimensions of a visible `titlebar-area-*` area. These variables are available when using the `window-controls-overlay` [`display_override`](/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/display_override) manifest field. The variables' values can be used to ensure content doesn't overlap window control buttons (that is, minimize, maximize, and close) with progressive web apps (PWA) installed on desktop devices. + - `keyboard-inset-top`, `keyboard-inset-right`, `keyboard-inset-bottom`, `keyboard-inset-left`, `keyboard-inset-width`, `keyboard-inset-height` + - : The insets from the edge of the viewport and dimensions of the device's on-screen virtual keyboard. Defined in the {{domxref("VirtualKeyboard API", "VirtualKeyboard API", "", "nocode")}}. + - `viewport-segment-width`, `viewport-segment-height`, `viewport-segment-top`, `viewport-segment-right`, `viewport-segment-bottom`, `viewport-segment-left` + - : The dimensions and offset positions of specific viewport segments. The `viewport-segment-*` keyword is followed by two space-separated {{cssxref("<integer>")}} values that indicate the segment's horizontal and vertical position, or indices. The viewport-segment keywords are only defined when the viewport is made up of two or more segments, as with foldable or hinged devices. -The `` can be one of the following: +- `` {{optional_inline}} + - : A fallback value to be inserted if the environment variable referenced in the first argument does not exist. Everything after the first comma is deemed to be the fallback value. This can be a single value, another `env()` function, or a comma-separated list of values. -- `safe-area-inset-top`, `safe-area-inset-right`, `safe-area-inset-bottom`, `safe-area-inset-left` - - : The `safe-area-inset-*` variables are four environment variables that define a rectangle by its top, right, bottom, and left insets from the edge of the viewport, which is safe to put content into without risking it being cut off by the shape of a non‑rectangular display. For rectangular viewports, like your average laptop monitor, their value is equal to zero. For non-rectangular displays — like a round watch face — the four values set by the user agent form a rectangle such that all content inside the rectangle is visible. -- `safe-area-max-inset-top`, `safe-area-max-inset-right`, `safe-area-max-inset-bottom`, `safe-area-max-inset-left` - - : The safe area maximum inset environment variables represent the static maximum value of their dynamic `safe-area-inset-*` variable counterpart. -- `titlebar-area-x`, `titlebar-area-y`, `titlebar-area-width`, `titlebar-area-height` - - : The `titlebar-area-*` variables are useful for PWA installed on Desktop devices. When a desktop PWA uses the `window-controls-overlay` [display_override](/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/display_override) value, then it can use the `titlebar-area-*` variables to make sure content doesn't overlap with the window control buttons (i.e., minimize, maximize, and close). -- `keyboard-inset-top`, `keyboard-inset-right`, `keyboard-inset-bottom`, `keyboard-inset-left`, `keyboard-inset-width`, `keyboard-inset-height` - - : The `keyboard-inset-*` variables provide information about the on-screen virtual keyboard's appearance. They define a rectangle by its top, right, bottom, and left insets from the edge of the viewport (the width and height insets are calculated from the other insets). To learn more, see the {{domxref("VirtualKeyboard API", "VirtualKeyboard API", "", "nocode")}}. +## Description -> [!NOTE] -> Like other CSS custom property names, user agent-defined environment variable names are case-sensitive. +The `env()` function is used to insert the value of a globally-scoped, [user-agent-defined environment variable](/en-US/docs/Web/CSS/CSS_environment_variables/Using_environment_variables#browser-defined_environment_variables) into your CSS. The `env()` function can be used as a property value or in place of any part of a property value or descriptor (for example, in [Media query rules](/en-US/docs/Web/CSS/@media)). -## Description +The function accepts an `` as its first argument. This is a case-sensitive {{cssxref("<custom-ident>")}} equal to the [name of the environment variable](/en-US/docs/Web/CSS/CSS_environment_variables/Using_environment_variables#browser-defined_environment_variables) to be substituted, but it can also include additional space-separated values if required. For example, `env(viewport-segment-width 0 0)` would return the width of the top or left segment in the case of a device with multiple viewport segments. -The `env()` function inserts the value of a user-agent defined environment variable into your CSS, in a similar fashion to the {{cssxref("var", "var()")}} function and [custom properties](/en-US/docs/Web/CSS/--*). The difference is that, as well as being user-agent defined rather than author-defined, environment variables are globally scoped to a document, whereas custom properties are scoped to the element(s) on which they are declared. +The second argument, if provided, is the fallback value, which is used if the environment variable referenced in the first argument is not supported or doesn't exist. The fallback can be another environment variable, even with its own fallback. -In addition, unlike custom properties, which cannot be used outside of declarations, the `env()` function can be used in place of any part of a property value, or any part of a descriptor (e.g., in [Media query rules](/en-US/docs/Web/CSS/@media)). As the spec evolves, it may also be usable in other places such as selectors. +The syntax of the fallback is similar to the fallback syntax of the {{cssxref("var()")}} function used to insert [CSS custom properties](/en-US/docs/Web/CSS/--*) in that it allows for multiple commas. Anything between the first comma and the end of the function is considered the fallback value. However, if the `env()` function is used within a property value or descriptor that doesn't include commas, a fallback value that includes commas will not be valid. -Originally provided by the iOS browser to allow developers to place their content in a safe area of the viewport, the `safe-area-inset-*` values defined in the specification can be used to help ensure content is visible even to viewers using non‑rectangular displays. +A property or descriptor containing a syntactically valid `env()` function is assumed to be valid at parse time, when the browser first reads and interprets the downloaded CSS text. It is only syntax-checked at compute time, after each `env()` function has been substituted with its browser-provided value (or the fallback value if the environment variable passed as the first parameter is not a recognized environment variable name). If the value is invalid and no fallback is provided, the property or descriptor containing the `env()` function is [invalid at computed-value time](/en-US/docs/Web/CSS/CSS_syntax/Error_handling#invalid_custom_properties). -For example, a common issue solved by `env()` is that of device notifications covering up some of the app user interface. By positioning fixed elements using `env()` you can ensure that they display in a safe area of the viewport. +When an `env()` substitution is invalid, and an invalid fallback is included, or the fallback is omitted, the declaration is not ignored. Instead, the [initial](/en-US/docs/Web/CSS/CSS_cascade/Value_processing#initial_value) or [inherited](/en-US/docs/Web/CSS/CSS_cascade/Inheritance) value of the property is used. The property is set to a new value, but it may not be the expected one. -Another use case for `env()` variables is for desktop [Progressive web apps](/en-US/docs/Web/Progressive_web_apps) (PWAs) that use the Window Controls Overlay feature to take advantage of the full application window surface area. Using the `titlebar-area-*` values, developers can position elements where the title bar would have been and ensure that content stays clear of the window control buttons. +### Use cases -## Formal syntax +Originally provided by the iOS browser to allow developers to place their content in a safe area of the viewport, and not be obscured by device notches or rounded corners, the `safe-area-inset-*` values can be used to help ensure content is visible to viewers. This feature was later expanded beyond its initial purpose to enable use cases such as [stopping device notifications from covering up some of the app user interface](#using_env_to_ensure_buttons_are_not_obscured_by_device_ui). -{{CSSSyntax}} +Another use case for `env()` variables is for desktop [Progressive web apps](/en-US/docs/Web/Progressive_web_apps) (PWAs) that use the [Window Controls Overlay](/en-US/docs/Web/API/Window_Controls_Overlay_API) feature to take advantage of the full application window surface area. Using the [`titlebar-area-*` values](#titlebar-area-x) values, developers can position elements where the title bar would have been and [ensure content is not obscured by window control buttons](#using_env_to_ensure_content_is_not_obscured_by_window_control_buttons_in_desktop_pwas). -## Usage +The `viewport-segment-*` variable names can be used to set your containers to fit neatly into the available segments of a multi-viewport-segment device such as a hinged or foldable device. The integers following the `viewport-segment-*` name indicate which segment of the multiple segments the environment variable is referencing. -To tell the browser to use the whole available space on the screen, and so enabling us to use the `env()` variables, we need to add a new viewport meta value: +### Names followed by integers -```html - -``` +When the environment variable is array-like, meaning the name may reference more than once value, such as is the case with devices with multiple viewport segments, the `` parameter includes both the name of the variable and the indices of the specific instance of the variable the function is referencing. For example, in the case of the `viewport-segment-*` variables, the variable names are passed to the `env()` function along with two integers indicating the indices of the segment to return the value for. These values are both integers of `0` or greater. The first integer represents the horizontal index of the segment, with `0` being the left-most segment, and the second value represents the vertical index of the segment, with `0` representing the bottom-most segment: + +![Two device segment layouts; in a horizontal layout, 0 0 is the first segment and 1 0 is the second segment. In a vertical layout, the indices are 0 0 and 0 1](env-var-indices.png) + +- In a horizontal side-by-side layout, the left segment is represented by `0 0`, and the right segment is represented by `1 0`. +- In a vertical top-to-bottom layout, the top segment is represented by `0 0`, and the bottom segment is represented by `0 1`. +- In devices with more than two segments, the numbers may be greater. For example, a device with three horizontal segments may have the center segment represented by `1 0`, and the right-hand segment represented by `2 0`. -You can then use `env()` in your CSS: +For example, the following returns the width of the right-hand segment on a two-segment foldable device where the segments are oriented horizontally: ```css -body { - padding: env(safe-area-inset-top, 20px) env(safe-area-inset-right, 20px) - env(safe-area-inset-bottom, 20px) env(safe-area-inset-left, 20px); -} +env(viewport-segment-width 1 0) ``` +See the [Viewport segment API demo](https://mdn.github.io/dom-examples/viewport-segment-api/) for a full working demo ([source code](https://github.com/mdn/dom-examples/tree/main/viewport-segment-api)). Also check out [Using the Viewport Segments API](/en-US/docs/Web/API/Viewport_segments_API/Using) for a full demo explanation. + +## Formal syntax + +{{CSSSyntax}} + ## Examples ### Using env() to ensure buttons are not obscured by device UI -In the following example `env()` is used to ensure that fixed app toolbar buttons are not obscured by device notifications appearing at the bottom of the screen. On the desktop `safe-area-inset-bottom` is `0`. However, in devices that display notifications at the bottom of the screen, such as iOS, it contains a value that leaves space for the notification to display. This can then be used in the value for {{cssxref("padding-bottom")}} to create a gap that appears natural on that device. +In the following example, `env()` is used to ensure that fixed app toolbar buttons are not obscured by device notifications appearing at the bottom of the screen. On the desktop `safe-area-inset-bottom` is `0`. However, in devices that display notifications at the bottom of the screen, such as iOS, it contains a value that leaves space for the notification to display. This can then be used in the value for {{cssxref("padding-bottom")}} to create a gap that appears natural on that device. + +#### HTML + +We have a {{htmlelement("main")}} section containing a fake application and a {{htmlelement("footer")}} containing two {{htmlelement("button")}} elements: ```html
Main content of app here
@@ -93,6 +104,10 @@ In the following example `env()` is used to ensure that fixed app toolbar button ``` +#### CSS + +Using [CSS flexible box layout](/en-US/docs/Web/CSS/CSS_flexible_box_layout), we create a footer that is only as tall as it needs to be, while the main section containing the application fills up the rest of the viewport: + ```css body { display: flex; @@ -113,11 +128,6 @@ footer { gap: 1em; justify-content: space-evenly; background: black; - padding: 1em 1em calc(1em + env(safe-area-inset-bottom)); - /* adds the safe-area-inset-bottom value to the initial 1em of padding. - a larger black area will display for a device that has a positive value for this variable. */ - position: sticky; - bottom: 0; } button { @@ -131,11 +141,28 @@ button { } ``` +We set [`position: sticky`](/en-US/docs/Web/CSS/position#sticky) to stick the footer to the bottom of the viewport. We then use the {{cssxref("padding")}} shorthand to add padding to the footer. We include the value of the `safe-area-inset-bottom` environment value to an initial `1em` of bottom padding. A larger black area will display on devices that have a positive value for this variable, ensuring the buttons in the footer are never obscured. + +```css +footer { + position: sticky; + bottom: 0; + + padding: 1em 1em calc(1em + env(safe-area-inset-bottom)); +} +``` + +#### Results + {{EmbedLiveSample("Using_env_to_ensure_buttons_are_not_obscured_by_device_UI", "200px", "500px")}} -### Using the fallback value +### Using a fallback value + +This example makes use of the optional second parameter of `env()`, which provides a fallback value in case the environment variable is not available. -The below example makes use of the optional second parameter of `env()`, which allows you to provide a fallback value in case the environment variable is not available. +#### HTML + +We include a paragraph of text: ```html

@@ -147,6 +174,10 @@ The below example makes use of the optional second parameter of `env()`, which a

``` +#### CSS + +We set a {{cssxref("width")}} of `300px` and a {{cssxref("border")}}. We then add {{cssxref("padding")}}, using the `env()` function with a fallback for the size of the padding on each side. We intentionally set an invalid value for the left padding (remember, environment variable names are case-sensitive), to demonstrate the use of the fallback value. + ```css p { width: 300px; @@ -156,32 +187,13 @@ p { } ``` -{{EmbedLiveSample("Using_the_fallback_value", "350px", "250px")}} - -### Example values - -```css -/* zero for all rectangular user agents */ -padding: env(safe-area-inset-bottom, 50px); +#### Results -/* 50px because UA properties are case sensitive */ -padding: env(Safe-area-inset-bottom, 50px); - -/* as if padding: '50px 20px' were set because x is not a valid environment variable */ -padding: env(x, 50px 20px); - -/* ignored because '50px, 20px' is not a valid padding value and x is not a valid environment variable */ -padding: env(x, 50px, 20px); -``` - -The syntax of the fallback, like that of custom properties, allows commas. But, if the property value doesn't support commas, the value is not valid. - -> [!NOTE] -> User agent properties are not reset by the [all](/en-US/docs/Web/CSS/all) property. +{{EmbedLiveSample("Using_the_fallback_value", "350px", "250px")}} ### Using env() to ensure content is not obscured by window control buttons in desktop PWAs -In the following example `env()` ensures that content displayed in a desktop Progressive Web App that uses the [Window Controls Overlay API](/en-US/docs/Web/API/Window_Controls_Overlay_API) is not obscured by the operating system's window control buttons. The `titlebar-area-*` values define a rectangle where the title bar would normally have been displayed. On devices that do not support the Window Controls Overlay feature, such as mobile devices, the fallback values are used. +In the following example, `env()` ensures that content displayed in a desktop Progressive Web App that uses the [Window Controls Overlay API](/en-US/docs/Web/API/Window_Controls_Overlay_API) is not obscured by the operating system's window control buttons. The `titlebar-area-*` values define a rectangle where the title bar would normally have been displayed. On devices that do not support the Window Controls Overlay feature, such as mobile devices, the fallback values are used. Here is what a PWA installed on a desktop device normally looks like: @@ -213,6 +225,10 @@ main { > [!NOTE] > Using `position:fixed` makes sure the header does not scroll with the rest of the content, and instead stays aligned with the window control buttons, even on device/browsers that support elastic overscroll (also known as rubber banding). +### Viewport segments + +The [Viewport segment API demo](https://mdn.github.io/dom-examples/viewport-segment-api/) and [Using the Viewport Segments API](/en-US/docs/Web/API/Viewport_segments_API/Using) guide provides a demonstration and explanation of using the `env()` function with the `viewport-segments-*` environment variables. + ## Specifications {{Specifications}} @@ -229,6 +245,7 @@ main { - [CSS custom properties for cascading variables](/en-US/docs/Web/CSS/CSS_cascading_variables) module - [Custom properties (`--*`): CSS variables](/en-US/docs/Web/CSS/--*) - [Using CSS custom properties (variables)](/en-US/docs/Web/CSS/CSS_cascading_variables/Using_CSS_custom_properties) +- [Viewport Segments API](/en-US/docs/Web/API/Viewport_segments_API) - [Customize the window controls overlay of your PWA's title bar](https://web.dev/articles/window-controls-overlay) - [Display content in the title bar](https://learn.microsoft.com/en-us/microsoft-edge/progressive-web-apps/how-to/window-controls-overlay) - [Breaking Out of the Box](https://alistapart.com/article/breaking-out-of-the-box/) diff --git a/files/jsondata/GroupData.json b/files/jsondata/GroupData.json index 0040b7b4ae576f8..5462bd5b2394dfd 100644 --- a/files/jsondata/GroupData.json +++ b/files/jsondata/GroupData.json @@ -1857,6 +1857,14 @@ "properties": [], "events": [] }, + "Viewport Segments API": { + "overview": ["Viewport Segments API"], + "guides": ["/docs/Web/API/Viewport_segments_API/Using"], + "interfaces": ["Viewport"], + "methods": ["Window.viewport"], + "properties": [], + "events": [] + }, "View Transition API": { "overview": ["View Transition API"], "guides": ["/docs/Web/API/View_Transition_API/Using"],