前端CSS网页布局新技术(双屏和折叠屏手机)解决方案
三星 Galaxy Fold 和 Surface Duo 以及华为mate X等系列折叠屏手机问世至今已有三年多的时间。此后,三星 Galaxy Z Fold 3 和 Galaxy Z Flip 3、华为mate X2S、荣耀magic V系列等手机均已上市。可折叠设备可供购买,目前正在被消费者使用,随之而来的是我们作为开发人员可以开始探索这种新型设备和响应式设计的下一个发展的机会。
这些 Web 平台功能与现有概念(例如视口和媒体查询)集成,因此开发人员和设计人员可以花更多时间思考如何利用两个显示器来创建增强体验,而不是学习一组新代码来构建它们。
使用新的 CSS 媒体功能检测可折叠设备
双屏和可折叠设备只是响应式设计的下一步,因此它们被视为另一个响应式设计目标,我们可以使用媒体功能为其设计样式。我们今天已经使用媒体功能和查询来定位台式机、平板电脑和手机,现在我们拥有 CSS Viewport Segments 媒体功能来定位我们的可折叠和双屏设备。
horizontal-viewport-segments
视口分段媒体查询可以有两个值。第一个是
horizontal-viewport-segments,这表示设备铰链垂直且视口被硬件铰链拆分或折叠成列时的设备状态。
当
horizonal-viewport-segment铰链处于垂直折叠姿势时,目标是设备。
为了专门为这种方向的可折叠设备提供样式,我们将编写以下内容:
@media (horizontal-viewport-segments: 2) {
// Styles specific to the device in this orientation
}
整数表示设备方向中存在的视口数量。当设备像一本书一样处于垂直折叠姿势时,我们在水平方向有两个不同的视口,在垂直方向只有一个视口。
我们还可以结合我们的媒体查询来定位双屏设备和某些视口宽度,以提供特定的样式:
@media (horizontal-viewport-segments: 2) and (min-width: 540px) {
body {
background: yellow;
}
}
vertical-viewport-segments
我们的视口分段媒体功能的第二个值是
vertical-viewport-segments,这是设备铰链水平时设备的状态,并且硬件铰链将我们的视口分成行。
vertical-viewport-segments目标设备处于水平折叠姿势。
要定位在这个方向旋转的设备,我们将使用以下代码:
@media (vertical-viewport-segments: 2) {
// Styles specific to the device in this orientation
}
使用 JavaScript 检测可折叠设备
在某些情况下,您可能无法或不想使用 CSS 媒体查询来检测您的用户是否在可折叠设备上,这就是 JavaScript API 的用武之地。最初,提出了一个名为 Windows Segments Enumeration 的全新 API ,但在开发者社区通过原始试验获得反馈后,在现有的Visual Viewport API 草案规范的基础上构建更有意义。
视口段属性
视口段表示位于彼此相邻的单独显示器上的窗口区域。要检测双屏设备,您可以使用以下代码查询 segments 属性:
const segments = window.visualViewport.segments;
此查询返回的值将是一个数组DOMRects,指示有多少视口。如果只有一个视口段,则查询将返回null,并以这种方式实现以防止将来出现兼容性问题,以免开发人员开始使用visualViewport.segments[0]针对单屏设备。
在双屏设备上,查询将返回 2 DOMRects,表示当浏览器窗口跨越折叠时可用的 2 个视口。
我们存储在segments常量中的这个值是查询属性时设备状态的不可变快照,如果浏览器窗口调整大小或设备旋转,之前检索到的视口段不再有效,需要查询再次通过调整大小或方向事件(或两者)。
如果您调整浏览器窗口的大小以仅跨越一个显示区域,我们将触发调整大小事件。
如果您旋转设备,这将触发调整大小和方向事件,您可以使用这些事件再次查询属性以获取浏览器显示区域的当前状态。
window.addEventListener("resize", function() {
const segments = window.visualViewport.segments;
console.log(segments.length); *// 1*
});
何时使用 JAVASCRIPT API 与 CSS 媒体功能来检测 设备
CSS 媒体功能和 JavaScript 段属性都将检测双屏设备,但 JavaScript 属性最好在没有使用 CSS 时使用,当您在 Canvas2D 和 WebGL 中处理对象时可能会发生这种情况。例如,您正在开发的游戏可以同时利用两个屏幕。
使用 CSSenv()变量
除了 CSS 媒体功能之外,还引入了六个新的 CSS 环境变量,以帮助开发人员计算显示区域的几何形状,计算铰链区域在被 Surface Duo 等物理硬件功能遮挡时的几何形状,以及它们还可用于帮助将内容放置在每个显示区域的边界内。
六个新的环境变量如下:
- env(viewport-segment-width <x> <y>);
- env(viewport-segment-height <x> <y>);
- env(viewport-segment-top <x> <y>);
- env(viewport-segment-left <x> <y>);
- env(viewport-segment-bottom <x> <y>);
- env(viewport-segment-right <x> <y>);
x和位置表示由分隔每个视口段的硬件功能创建的y二维网格,坐标0,0从左上段开始。
当您的设备处于垂直折叠姿势且视口并排时,左侧的视口段将由 表示env(viewport-segment-width 0 0),而右侧的视口段将由 表示env(viewport-segment-width 1 0)。如果您将设备转换为水平折叠姿势,视口堆叠,顶部将由 表示env(viewport-segment-height 0 0),底部视口由表示env(viewport-segment-height 0 1)。
使用env(viewport-segment-width)andenv(viewport-segment-width)时,除了索引之外,我们还可以设置一个后备值,如下所示:
env(viewport-segment-width 0 0, 100%);
但是这个额外的后备值是可选的,由作者自行决定,如果他们想包含它。
计算铰链宽度
当您的设备的铰链被硬件功能遮挡时,您可以使用提供的环境变量来计算它。
我们可以使用环境变量计算设备铰链。
在我们的示例中,我们有一个处于垂直姿势的设备,并且想要找到铰链宽度,这样就不会遮挡任何内容。我们将从左显示器的右视口段中减去右显示器的左视口段:
calc(env(viewport-segment-left 1 0) - env(viewport-segment-right 0 0));
使用 CSSenv()变量 放置内容
我们可以使用 CSS 环境变量在显示区域边界内放置内容,如果您想将内容直接放置在铰链或折叠处,这些特别有用。
在下面的示例中,我们将在左侧第一个显示区域的铰链上直接放置图像。该区域是视口的右侧部分,因此我们将使用viewport-segment-right以下代码放置它:
img {
max-width: 400px;
}
@media (horizontal-viewport-segments: 2) {
img {
position: absolute;
left: env(viewport-segment-right 0 0);
}
}
如果我们在 Surface Duo 模式下在 Edge 开发人员工具中模拟我们的屏幕,我们将获得以下布局:
最初使用环境变量将图像放置在我们的布局中会将其放置在错误的显示区域中。
这不是我们想要的。图像应位于左侧的显示区域中。
因为图像是使用属性绝对定位的left,所以图像的左边缘最终与viewport-segment-right显示区域对齐。
然后,我们需要从环境变量中减去图像的宽度,以使图像与正确的铰链边缘对齐:
img {
max-width: 400px;
}
@media (horizontal-viewport-segments: 2) {
img {
position: absolute;
left: calc(env(viewport-segment-right 0 0) - 400px);
}
}
从视口段中减去图像宽度会将其沿左侧显示中的铰链放置。
现在我们将图像放置在我们想要的位置。有关如何沿铰链对齐项目的其他示例,您可以查看这个简单的盒子演示。打开Edge Developer Tools>Device Emulation然后选择Surface Duo并确保您Duo emulation处于校正方向姿势。
把它们放在一起:让我们构建一个适应双屏设备的食谱页面
作为一个在做饭时经常使用手机的人,当我在我的双屏设备上时会适应的食谱网站会非常有帮助。让我们来看看如何考虑为它调整一个单独的食谱页面。
我想考虑我将如何分块我的主要内容。通常情况下,我至少会看到食谱标题、制作的份量、烹饪需要多长时间、一张或多张图片、配料以及制作菜肴的步骤。
当我画出我的线框时,我得到以下信息:
桌面上食谱页面的标准布局
我希望我的标题和食谱详细信息在最顶部,然后是一个占据整个内容宽度的图像,然后是成分列表和食谱步骤。我不想堆叠后两个内容组,因为如果我堆叠它们,成分列表的右侧会有很多空白,所以我希望步骤坐在成分旁边,给我两列图片下方。
用于布局的 CSS 网格或 FLEXBOX?
我知道我想如何在普通桌面屏幕上布置这个食谱,并且有多种方法可以对这个布局进行编码和对内容进行分组,但我如何对其进行分组,以及我想在双屏上实现什么布局在我编码之前需要考虑设备。根据我为桌面视图所做的草图,我可以使用 flexbox 和 CSS Grid 的组合来实现我想要的布局,我将成分和步骤分组到一个 flex 容器中。但是让我勾勒一下我希望我的页面如何在双屏上显示。
垂直折叠位置的可折叠设备上的理想布局通过显示屏将内容分开,因此不会被铰链遮挡。
如果我想在布局上有更大的灵活性,那么我不能将我的成分和步骤分组到一个 flex 容器中,否则,无论图像没有进入哪一列,都会有很大的空白。
如果我只在这个布局中使用 flexbox,它会产生一些我想避免乱用的间距。
添加我们的内容
我将在桌面和双屏布局中只使用 CSS Grid。所以,让我们构建我们的内容。
<main>
<section class="recipe">
<div class="recipe-meta">
… <!—Contains our recipe title, yield and servings -->
</div>
<img src="imgs/pasta.jpg" alt="Pasta carbonara photographed from above on a rustic plate" />
<div class="recipe-details__ingredients">
…<!— Contains our ingredients list -->
</div>
<div class="recipe-details__preparation">
… <!— Contains our list of steps to put the ingredients together -->
</div>
</section>
</main>
接下来,让我们构建页面的结构。我要定义我的网格:我只想要三列,并且我希望它们是容器的相等部分。
.recipe {
display: grid;
grid-template-columns: repeat(3, 1fr);
接下来,我将定义我的行,并且我将使用grid-auto-rowswith minmax,这样我的行是最小的,175px但可以增长到最大内容高度的最大值。
grid-auto-rows: minmax(175px, max-content);
然后我将添加更多属性: my grip-gap、我的最大内容宽度和一个边距,以使我的布局在页面上居中。
grid-gap: 1rem;
max-width: 64rem;
margin: 0 auto;
}
然后,我将把我的内容放入我定义的网格中:
.recipe-meta {
grid-column: 1 / 4;
}
.recipe-meta p {
margin: 0;
}
img {
width: 100%;
grid-column: 1 / 4;
}
.recipe-details__ingredients {
grid-row: 3;
}
.recipe-details__preparation {
grid-column: 2 / 4;
grid-row: 3;
}
这将根据我的草图为我提供布局:
布局在桌面上按预期呈现
伟大的!但是我的双屏布局呢?让我们深入了解我们的horizontal-viewport媒体功能和双屏网格。
使用媒体查询和调整容器布局
首先,这是我现在在双屏上的布局:
在没有实现任何双屏代码的情况下,如果用户想要将浏览器跨过两个显示器,那么页面将是这样的。
如果我们向下滚动:
如果用户选择跨越两个显示器,则内容会被铰链遮挡。
不是很好。我们的内容被铰链遮住了,所以让我开始重新定义我的网格。
对于我的网格列,我仍将使用三列,但我希望一列占据左侧的第一个视口段,另外两列占据右侧视口段,因此我将使用我的 CSS环境变量env(viewport-segment-width 0 0)告诉浏览器,对于我的第一列,我希望它占据第一个显示区域的整个视口。
@media (horizontal-viewport-segments: 2) {
/* Body styles for smaller screens */
body {
font: 1.3em/1.8 base, 'Playfair Display', serif;
margin: 0;
}
.recipe {
grid-template-columns: env(viewport-segment-width 0 0 1fr 1fr;
grid-template-rows: repeat(2, 175px) minmax(175px, max-content);
}
}
对于我的行,我希望在放置上更灵活一点,所以我将重复两行175px,这是关于带有配方标题、产量和时间信息的容器的高度,之后的行应该匹配我最初在网格中定义的内容。
如果我在 DevTools 中检查我的设计,我可以看到我在配方容器上设置的width和margin最初将我想要与我的视口段对齐的网格线推到正确的视口段中。
添加我的代码后,我的内容不再被遮挡,但仍需要一些间距调整。
要重置它,我将重置我的marginand max-width。
@media (horizontal-viewport-segments: 2) {
.recipe {
grid-template-columns: env(viewport-segment-width 0 0) 1fr 1fr;
grid-template-rows: repeat(2, 175px) minmax(175px, max-content);
margin: 0;
max-width: 100%;
}
}
重置我的边距和填充会掩盖右侧显示中的内容。
现在我要把我的内容放在网格中并调整我的布局。
.recipe-meta {
grid-column: 1 / 2;
padding: 0 2rem;
}
img {
grid-column: 2 / 4;
grid-row: 1 / 3;
width: 100%;
height: 100%;
object-fit: cover;
/* necessary to keep the image within the grid lines */
}
.recipe-details__ingredients {
grid-row: 2;
padding: 0 2rem;
}
.recipe-details__preparation {
grid-column: 2 / 4;
grid-row: 3;
padding: 0 2rem 0 3rem;
}
我已经对内容应用了填充,除了我决定要跨越整个视口的图像。对于图像下方的内容,由于从物理铰链下方开始的网格线的性质,我想添加额外的填充,因此它看起来左侧的填充与其他带有填充的项目相同。如果我不添加额外的,它会落得太靠近铰链。因为我已经有一个 grid-gap1rem并且我想将 padding 加倍,所以我将添加3rem而不是4rem为我们提供双屏设备上的最终布局:
我可以重新添加尺寸更合适的填充来显示内容,因此它不会在带有物理铰链的设备上被遮挡。
只需对我们的 CSS 进行一些小的调整并使用其中一项新的媒体功能,我们就有了一个适应双屏设备的布局。要查看体验,请前往此处的 Edge 演示站点或基于 Chromium 的浏览器,然后打开浏览器开发人员工具以查看 Surface Duo 仿真。如果您在 Chrome 中打开该站点,请确保在 下启用了实验性网络平台功能标志chrome://flags,以便演示正确显示。
单屏响应式设计细节
为了确保我们考虑到小型单屏设备,我为手机布局选择的代码使用了 flexbox 并将所有内容放在一个列中:
@media (max-width: 48rem) {
body {
font: 1.3em/1.8 base, 'Playfair Display', serif;
}
.recipe-details {
display: flex;
flex-direction: column;
}
}
API 浏览器可用性和无设备测试
默认情况下,这些双屏 API 在 Microsoft Edge 和 Android 上的 Edge 中可用,从版本 97 开始。这些计划很快就会出现在其他 Chromium 浏览器中,但具体时间尚未确定。要在 Chrome 中启用这些 API,请转到chrome://flags并启用实验性网络平台功能。
虽然这些是相对较新的设备,但许多现在已经进入第二代和第三代,因此公司正在投资它们。如果您无法使用物理设备,最好的测试方法是使用浏览器开发工具。我已经在仿真工具和 Surface Duo 上测试了我的网站,Duo 的仿真工具似乎是相同的。我的设计在设备上的外观与在 DevTools 中的外观相同。它使构建和设计双屏设备就像开发桌面和单屏移动设备一样容易。
如果您使用的是不支持这些 API 的桌面或设备,则可以为 Visual Viewport Segments 属性提供一个 polyfill。CSS 媒体查询没有 API。目前,市场上的双屏设备都是基于安卓的,这些API计划在安卓上可用的基于Chromium的浏览器中。
如果可折叠设备上的浏览器不支持这些功能,您可以使用 polyfill 或确保您的网站在小单屏上仍能很好地呈现,因为用户可以灵活选择如何在双屏上显示网站屏幕设备。他们可以跨两个显示器跨越一个网站,或者他们可以选择让它跨一个显示器,如果他们选择后者,它将像在平板电脑或手机上一样显示。即使您的网站没有双屏实现,用户仍然可以选择单显示视图。双屏 API 提供了一种方法来逐步增强拥有设备的用户的体验。
结束
双屏设备只是响应式设计的下一个发展方向。如果您有 PWA 或网站,可用的 API 可以无缝集成到您现有的代码库中。还有其他方法可以为双屏设备构建应用程序,您可以在Surface Duo 文档
https://docs.microsoft.com/en-us/dual-screen/中查看这些方法。这是在网络上进行布局的激动人心的时刻,双屏提供了获得更多创意的机会。
为帮助到一部分同学不走弯路,真正达到一线互联网大厂前端项目研发要求,首次实力宠粉,打造了《30天挑战学习计划》,内容如下:
HTML/HTML5,CSS/CSS3,JavaScript,真实企业项目开发,云服务器部署上线,从入门到精通
- PC端项目开发(1个)
- 移动WebApp开发(2个)
- 多端响应式开发(1个)
共4大完整的项目开发 !一行一行代码带领实践开发,实际企业开发怎么做我们就是怎么做。从学习一开始就进入工作状态,省得浪费时间。
从学习一开始就同步使用 Git 进行项目代码的版本的管理,Markdown 记录学习笔记,包括真实大厂项目的开发标准和设计规范,命名规范,项目代码规范,SEO优化规范
从蓝湖UI设计稿 到 PC端,移动端,多端响应式开发项目开发
- 真机调试,云服务部署上线;
- Linux环境下 的 Nginx 部署,Nginx 性能优化;
- Gzip 压缩,HTTPS 加密协议,域名服务器备案,解析;
- 企业项目域名跳转的终极解决方案,多网站、多系统部署;
- 使用 使用 Git 在线项目部署;
这些内容在《30天挑战学习计划》中每一个细节都有讲到,包含视频+图文教程+项目资料素材等。只为实力宠粉,真正一次掌握企业项目开发必备技能,不走弯路 !
过程中【不涉及】任何费用和利益,非诚勿扰 。
如果你没有添加助理老师微信,可以添加下方微信,说明要参加30天挑战学习计划,来自博客园!老师会邀请你进入学习,并给你发放相关资料。