Viewport Object in the Data-binding Context
The data-binding context for an Alexa Presentation Language (APL) document includes a viewport
property that describes the operating characteristics of the display device.
viewport
property is available to your APL document as part of the data-binding context. This is separate from the viewport information included in requests sent to your skill, which you can access in your skill code.Viewport object example
For example, the viewport object on the original Echo Show reports the following properties:
{
"viewport": {
"width": 1024,
"height": 600,
"pixelWidth": 1024,
"pixelHeight": 600,
"shape": "rectangle",
"dpi": 160,
"theme": "dark",
"mode": "hub",
"autoHeight": false,
"autoWidth": false,
"minHeight": 600,
"minWidth": 1024,
"maxHeight": 600,
"maxWidth": 1024
}
}
Your document can use conditional logic to provide different experiences for different viewports.
Properties
The viewport
object has the properties shown in the following table.
Property | Type | Description |
---|---|---|
|
Boolean |
When |
|
Boolean |
When |
|
Integer |
The pixel density of the viewport. |
|
Positive Dimension |
Default height in display-independent pixels (dp). |
|
Positive Dimension |
Maximum height in display-independent pixels (dp). |
|
Positive Dimension |
Maximum width in display-independent pixels (dp). |
|
Positive Dimension |
Minimum height in display-independent pixels (dp). |
|
Positive Dimension |
Minimum width in display-independent pixels (dp). |
|
Mode |
The operating mode. |
|
Integer |
Default height in pixels. |
|
Integer |
Default width in pixels. |
|
Possible values: |
Shape of the viewport. |
|
String |
The preferred color scheme. |
|
Positive Dimension |
Default width in dp. |
autoHeight
When true
the APL document can adjust its height within the range minHeight
and maxHeight
. When false
, the viewport is always exactly height
units tall.
The autoHeight
property is a convenience property for quickly establishing if the viewport might change in height. This property is equivalent to ${viewport.height != viewport.maxHeight || viewport.height != viewport.minHeight}
.
autoWidth
When true
the APL document can adjust its width within the range minWidth
and maxWidth
. When false
, the viewport is always exactly width
units tall.
The autoWidth
property is a convenience property for quickly establishing if the viewport might change in width. This property is equivalent to ${viewport.width != viewport.maxWidth || viewport.width != viewport.minWidth}
.
dpi
The display-independent pixel (dp) measurement of a screen is an artificial value that represents the visual size of the screen assuming that the screen is held at a mobile-phone viewing distance and has a pixel density of approximately 160 pixels per inch (the original iPhone screen was 163 pixels per inch). Two screens viewed at the same distance with the same physical size have approximately the same dp dimensions regardless of the actual pixel density of the screen.
The dots-per-inch (dpi) of a viewport is an artificial value that reflects the visual size of a point or pixel relative to the observer, and it doesn't match the actual pixels-per-inch size of the screen. The formula for dpi is:
dpi = 160 * (pixelSize / dpSize)
The following DPI values are supported: 120, 160, 213, 240, 320, 480, 640.
In practice the manufacturer selects the dpi size of the screen based on physical dimensions and expected viewing distance, and then calculates the dp size based on that dpi. For example, manufacturers recommend a 1080p television watching distance of approximately twice the diagonal measurement of the television screen, regardless of the actual screen size. Because the apparent visual size of the TV to the viewer is constant, all 1080p televisions have dpi=320, with pixelHeight
of 1080 and height
of 540.
height
The viewport height
property is the suggested display-independent pixel height of the viewport. When autoHeight
is false
, this height is strictly enforced. The viewport occupies exactly that height on the screen. When autoHeight
is true
, this height is a recommended default height, but the actual height might vary between minHeight
and maxHeight
. The APL document displayed within the viewport clips to the bounds of the viewport.
For more about how the size properties work together, see About viewport size.
maxHeight
The viewport maxHeight
property is the maximum allowed display-independent pixel measurement of the height of the viewport. When autoHeight
is false
, this is the same as the viewport height
.
For more about how the size properties work together, see About viewport size.
maxWidth
The viewport maxWidth
property is the maximum allowed display-independent pixel measurement of the width of the viewport. When autoWidth
is false
, this value is the same as the viewport width
.
For more about how the size properties work together, see About viewport size.
minHeight
The viewport minHeight
property is the minimum allowed display-independent pixel measurement of the height of the viewport. When autoHeight
is false
, this value is the same as the viewport height
.
For more about how the size properties work together, see About viewport size.
minWidth
The viewport minWidth
property is the minimum allowed display-independent pixel measurement of the width of the viewport. When autoWidth
is false
, this value is the same as the viewport width
.
For more about how the size properties work together, see About viewport size.
mode
The mode
property describes the expected use of the device. The mode property returns one of the following values:
Value | Description | Common input types | Examples |
---|---|---|---|
auto |
Used by the driver in a vehicle. | Touch | Automobile dashboard, built-in aircraft display |
hub |
A table-top or fixed-position devices. | Touch (when close) | Amazon Echo Show, counter-top appliance |
mobile |
A handheld device carried by the user. | Touch | Mobile phone, tablet computer |
pc |
A desktop or laptop computer. | Keyboard, mouse, track pad | Desktop, laptop computer |
tv |
A television or projected display. | Remote control | Television, billboard |
The input types listed in the table are representative and not guaranteed to exist for a particular device mode.
A single device can report different modes at different times. For example, a tablet computer reports as a mobile
device at most times, but might report as a hub
device when docked in a docking station. Proximate devices often report as different modes. For example, in an automobile the device built into the dashboard reports as auto
, the device installed in the ceiling behind the driver for passengers reports as tv
, and the mobile phone held by a passenger reports as mobile
.
The list of modes might change. When you use mode
in conditional logic, assume that the property could return an unrecognized value. Always provide a default definition for any properties or components that depend upon mode.
pixelHeight
The pixelHeight
property is the pixel measurement of the height
of the viewport. This is equal to ${viewport.height * viewport.dpi / 160}
. The pixelHeight
property is provided as a convenience to use when selecting suitable bitmap images to display.
pixelWidth
The pixelWidth
property is the pixel measurement of the width
of the viewport. This is equal to ${viewport.width * viewport.dpi / 160}
. The pixelWidth
property is provided as a convenience to use when selecting suitable bitmap images to display.
shape
The shape
of the screen returns either round
or rectangle
.
theme
The theme reflects the basic color scheme in use on the device. The theme is a string value. You can set the theme in the APL document in the theme
property. When not set in the document, the device sets it to either "light" or "dark":
light
: Dark text drawn on a light backgrounddark
: Light text drawn on a dark background
You can use the theme when you define styles in your document or package. The following example shows two styles that adjust based on the theme
.
{
"styles": {
"styledText": {
"values": [
{
"color": "${viewport.theme == 'dark' ? 'white' : 'black'}"
}
]
},
"styledFrame": {
"values": [
{
"backgroundColor": "${viewport.theme == 'dark' ? '#096484' : '#74B6CF'}"
}
]
}
}
}
In your document, you can choose to ignore the theme entirely or override the device-supplied value with a custom theme. For example, the following document creates a custom "fancy" theme. Change the value of the theme
property and note that the text changes color.
This approach provides flexibility when the styles and resources are in a separate APL package. You can switch between various custom appearances with a single theme choice.
About viewport size
The viewport
object has height (autoHeight
, height
, minHeight
, and maxHeight
) and width (autoWidth
, width
, minWidth
, and maxWidth
) properties that define the drawing size of the APL document.
Usually, the viewport has a fixed size. For example, an APL document might display as a full screen on an Alexa device, where the size of the viewport is fixed to the size of the screen.
The following example shows the viewport
object for a full screen display of an APL document on a 1280 by 1024 screen with a 320 dpi.
"viewport": {
"autoHeight": false, // The height is fixed
"autoWidth": false, // The width is fixed
"dpi": 320,
"height": 512, // 1024 pixels @ 320 dpi = 512 dp
"maxHeight": 512, // Same as height
"maxWidth": 640, // Same as width
"minHeight": 512, // Same as height
"minWidth": 640, // Same as width
"pixelHeight": 1024,
"pixelWidth": 1280,
"shape": "rectangle",
"width": 640 // 1280 pixels @ 320 dpi = 640
}
Sometimes, the size of the viewport might be flexible in height or width. For these viewports, the autoHeight
or autoWidth
properties report true
.
For example, consider a displayed APL document where the height is fixed to 400 dp, but the width of the document might vary between 200 dp and 600 dp. The viewport object reports the following.
"viewport": {
"autoHeight": false, // The height is fixed
"autoWidth": true, // The width can vary
"dpi": 320,
"height": 400, // The height is fixed to 400 dp
"maxHeight": 400, // Same as height
"maxWidth": 600, // The maximum width is 600 dp
"minHeight": 400, // Same as height
"minWidth": 200, // The minimum width is 200 dp
"pixelHeight": 800, // 400 dp @ 320 dpi = 800 pixels
"pixelWidth": 800, // 400 dp @ 320 dpi = 800 pixels (default width)
"shape": "rectangle",
"width": 400 // The default width is 400 dp
}
For details about how APL calculates the size of the top component for variable viewports, see Understanding viewport layout.
Components aren't required to match the viewport size
The size of the top component in the view hierarchy isn't required to match the size of the viewport. When the sizes don't match, clipping occurs or blank spaces display. The top-left corner of the component is attached to the top-left corner of the viewport. For example, assume a fixed viewport size of 640 dp by 512 dp with the following APL document.
"mainTemplate": {
"item": {
"type": "Frame",
"width": 2000,
"height": "50vh",
"backgroundColor": "green"
}
}
The top-level Frame
has a width of 2000 dp and a height of 256 dp, but it displays within the bounds of the 640x512 viewport. The device displays blank space below the document, filled in with the document background if set. The right side of the Frame
runs off the side of the screen and isn't visible.
Viewport height and width reflect the current screen orientation and dimensions
The viewport height and width reflect the current screen orientation and dimensions. A tablet computer with a 1024 by 768 pixel screen showing a fulls screen APL document reports a viewport pixelWidth
of 768 in portrait mode and 1024 in landscape mode. The fact that the screen is rotated isn't reported to the APL document.
Understand viewport layout
This section describes how the size of the viewport and the size of the top-level component in an APL document interact. Note the following definitions:
- Viewport – Defined by the APL runtime. The viewport represents the space that the APL document renders within.
- Top-level component size – Defined by the APL document. All other components in the document are clipped to the bounds of the top-level component. The top-level component is often a
Container
, but can be any component.
The width and height calculations use the same algorithm. The following sections describe how APL calculates the output widths of the viewport and top-level component. The output heights of the viewport and top-level component are calculated in the same way.
The algorithms described here are a simplified version of the actual Flexbox Box Layout Module and CSS Box Sizing Module logic. Refer to those documents for the complete details.
This section assumes that the viewport and component properties are well-ordered when defined. This means that they adhere to the following rule:
viewport.minWidth <= viewport.width <= viewport.maxWidth (if both defined)
component.minWidth <= component.width <= component.maxWidth (if both defined)
Refer to the CSS Box Sizing Module specification for a discussion of how these properties interact when they aren't well-ordered.
Fixed viewport
Most APL runtimes place documents in a fixed-size viewport. A fixed viewport has the same value for the viewport width
, minWidth
, and maxWidth
.
viewport.minWidth == viewport.width == viewport.maxWidth
viewport.autoWidth = false
The following rules use the top-level component properties for width
, minWidth
, and maxWidth
to determine the output width of the component.
When component width is an absolute dimension
When the component width
is an absolute dimension, the output width is the specified width
value clamped to the component maxWidth
and minWidth
properties. The size of the viewport isn't used in the computation. Examples of absolute dimensions include values such as 25px
, 10vw
, or 30
.
The following pseudo-code shows this calculation.
if TypeOf( component.width ) == AbsoluteDimension:
w = Clamp( component.width, component.minWidth, component.maxWidth )
component.output.width = w
Layout( component, width=w )
Component width is a relative dimension
When the component width
is a relative dimension, the output width is the product of the component width
and the viewport width
clamped to the component maxWidth
and minWidth
. Examples of relative dimensions include values such as 25%
and 50%
.
The following pseudo-code shows this calculation.
if TypeOf( component.width ) == RelativeDimension:
w = component.width * viewport.width
w = Clamp( w, component.minWidth, component.maxWidth )
component.output.width = w
Layout( component, width=w )
Component width is auto
If the component width
is auto
, the output width depends on whether the maxWidth
has a value. If maxWidth
has a value, the component tightly wraps its children and clamps to the component maxWidth
and minWidth
. If maxWidth
doesn't have a value, the component fills the viewport.
The following pseudo-code shows this calculation.
if TypeOf( component.width ) == AutoDimension:
if IsDefined( component.maxWidth ):
w = Layout( component, width=Undefined ).getWidth()
w = Clamp( w, component.minWidth, component.maxWidth )
else:
w = viewport.width
component.output.width = w
Layout( component, width=w )
In all three of the these scenarios, the top-level component output width can be smaller or larger than the viewport width
. APL positions the top-left corner of the component at the origin of the viewport (the top-left corner). When the component output width is larger than the viewport width
, the viewport clips the right side of the component. When the component output width is smaller, the document background
is visible on the right-hand side of the viewport.
Variable viewport
Some APL runtimes support variable-size viewports. A variable viewport expands or contracts to adjust to the size of the APL document in either width, height, or both. For example, a runtime displaying a horizontal list of APL documents might allow the individual documents to vary in width to allow some documents to take extra horizontal space. A variable viewport has different values for viewport width
, minWidth
, and maxWidth
.
viewport.minWidth <= viewport.width <= viewport.maxWidth
viewport.minWidth < viewport.maxWidth
viewport.autoWidth = true
The final viewport output width is in the range [minWidth, maxWidth]
.
The viewport width
is the default output width of the viewport. This value is used in two ways:
- When the component
width
is set to a relative dimension, the viewport output width is fixed to the viewportwidth
. Usually the componentwidth
is100%
, indicating that the component wants to be the default width of the viewport. - Resource calculations within an APL document normally use the viewport
width
when defining resources that depend on the size of the viewport. Resource values are calculated when the document is first loaded, which happens before the final viewport output width has been calculated. Therefore, the default width of the viewport is a convenient baseline to calculate with.
The top-level component width
minWidth
, and maxWidth
properties determine the top-level component output width
and the viewport output width
by the following rules:
The following rules use the top-level component properties for width
, minWidth
, and maxWidth
to determine the output width of the component.
Component width is an absolute dimension
When the component width
is an absolute dimension, the component output width is clamped to the component [minWidth, maxWidth]
range. The viewport output width is the component output width clamped to the viewport [minWidth, maxWidth]
range. Examples of absolute dimensions include values such as 25px
, 10vw
, or 30
.
The following pseudo-code shows this calculation.
if TypeOf(component.width) == AbsoluteDimension:
w = component.width
w = Clamp( w, component.minWidth, component.maxWidth )
component.output.width = w
viewport.output.width = Clamp( w, viewport.minWidth, viewport.maxWidth )
Layout( component, width=w )
For example:
Given viewport: { minWidth: 100, width: 200, maxWidth: 300 }
component: { minWidth: 0, width: 250, maxWidth: Undefined }
Then viewport.output.width = 250
component.output.width = 250
Component width is a relative dimension
When the component width
is a relative dimension, the component output width is the product of the component width
and the viewport width
, clamped to the component [minWidth, maxWidth]
range. The viewport output width is the viewport width
.
The following pseudo-code shows this calculation.
if TypeOf(component.width) == RelativeDimension:
w = component.width * viewport.width
w = Clamp( w, component.minWidth, component.maxWidth )
component.output.width = w
viewport.output.width = viewport.width
Layout( component, width=w )
For example:
Given viewport: { minWidth: 100, width: 200, maxWidth: 300 }
component: { minWidth: 0, width: "80%", maxWidth: 150 }
Then viewport.output.width = 200
component.output.width = 150
If you set the relative dimension smaller than 100%
, the background shows on the right-hand side of the viewport. If you set the relative dimension larger than 100%
, the right-hand side of the component is clipped.
If your goal is to stretch or shrink the viewport and the component by a percentage amount from the default viewport size, use an absolute dimension referencing the width of the viewport. For example, to make a component and viewport 25 percent larger than the default viewport width
, set the component width
to 125vw
. That value is an absolute dimension equal to 125 percent of the viewport width
and therefore follows the absolute dimension rules.
Component width is "auto"
If the component width
is auto
, the output width depends on whether the maxWidth
has a value. If maxWidth
has a value, the component tightly wraps its children and clamps to the component maxWidth
and minWidth
. If maxWidth
doesn't have a value, the component fills the viewport.
If the component width
is auto
, the layout engine calculates an intermediate viewport output width for the component by laying out the component's internal elements using their "natural" width. That intermediate viewport output width is then clamped to both the component [minWidth, maxWidth]
range and the viewport [minWidth, maxWidth]
range. The component output width is set to the clamped value and the component is laid out a second time.
The following pseudo-code shows this calculation.
if TypeOf(component.width) == AutoDimension:
w = Layout( component, width=Undefined ).getWidth()
w = Clamp( w, component.minWidth, component.maxWidth )
w = Clamp( w, viewport.minWidth, viewport.maxWidth )
viewport.output.width = w
Layout( component, width=w )
For example, assume that the top-level component is a Text
component with a long paragraph of text.
Given viewport: { minWidth: 100, width: 200, maxWidth: 300 }
component: { minWidth: 0, width: auto, maxWidth: Undefined }
total text width (single line) = 430
Then viewport.output.width = 300
component.output.width = 300
The auto
setting for the component width
property requires the layout algorithm to run twice. First, the component is laid out assuming its internal elements are their "natural" width. The natural width of a Text
component is the width of the text laid out in a single line (in this example, 430). This width is then clamped to the valid width range specified by the viewport (in this example, 300). Finally, the component is laid out again with its width fixed to this value. This second layout pass wraps the text to multiple lines.
Component width and height are both "auto"
If the viewport is variable in both width and height and the top-level component has auto
for both the width
and height
properties, APL uses the following algorithm.
if TypeOf(component.width) == AutoDimension AND TypeOf(component.height) == AutoDimension:
// Calculate the width of the viewport
w = Layout( component, width=Undefined, height=Undefined ).getWidth()
w = Clamp( w, component.minWidth, component.maxWidth )
w = Clamp( w, viewport.minWidth, viewport.maxWidth )
viewport.output.width = w
// Now calculate the height of the viewport
h = Layout( component, width=w, height=Undefined ).getHeight()
h = Clamp( h, component.minHeight, component.maxHeight )
h = Clamp( h, viewport.minHeight, viewport.maxHeight )
viewport.output.height = h
// Layout with the final width and height
Layout( component, width=w, height=h )
The first layout pass calculates the viewport output width. The second layout pass calculates the viewport output height. The final layout pass lays out the component hierarchy using the viewport output width and height.
Related topics
Last updated: Nov 28, 2023