可折叠Web的说法是可折叠设备带来的。可折叠设备形式多样,从笔记本电脑到手机,再到新奇的双屏幕混合设备。对于这类新发明并无一个全面的定义,但大多数均可以归为两类。“可折叠”是指屏幕能够折叠的设备(好比华为Mate X,三星Galaxy Z Flip);而“双屏”设备的屏幕是分开的,但也能够以独特的方式一块儿工做,以灵活的形式提供生产力(好比,微软的Surface Neo和Surface Duo)。当涉及到Web设计时,这两种类型可能会遵循相似的规则。若是这项技术能大获成功,那么Web设计将面临十年来最大的变革。这对于咱们Web开发者而言,也将会开启新的旅程。css
听起来就很使人兴奋,但这到底意味着什么呢?可折叠Web将带来新的挑战,新的机遇,并且极可能还会带来新的概念。互联网可能也会经历自智能手机以来最大的变革。你可能会认为这是一种炒做,但事实上这样的一天已经离咱们不是太远。记得在去年这个时候,有些移动品牌商,好比华为,三星都推出可折叠的硬件设备,而微软,苹果等公司在幕后的努力也不逊色。能够说可折叠Web即将到来。咱们真的应该去思考可折叠Web可能会给我带来什么变化?若是这一天真的到来,咱们的技术是否能支持该设备。简单地说,咱们开发的Web页面能不能在可折叠设备和双屏幕上完美的运行。html
可折叠设备采用的是一种柔性屏幕技术,该技术的研究始于20世纪70年代,但直到世纪之交才获得真正的发展。特别是在去年,获得了爆发式的发展——在市场上能看到一些可折叠设备终端。好比三星Galaxy Z Flip手机,模仿的是老式的翻盖手机:git
好比三星的Galaxy Fold手机,在折叠状态是一个小屏幕,展开状态是一个宽屏幕:github
好比华为Mate X,屏幕是包裹在手机外面的:web
还有不少像电子书同样,当设备彻底打开时,内部的两个显示屏会合二为一。一般在外面有一个独立的小屏幕,这样用户在使用的时候就不用打开它。npm
双屏幕设备是具备两个对称屏幕的便携式设备,以独特的方式一块儿工做,以灵活的形式提供生产力。好比像微软的Surface Neo和Surface Duo这样的双屏幕设备,人们能够比以往任什么时候间都更快地完成工做。若是你使用过Surface Neo这样的双屏幕设备,你能够在一个屏幕上作笔记,在传输过程当中在另外一个屏幕上查看完整的项目建议书:windows
尽管如今市场上有不一样的折叠屏,双屏幕设备,并且还会有更多的相似设备出现,但咱们相信为这些设备设计应用程序会有一个共同的方法。咱们但愿这将帮助你的应用程序能跑在更多的设备上,而不须要为不一样的设备作特殊的设计和处理。api
换句话说,在可折叠屏或双屏幕的设备上,用户能够作更多的事情,好比说让屏幕分屏,能够同时打开多个应用程序:数组
也能够打开同一个应用,在应用中分屏,打开不一样的页面,好比:浏览器
像上图这样,应用程序在两个屏幕上显示,就是所谓的跨屏布局。默认状况下,该应用程序将表现得好像它是在一个更大的屏幕上显示。你也能够改变你现有的应用程序布局来适应两个屏幕之间的缝隙,或者你能够更进一步,允分的利用双屏幕设备而专门建立不一样的布局控件。好比iPad版本的手淘,就能够分屏展现:
可折叠和双屏幕设备正在出现。这已经不是概念,也不是炒做。这更不是重点。重点是:
可折叠和双屏幕这项技术将如何影响Web开发人员、用户体验设计师以及其余以提供高质量浏览体验为业务的人。
首先可折叠和双屏幕会给视觉设计师在作设计的时候带来很大的变化。
整个可折叠的概念是基于你能够把你的手机变成平板电脑的想法。市场上大多数平板电脑的屏幕宽高比都是 4:3
,因此手机和平板电脑的混合也应该是4:3
。这使用折叠设备达到3:2
。而这些比率都不能保证16:9
或18:9
的真实视频体验。其中4:3
的宽高比更适合在各类文本和图形编辑器中执行任务和工做,好比iPad,但它须要更大的分辨率,这是可折叠设备没法作到的。这使得大多数可折叠手机处于一个模糊地带,给人用户的体验就会变得很糟糕,这也是由于在传统手机中是没法达到16:9
的比例。
为了让可折叠手机成为一种有用的媒体设备,它必须转换成16:9
或18:9
的设备,而后再折叠成8:9
或9:9
—— 基本上就是一个正方形。@Nathan Cunn经过计算得出结论,折叠手机的完美宽高比应该是其宽度的1.4
倍。
这也将会是iPhone折叠屏将会采用的一种宽高比例:
除此以外,无论是可折叠设备仍是双屏幕设备,最大的特征就是屏幕变大了,在展开的状态下和平板同样了。这样一来,可用的空间就变大了。
可折叠和多屏设备打破了移动设备(手机)可用空间小的束缚!
空间大了,能放置的内容就多了,若是设计仍是按着之前的思路,直接拉伸平满全屏,就过于浪费了。面对这样的场景,除了响应式Web设计能帮助咱们更好的利用可用空间以外,还能够参照淘宝设计提出的一个概念:
让你的内容像水同样的流动(“Content is like water”)
用一张图来描述:
有关于这方面更详细的介绍,能够关注淘宝设计微信公众号
你能够搜索“可折叠”关键词,能找到一些这方面的文章,好比:
对于双屏幕给设计带来的变化,或者说设计应该要注意的细节,能够阅读微软官方有关于双屏幕的介绍:《Introduction to dual-screen devices》。
另外,折叠屏幕还会带来一些其余的设计和体验变化。
随着状态的改变(这里的状态是折叠和展开状态,单屏和多屏状态),整个体验自己也随之改变。目前大多数用户都习惯用一只手操做移动设备(手机),而展开状态,就像iPad了,这个时候须要两只手来操做设备(或应用)。
手机操做 vs 平板操做
可折叠设备和多屏幕设备有着明显的区别。
可折叠设备在展开状态时,它的屏幕是连续性的,咱们在设计的体验应该无缝地转移到全屏上。
针对这样的情景,若是只是粗暴的放大到全屏,那么布局上不会有太多的变化,只不过对于Web中的部分对象会变得模糊,好比图像。固然,也能够考虑设计上作差别性的处理,好比说作分屏设计:
对于多屏幕设备,有可能屏幕不是连续性的,好比微软的Surface Neo和Surface Duo,屏幕之间就有一个间隙:
在设计和布局的时候,就须要避免Web对象处在两个屏幕的间隙之间,好比:
或者:
前面提到过,折叠屏和多屏幕最大的特征之一,就让咱们有更多的空间可利用。这样对于用户来讲,对于处理多任务更友好,能同时作更多的事情。所以,咱们应该始终考虑用户可能会同时运行多个App应用。好比说,一边查看日历,一边查看地图,一边看新闻:
除了同时打开多个App应用以外,还能够在同一个App中,分屏作不一样的事情,好比,一边看直播,一边逛淘宝:
折叠屏和多屏幕除了给设计师带来新的挑战以外,给Web开发者也带来相应的挑战。在去年华为Mate X出来的时候,有幸参与在Mate X作一些Web端的适配处理。主要处理H5的应用完美适配折叠屏设备。
因为相关H5业务采用的都是视窗单位vw
(我常称该方案为vw-layout
),能较好的让相应的H5业务适配折叠屏展开状态,但也存在一些相应的问题,最为突出的是图像变得模糊:
固然也尝试着采用响应式Web设计来作不一样的布局处理:
虽然该方式可让咱们的H5应用最大化的利用折叠屏可用空间,但也存在必定的缺陷。所以在《聊聊安卓折叠屏给交互设计和开发带来的变化》一文中提出相应的概念:
处理折叠屏时,咱们应该像一些带有刘海设备(好比iPhone X)同样,具备独特的检测特性来检测折叠设备或多屏幕设备
值得庆幸的是这一年来,在这方面有了明显的变化,尤为是微软公司的团队对可折叠技术的探究和讨论很是的积极。在今年2月份,三位微软开发人员@Bogdan Brinza、@Daniel Libby和@Zouhir Chahoud发表了一篇文章,解释如何使用JavaScript API和CSS 媒体查询来处理可折叠和多屏幕设备的布局。
该文档提出两个概念:用于双屏幕布局的CSS 和 窗口段枚举的JavaScript API。它的宗旨是做为讨论折叠屏和多屏幕在Web开发中技术标准。即:以可折叠和双屏幕设备为目标的Web开发人员可以在跨多个显示区域的窗口中有效的对Web应用进行布局。
从@Bogdan Brinza、@Daniel Libby和@Zouhir Chahoud三位开发者在Github上发表的文档《Web Platform Primitives for Enlightened Experiences on Foldable Devices》来看。处理可折叠和多屏幕设备的Web布局主要由两部分特性组成,其一是CSS的媒体查询特性,其二是JavaScript API。
接下来,咱们主要围绕着这两个部分来展开。
特别声明:用于双屏幕布局的CSS还处于W3C规范的草案当中,一切皆有可能会变。
@Brinza、@Libby和@Chahoud提出了一个CSS特性,即媒体特性,它能够肯定网站是否跨越两个相邻的显示区域,以及这两个相邻显示区域的配置。相应的还提出了另外一个特性,即环境变量(指的是用户代理定义的环境变量),它将帮助Web开发人员以CSS像素计算每一个屏幕区域的大小。
当浏览器窗口跨越设备折叠时,告诉Web开发者折叠方向和显示边界能够帮助他们开发出来具备较好体验的Web应用。这里快速概述可能会出现的模式。
将更大屏幕的UI模式带到更小的便携设备
因为屏幕尺寸的限制,传统的便携式触摸设备在很大程度上依赖于“叠加视图”,好比点击收件箱列表中的一封邮件,就会致使整个收件箱列表视图被选中的邮件内容视图所取代。这种行为一般会建立额外的操做步骤;而在更大屏幕的设备上将会有一个更天然的配置,邮件收件箱列表视图和邮件内容视图是并排的。
固然,这种从新创造的模式并非惟一的解决方案,只不过可折叠屏和多屏幕设备相对于传统的便携触摸式移动设备来讲多了一个显示器,至关于增长一个屏幕空间,这样一来能够为Web开发者和设计师提供独特的机会来创造新的体验。
轻松改进现有的Web应用和UI组件
Web开发人员可能不想为这类设备引入主要的UI更改,而只想简单地移动一些组件。在下面的示例中,对于模态对话框(Modal
)避免设备折叠更有意义(不管可折叠设备是无缝的仍是有间隙的),并容许Web开发人员逐步加强他们的站点,提供更好的体验。
也正由于这些缘由,提出了相应的CSS特性和设计原则。
spanning
提出一个新的媒体特性:spanning
,该特性可用于检测浏览器窗口是否跨越多个显示区域。
spanning
特性主要有三个值:
single-fold-vertical
:屏幕是水平的,布局视图跨越单个折叠(两个屏幕)而且折叠姿式是垂直时(分左右两边),这个值是匹配的single-fold-horizontal
:屏幕是垂直的,布局视图跨越单个折叠(两个屏幕)而且折叠姿式是水平时(分上下),这个值是匹配的none
:描述浏览器窗口不处于跨越模式时的状态这个有点相似于刘海设备同样,经过env()
函数来识别环境变量,即识别安全区域:
env(safe-area-inset-top)
:在Viewport顶部的安全区域内设置量(CSS像素)env(safe-area-inset-bottom)
:在Viewport底部的安全区域内设置量(CSS像素)env(safe-area-inset-left)
:在Viewport左边的安全区域内设置量(CSS像素)env(safe-area-inset-right)
:在Viewport右边的安全区域内设置量(CSS像素)这份建议预约义了几个可识别折叠或多屏设备的CSS环境变量:fold-top
、fold-left
、fold-width
和fold-height
。
Web开发人员能够利用这些变量来计算横屏和竖屏的每一个屏幕片断大小。
注意,这些CSS环境变量的值是CSS像素,而且是相对于布局视图的(即在客户端坐标中,由CSSOM视图定义)。当不处于跨越状态时,这些值将被视为不存在,则会取env()
函数的回退值。
来看一个简单的示例:一个地图应用程序,在一个屏幕上显示地图,在另外一个屏幕上显示搜索结果。以下图所示:
若是用CSS代码来实现的话,大体以下:
@media (spanning: single-fold-vertical) {
body {
flex-direction: row;
}
.map {
flex: 1 1 env(fold-left)
}
.locations-list {
flex: 1;
}
}
复制代码
spanning
的Polyfill到目前为止,新增的CSS媒体特性spanning
和相应的环境变量都还处于草案的讨论阶,但若是你要尝试着在折叠设备或多屏幕设备上使用该特性的话,可使用@darktears 提供的一个Polyfill。
这个Polyfill的使用很简单,你可使用NPM将这个Polyfill加载到你的项目中:
npm install --save spanning-css-polyfill
复制代码
安装完以后,经过<script>
将对应的spanning-css-polyfill.js
引入到项目中:
<script type="module" src="/path/to/modules/spanning-css-polyfill.js"></script>
复制代码
也可使用import
的方式引入:
import "/path/to/modules/spanning-css-polyfill/spanning-css-polyfill.js";
复制代码
这样你就能够在CSS中使用spanning
这个新媒体查询特性和CSS环境变量fold-top
、fold-left
、fold-width
和fold-height
。
固然,你还能够手动改变显示(display
)相关的配置。好比,经过导入FoldablesFeature
对象:
import { FoldablesFeature } from '/path/to/modules/spanning-css-polyfill/spanning-css-polyfill.js';
复制代码
能够经过FoldablesFeature
对象来更新像spanning
、foldSize
和browserShellSize
等值。你也能够订阅change
事件,以便spanning
媒体查询特性或环境变量发生变动时获得相应的通知。
import { FoldablesFeature } from '/path/to/modules/spanning-css-polyfill/spanning-css-polyfill.js';
const foldablesFeat = new FoldablesFeature;
// Add an event listener.
foldablesFeat.onchange = () => console.log("change");
// Add as many event listeners as you want.
foldablesFeat.addEventListener('change', () => console.log("change"));
// Change a single value; results in one update (one 'change' event firing).
foldablesFeat.foldSize = 20;
// Change multiple values by assignment; results in one update.
Object.assign(foldablesFeat, { foldSize: 50, spanning: "none"});
// Change multiple values in one scope; results in one update
(function() { foldablesFeat.foldSize = 100; foldablesFeat = "single-fold-horizontal" })();
复制代码
有关于spanning
更详细的使用,能够查看Github上的相关教程。
特别声明,枚举窗口片断的JavaScript API已移到W3C第二屏幕社区组。相关的解释、问题和评论,能够参阅GitHub的
webscreens/window-segments
仓库。
这里提出了一个窗口片断的新概念,它表示位于单独(相邻)显示上的窗口区域(及其尺寸)。窗口片断尺寸以CSS像素表示,并容许Web开发者经过JavaScript API对窗口片断进行枚举,在相应的窗口片断上放置独立内容。
这个建议主要针对响应式场景,在这种状况下,Web应用程序但愿利用跨越多个显示的优点,经过用户、窗口管理器将其置于该状态。它不适合将内容预先放置在各类可用显示的单独顶级浏览器上下文的状况(这属于Window Placement API和Presentation API)。请注意,使用枚举窗口片断的API和Web现有的特性,可使用JavaScript来编写交叉显示和窗口的矩形,同时考虑devicePixelRatio
来,计算横跨多个显示的窗口区域。不过,这个并不能正确的处理将来设备形式中存在的极端状况,所以,这个提议试图解决Web开发人员针对或考虑显示内容屏幕做为一个实际的起点。
简单地来讲,Web开发者可使用getWindowSegments()
来获取一个DOMRects
数组,而后根据每一个窗口片断返回的数据,开发人员可以推断出可用连接(Hinge)的数量以及其方向。
用户能够在任什么时候候将浏览器窗口脱离跨越模式,并将其放在某个屏幕上,反之亦然,在这种状况下,将触发窗口resize
事件,从而能够查询并得到可用屏幕段的数量。
好比咱们上面提到的示例:
若是使用JavaScript来解决的话,能够像下面这样:
const screenSegments = window.getWindowSegments();
if( screenSegments.length > 1 ) {
// 如今咱们知道这个设备是可折叠(可多屏幕)的
// 建议测试 screenSegments[0].width === screenSegments[1].width
// 能够更新CSS类,实现不一样的布局效果
document.body.classList.add('is-foldable');
document.querySelector('.map').classList.add('flex-one-half');
document.querySelector('.locations-list').classList.add('flex-one-half');
}
复制代码
咱们再来看另外一个示例,当窗口的resize
事件和spanning
状态发现变化时处理方案。
先看CSS的解决方案:
@media (spanning: none) and (max-width: 728px) {
body {
flex-direction: column;
}
.map {
flex: 0 0 300px;
}
.locations-list {
flex: 1;
}
}
复制代码
若是使用JavaScript能够这样:
window.onresize = function() {
const segments = window.getWindowSegments();
console.log(segments.length) // 1
if( screenSegments.length > 1 ) {
document.body.classList.add('is-foldable');
document.querySelector('.map').classList.add('flex-one-half');
document.querySelector('.locations-list').classList.add('flex-one-half');
}
}
复制代码
最后咱们来看实际案例。
你可能在手上没有折叠屏或多屏幕的设备,有可能没法看到实际效果。但可使用一款基于Web的模拟器,这款模拟器能够模拟微软 Surface Duo 和 Surface Neo两款分屏设备:
@kenchris 在GitHub上spanning-css-polyfill提供了几个Demo,咱们来看最简单的basic
中的index.html
。
HTMl部分很简单(这个Demo自己就很简单):
<div class="wrapper">
<div class="col1"></div>
<div class="col2"></div>
</div>
复制代码
在</body>
前加载了一个.js
文件,根据CSS Spanning Polyfill提供的一些方法,处理一些全局样式,甚至能够根据JavaScript的API来构建CSS方面的样式。
<script type="module" src="../../src/index.js"></script>
复制代码
接着看CSS部分。在CSS中使用媒体查询特性:
/* 普通设备下对应的CSS */
.wrapper {
display: flex;
height: 100%;
width: 100%;
}
.col1 {
flex: 0 0 200px;
background-color: lightgray;
transition: background-color .2s linear;
}
.col2 {
flex: 1;
background-color: papayawhip;
transition: background-color .2s linear;
}
.col1:before {
content: "not spanning";
}
.col2:before {
content: "not spanning";
}
复制代码
不是分屏(或折叠)设备中,看到的效果像下面这样:
在水平方向分屏状态(即spanning
取值为single-fold-vertical
)下的CSS:
@media (spanning: single-fold-vertical) {
.col1 {
flex: 0 0 env(fold-left);
margin-right: env(fold-width);
background-color: steelblue;
}
.col2 {
background-color: yellow;
}
.col1:before {
content: "spanning single-fold-vertical";
}
.col2:before {
content: "spanning single-fold-vertical";
}
}
复制代码
注意,示例中还使用了CSS的env()
函数,调用了CSS环境变量fold-left
和fold-width
。这个时候看到的效果以下:
当你把浏览器模式(Browser Mode)切换为“Left”或“Right”时,看到的效果以下:
上图是Surface Duo模拟器,Browser Mode为Left状态效果
上图是Surface Duo模拟器,Browser Mode为Right状态效果
接下来再来设备垂直方向分屏(即spanning
取值为single-fold-horizontal
)的布局样式:
@media (spanning: single-fold-horizontal) {
.wrapper {
flex-direction: column;
}
.col1 {
flex: 0 0 env(fold-top);
margin-bottom: env(fold-height);
background-color: pink;
}
.col2 {
background-color: seagreen;
}
.col1:before {
content: "spanning single-fold-horizontal";
}
.col2:before {
content: "spanning single-fold-horizontal";
}
}
复制代码
将设备的方向切换到portrait
状态下,浏览器在spanning
状态下,看到的效果以下:
一样的,若是你把模拟器的浏览器模式切换到"Top"或"Bottom"状态下,看到的效果也会不同:
最后,你还能够在spanning:none
状态下设置相应的CSS:
@media (spanning: none) {
.col1:before {
content: "spanning:none";
}
.col2:before {
content: "spanning:none";
}
}
复制代码
上面是一个较为简单的示例。那么接下来,咱们在上面的基础上把页面作得稍微复杂一点:
<!-- HTML -->
<ul class="card__container">
<li class="card">
<div class="card__object"><img src="//source.unsplash.com/300x300?01" alt="Psychopomp"></div>
<div class="card__body">
<h4 class="card__title">Psychopomp</h4>
<p>Japanese Breakfast</p>
</div>
</li>
<!-- ... -->
</ul>
复制代码
按照上面的示例,在媒体特性以外,给普通设备添加样式(也能够说是全局样式):
/* 布局关键样式 */
body {
width: 100vw;
min-height: 100vh;
margin: 0;
padding: 2vh;
}
.card__container {
gap: 2vmin;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
grid-auto-flow: dense;
}
.card:nth-child(1) {
grid-column: span 2;
}
.card:nth-child(6) {
grid-column: span 3;
}
复制代码
拖动浏览器时改变视窗大小,看到的效果以下:
在不对spanning
媒体特性下作任何样式处理时,在分屏状态下看到的效果以下:
一样的,先对spanning: single-fold-vertical
作样式上的处理:
@media (spanning: single-fold-vertical) {
.card__container {
gap: env(fold-width);
grid-template-columns: repeat(auto-fit, minmax(calc((env(fold-left) - env(fold-width) - 4vh) / 2), 1fr));
}
.card:nth-child(6) {
grid-column: span 2;
}
}
复制代码
这个时候水平分屏状态下的效果以下:
接着来看垂直方向的分屏状态下的效果,先来看未处理时的效果:
接下来在spanning: single-fold-horizontal
媒体特性下作一些布局上的处理:
@media (spanning: single-fold-horizontal) {
.card__container {
gap: 20px;
grid-template-columns: 1fr;
grid-template-rows: calc(env(fold-height) - 4vh);
}
.card__object {
height: 250px;
}
.card:nth-child(1) {
grid-column: span 1;
}
.card:nth-child(6) {
grid-column: span 1;
}
}
复制代码
看到的效果以下:
实际操做的时候,应该根据本身的使用场景,而后对应的媒体查询特性中配合CSS本地环境使用,实现不一样的效果。
有关于这方面的Demo,还能够查阅:
可折叠Web的出现,让移动优先的设计变得更加复杂,但也更加使人兴奋。可折叠Web多是第一次手持设备感到空间的扩展而不是限制。对于一些Web应用或Web页面来讲,须要作必定的调整,而对于另外一些Web应用来讲,则意味着须要大规模的从新设计。这个范围取决于开发人员的创新。