作者:CHRIS CASTLE
原文: https://blogs.windows.com/msedgedev
译者:杜尼卜微信搜索【前端全栈开发者】关注这个脱发、摆摊、卖货、持续学习的程序员的公众号,第一时间阅读最新文章,会优先两天发表新文章。关注即可大礼包,送某网精品视频课程网盘资料,准能为你节省不少钱!
浏览器是所有设备上使用最广泛的应用之一,如今,它运行在全新的硬件类别上:双屏和可折叠设备。
随着各种新的双屏和可折叠设备进入市场,包括MicrosofteSurface Duo,现在再没有比现在更好的时间来考虑你的网站如何采用这些外形。
今天,我们很高兴地宣布推出两项新的实验性功能,这两项功能将帮助Web开发人员有效地在跨越多个显示区域的浏览器窗口中布局内容,并创建响应式网站,以自然地适应这一类新设备。
- CSSscreen-spanning media feature和一组环境变量来描述折叠的几何形状。
- JavaScriptwindow segments enumeration API,在处理Canvas2d和WebGL等非DOM目标时很有用。
可折叠设备类
广义上讲,可折叠设备有两种变体:双屏设备和利用柔性显示技术的单屏设备。两者有很多共同点:它们是便携式的多姿势设备,允许用户旋转,翻转和折叠。
按照这种尺寸,应用程序可以位于一侧,也可以跨两个显示区域。响应这种跨越状态的网站与逻辑上划分呈现内容的语义和意图集成在一起。
这类设备所实现的广阔的屏幕空间和独特的姿态,让Web开发者可以在一个可以装进口袋或钱包的设备中开启前所未有的网络体验。
从传统的连续屏幕过渡到双屏和可折叠屏
虽然现有的网站会继续使用开箱即用的方式,但让网站意识到设备的可折叠性,可以大大提升用户体验。
为了更好地说明这个机会,并展示新创建的浏览器特性是如何工作的,我们将带你增强一个电子邮件客户端布局示例。
并排显示收件箱的列表视图和电子邮件的内容是一种常见的模式,自然适合较大的查看区域。当浏览器窗口跨越双屏设备上的两个显示区域时,总的视口宽度很可能与传统的水平平板电脑设备相当。
未经修改,电子邮件客户端将继续像往常一样工作。然而,如果我们能够将收件箱和邮件栏与折页对齐,将每个栏目都保持在一个显示区域的边界内,那么体验将得到极大的改善。这样,内容区域都不会被设备铰链切割或遮盖,也不会在柔性显示器的折叠区域上呈现。
为了实现理想的布局,我们引入了一个新的 screen-spanning
媒体功能和一组预先定义的环境变量,允许Web开发人员将可折叠设备作为另一个响应式Web设计目标。开发人员现在可以创建适用于每种设备类别的布局,而无需严格依赖特定的硬件参数。这种灵活性提高了可扩展性,因为它不需要为每个新设备类型重复工作。
检测显示区域
CSS screen-spanning
媒体功能将帮助Web开发人员测试根视口是否被跨越到多个相邻的显示区域,并提供关于这些相邻显示区域的配置细节(如堆叠或并排)。
screen-spanning
媒体功能被指定为一个值,该值描述设备具有的折叠(或铰链)数量及其姿势。如果该设备不是可折叠设备,则该值为none。如果它是可折叠的,则可以具有以下两个值之一:
Single-fold-vertical
:匹配具有单个折叠(两个显示区域)且折叠姿势为垂直的设备。Single-fold-horizontal
:匹配具有单个折叠(两个显示区域)且折叠姿势为水平的设备。
计算显示区域的几何形状
假设当处于 screen-spanning
状态时,折叠总是要把视口正好分成两半,这是不安全的。此外,某些窗口管理器可能会选择隐藏首屏后的Web内容。为了帮助Web开发人员计算每个显示区域的大小,并确保他们知道他们的内容(如果有的话)需要填充多少以避免遮罩,我们正在添加四个预定义的CSS环境变量。
env(fold-top)
env(fold-left)
env(fold-width)
env(fold-height)
这些变量的值是以CSS像素表示的,并且是相对于布局视口而言的(即在客户端坐标中,如CSSOM视图所定义)。当对不处于跨越状态的内容进行评估时,这些值将被视为不存在,并且浏览器将使用传递给env()函数的回退值。
增强我们的电子邮件示例应用程序,以实现双屏和可折叠的体验
让我们将CSS的 screen-spanning
媒体功能和折叠几何环境变量付诸实践,增强我们电子邮件客户端的读者视图。
@media screen and (min-width: 799px) {
/* 特定于平板电脑屏幕的规则 */
}
@media screen and (min-width: 799px) and (screen-spanning: single-fold-vertical) {
/* 主要是一个元素,其中包含上图中突出显示的3个flex项目 */
main {
display: flex;
flex-direction: row;
}
.navigation {
/*
** flex方向是行,因此flex-basis的行为类似于此flex项的宽度
**根据设计,可折叠/双屏上的所需宽度为60px
*/
flex-basis: 60px;
flex-grow: 0;
flex-shrink: 0;
}
.inbox {
/*
** 收件箱宽度会占用第一个显示区域的整个宽度,例如
** 收件箱宽度=显示区域1宽度-60像素(导航列宽度)
*/
flex-basis: calc( env(fold-left) - 60px );
/*
** 有些设备具有遮罩,因此我们需要在此列之后添加边距或间隙
** env(fold-width) = surface Duo上的28个CSS像素。
** env(fold-width) = 0不屏蔽内容的设备上的CSS像素。
*/
margin-inline-end: env(fold-width);
flex-grow: 0;
flex-shrink: 0;
}
.email-content {
/*
** the email content column should "grow" to fill the rest of the space
** but to demonstrate how to calculate the width of the 2nd display region
** we will manually set the width
*/
flex-basis: calc( 100vw - (env(fold-left) + env(fold-width)) );
flex-grow: 0;
flex-shrink: 0;
}
}
在JavaScript中枚举窗口段
当使用非DOM目标(如Canvas2d或WebGL)时,你可以使用新的 Window Segments Enumeration API
获得每个显示区域的几何体。
getWindowSegments()
是Window对象上的一个方法,它返回一个由1个或多个DOMRects组成的数组,这些DOMRects代表每个显示区域的几何形状和位置。
返回的数组是该方法被调用时显示区域状态的不可改变的快照。如果用户从跨接状态过渡到非跨接状态,或者旋转设备,则之前检索到的窗口段将无效。
const segments = window.getWindowSegments();
// case 1: desktops, traditional touch screen devices, foldable device not spanned
console.log(segments.length) // 1
// case 2: dual-screen and foldable
console.log(segments.length) // 2
页面应该监听窗口调整大小(resize
)事件或方向改变(orientationchange
)事件,以检测浏览器是否被调整大小,或设备是否被旋转,并检索更新的显示区域。
let segments = window.getWindowSegments();
// state 1: browser is spanned across 2 displays and fold is vertical.
console.log(segments.length); // 2
// state 2: user decided to rotate the device, browser is still spanned but fold is now *horizontal*
// on window resize, both resize and orientationchange events fire
// resize events will also fire when user go in or out of spanned state.
window.addEventListener('resize', () => {
// segments we initially retrieved are no longer
// update with latest information representing segments the 2 when the fold is horizontal
segments = window.getWindowSegments();
});
没有明确的方法来了解折叠姿势是垂直还是水平,因为可以从返回的DOMRects中轻松计算出此信息:
function isSingleFoldHorizontal() {
const segments = window.getWindowSegments();
// single fold means the device has 1 fold and 2 display regions
if( segments.length !== 2 ) {
return false;
}
// horizontal fold means 1st segment top is smaller than 2nd segment top
if( segments[0].top < segments[1].top ) {
return true;
}
// if we reach this point, the fold is vertical
return false;
}
同样适用于折叠宽度,Web开发人员可以使用 getWindowSegments()
提供的信息来了解窗口管理器是否掩盖了呈现在折叠后面的内容,以及折叠宽度是否大于零像素。
function foldWidth() {
const segments = window.getWindowSegments();
// if there's 1 segment, fold mask is not applicable, return 0
// if there's more than 2 segments, we don't deal with this kind of device, yet, return 0
if( segments.length !== 2 ) {
return 0;
}
// fold is vertical
// device looks like this: [][]
if( segments[0].top === segments[1].top ) {
return segments[1].left - segments[0].right;
}
// if we reach this point, the fold is horizontal
return segments[1].top - segments[0].bottom;
}
面向未来
作为开发者,我们在为今天创造的时候,往往会对未来进行规划,所以需要进行最低限度的重构,以解锁未来可能出现的场景。
与CSS不同,JavaScript有数组、循环和条件的概念,这使得窗口段枚举API和有N个显示区域的设备之间的映射更加直接。对于上图所示的假想设备,当浏览器横跨3个显示区域时,调用 getWindowSegments()
方法将返回一个由3个DOMRects组成的数组,使用简单的语言基元,如循环或内置的数组方法,你可以了解更多关于显示区域的配置情况(例如屏幕都是相同的宽度?等)
在CSS中,目前的计划是简单地在代表新的屏幕拓扑结构的 screen-spanning
媒体功能中添加新的值。
立即开始增强你的网站的可折叠体验
CSS screen-spanning 媒体功能和 Window Segment Enumeration API是可以在实验性标志后面使用的,你可以在edge://flags/#enable-experimental-web-platform-features处启用它们。
从Microsoft Edge 86开始,Web开发者可以使用Microsoft Edge DevTools在Windows和Mac桌面平台上模拟双屏&可折叠设备。另外,你也可以下载并安装新的Surface Duo模拟器预览版(2020.806.1或更新版本),在启用实验性平台功能标志后,使用内置的Edge浏览器进行测试和调试。
JavaScript Window Segments Enumeration API和 CSS screen-spanning媒体功能均以 Origin Trials 的形式提供,你可以获得代币并在生产中安全地试用这些新基元,以换取我们对 API 的反馈。
前方的路
这些API在Chromium项目、Google、Intel、W3C的CSSWG、第二屏WG等多方合作下,经过多次迭代和改进后,今天就可以供你实验了。
我们将桌面平台的CSS和JavaScript基元都贡献给了Chromium开源项目,现在DevTools的可折叠和双屏设备仿真不仅可以在Edge中使用,还可以在Chrome中使用,很快就可以在其他基于Chromium的浏览器中使用。目前,我们正在努力提升Android的实现,使所有基于Chromium的浏览器在Android操作系统上都能支持Web开发人员为这个灵活的设备类别提供令人兴奋的新体验。
如果你对任何一个API有反馈,请在GitHub上开一个问题让我们知道,或者你也可以在Twitter上联系我们(@_zouhir或@MSEdgeDev)。