跳到主要内容

如何使用容器查询制作响应式Web应用程序

响应式网页设计已经存在多年了,在那段时间里,我们看到了网站开发方式的巨大转变。媒体查询让我们写CSS基于各种条件,例如分辨率,媒体类型和 - 最常见的 - 浏览器视口尺寸。

已经出现了设计模式,以帮助我们管理构建响应各种不同屏幕的网站的复杂性。

布拉德弗罗斯特方便维护模式汇编您可以用于您的网站。一般来说,这些模式基于浏览器视口的整个宽度来定位内容。换句话说,它们在宏观层面而不是微观层面上瞄准元素。

例如,在Shopify.com上,每个内容频段都是单独处理的,并且在较小的设备上很好地折叠。从设计角度来看,管理这些频段的设计更容易。从编码的角度来看,它也更容易。

断点

您可以在全局级别或波段级别创建断点。在全球范围内,定义移动设备,平板电脑和桌面断点并让开发人员选择每个元素在这些特定断点内的响应方式并不罕见。

在乐队级别,您可以更好地控制每个内容片段何时应该中断。也许这两个柱片应该以400px的形式折叠成一个列,但是这个三柱片应该以500px的形式折叠成一个列。

虽然我们在处理波段级别的断点时有更多的控制权,但从设计的角度来看,我们也使事情变得更加复杂。大多数使用Sketch或Photoshop工作的设计师都会为几个常见的视口创建画板:可能是肖像移动,肖像平板电脑和桌面。

在处理波段级别的断点时,设计人员需要远离这些有限数量的视图,并开始将事情分解为更小的块。然而,在传统的模型中,所有这些乐队仍然需要作为有凝聚力的设计呈现。

复杂的网络应用

对于许多以艺术为导向的基于内容的网站,模式在有限数量的场景中呈现。另一方面,Web应用程序在更广泛的上下文中使用较小的模式。按钮组可能会显示在标题,主体,侧边栏或模式中。

Each band – the header, intro and content – can be responsively designed independently of each other and without worrying about context

每个乐队 - 标题,简介和内容 - 可以相互独立地进行响应设计,而不必担心背景

现在考虑所有这些上下文乘以可能显示这些页面的各种视口。我们已经从三种可能的视图(移动设备,平板电脑和桌面设备)转变为数百种可能性。使用媒体查询,我们必须使用许多基于上下文的选择器来处理这些场景。

.buttongroup .button {...} .header .buttongroup .button {...} .modal .buttongroup .button {...} .sidebar .buttongroup .button {...} @media(min-width:600px){。buttongroup .button {... } .header .buttongroup .button {...} .modal .buttongroup .button {...} .sidebar .buttongroup .button {...}} / *等等几页* /

许多Web应用程序需要在不同大小的不同布局中呈现类似的组件。例如,自动完成组件在宽主列中的呈现方式可能与在较小的侧列中的呈现方式不同。

输入容器查询

媒体查询只能告诉我们视口的宽度或文档的宽度。因此,如果我们想要在侧边栏大于400px时更改组件在侧边栏中的显示方式,我们必须知道当视口宽度大于1000px时侧边栏将为400px宽。另一方面,容器查询允许我们说'这是我的组件在具有超过400px的空间时应该是什么样子'。

在你太兴奋之前,请允许我快速地让你失望:容器查询没有浏览器实现。更糟糕的是,没有容器查询的规范(cue Sad Violins)。没有规范出现的原因是因为可以引入的循环逻辑。

我们来看一个简单的例子:

/ * mythical:容器语法* / .container {float:left; } .child {width:500px; }

这里,子元素将容器的大小推到500px宽。接下来,我们添加一个容器查询,以便在容器宽度大于450px时应用条件样式。

.container:container(min-width:450px)> .child {width:400px; }

但请注意,我们将子元素设置为400px宽。这意味着我们的容器查询不再适用,因为容器将缩小到400px。由于容器查询不再适用,我们回退到500px的原始声明。这会将容器的宽度推回到500px,容器查询再次应用 - 依此类推,直到浏览器崩溃。目前尚不清楚如何在容器查询中解决循环逻辑。

Shopify解决方案

没有规范,我们必须用JavaScript解决问题。在Shopify,我们选择手动推出自己的解决方案。我们创建了一个自定义脚本,可以在页面上找到我们的组件,并且可以在应用宽度条件时有条件地应用“响应”类。

对于我们的需求,宽度是我们担心的唯一考虑因素。这是构建响应式设计时最常用的属性,有些脚本只检测宽度。当然,有权访问查询高度等其他属性可以让我们创建更灵活,更强大的设计,但这也增加了复杂性。

为了定义查询,我们创建了一个JSON对象数组,允许我们快速选择我们想要的元素,然后测试父元素是否大于最小宽度或者不到最大宽度。如果是,那么我们将响应类应用于元素:

elements = [{“component”:“。flex-2x1”,“className”:“flex-2x1-responsive”,“minWidth”:768,“maxWidth”:1024},{“component”:“。modal”, “className”:“modal-responsive”,“maxWidth”:1024},{“component”:“。buttons”,“className”:“buttons-responsive”,“minWidth”:300}];

'component'名称是一个选择器 - 为了简单起见,它几乎总是一个单类选择器。我们使用命名约定来轻松识别我们的组件,并继续将命名约定延伸到应用的响应类。这些响应类将在与组件的其余部分相同的文件中定义。如果您熟悉CSS的可扩展和模块化架构(SMACSS),那么这些响应类的行为与状态非常相似。

右图:典型布局 - 使用的双列布局Flexbox的+$. The content stretches to fill the column it’s in Left: Lining up - When space is tight, Flexbox automatically reflows the right column underneath the left column, and the content grows to fill it

快速移动

对于具有大量组件的复杂应用程序,能够专注于单个组件而不关心它所使用的上下文是很好的。随着截止日期临近,团队能够通过分别处理每个组件来分工。标签如何工作?标题如何工作?布局如何工作?每个团队成员都可以抓住一块,解决其关注点,创建拉取请求,然后转到下一个组件。这使我们能够在不到一个月的时间内使用Web应用程序并使其响应。

......而不是那么快

在一个月内做出回应?天啊!为什么不是每个人都在这么短的时间内使用容器查询和构建响应式应用程序?事实是,大部分工作都是在设计层面进行的,这是在Shopify管理员响应之前几个月发生的。

设计团队正在考虑他们的工作影响,知道我们最终会做出响应,这为我们节省了大量的工作。一些组件 - 比如标签溢出 - 在响应之前需要考虑好,而且没有使用容器查询的基于JavaScript的解决方案是单独构建的。

例如,在我最近在Xero工作期间,设计团队正在经历这个过程。在每个上下文中考虑每个组件需要花费时间,并且需要更多时间来构建组件。如果设计师没有考虑到这一点,那么工程师就会这样做。我不贬低地说。无论如何,工作都需要完成,越快越好。

愤怒的JavaScript

用于查找元素和应用条件类的循环将被执行多次:

  • 每次页面加载
  • 每次浏览器调整大小
  • 每次交互都会影响文档流
  • 每次动态注入内容

您拥有的需要条件样式的组件越多,JavaScript所需的工作就越多。任何这些事件都可能造成明显的滞后。页面加载,然后在几分之一秒后,在应用类时会发生可辨别的移位。

完全避免查询

从Shopify最初实施容器查询开始的一年多时间里,团队正逐渐远离使用它们,选择其他技术来解决问题。因此,如果现在容器查询过于繁琐,没有它们我们能做什么呢?事实证明 - 谢谢Flexbox的- 我们有选择。

响应式设计面临的最大挑战是如何处理多列内容并以合理的方式重排它。我们来看看两个常见的例子。

带侧面导航的双柱偏置设计

Shopify有许多这样的屏幕:有一个侧面导航,然后是一个内容区域,有两列,一列比另一列大。如果两列的宽度都相同,那么我们就可以浮动列。当页面不再能够并排放置时,一列会落在另一列之下。

但是,对于偏移大小,简单地将一列浮动到另一列之下看起来很奇怪。当您向下滚动时,您会注意到内容突然没有伸展到容器的整个宽度。

使用Flexbox,我们可以为列和min-wrap定义最小宽度:包装到容器。当列达到最小值时,将在另一列之下流动。最好的部分是,当它包裹时,每列现在将拉伸到容器的整个宽度。

...
...
.two-columns {display:flex; flex-wrap:wrap; } .col1 {flex-basis:66%;最小宽度:360px; } .col2 {flex-basis:33%; }

通过在主列上设置min-width,我们基本上定义了一个基于该列的断点,允许它旁边的列在没有足够空间时流下。

The Media object with actions aligned to the right on larger screens

Media对象的操作在较大的屏幕上与右侧对齐

带有操作的媒体对象

媒体对象定义了一种非常常见的模式:左侧的图像,右侧的描述性文本。这种模式通常需要增加第三部分:右对齐动作。

Flexbox combined with our media object allows it to reflow the actions under the content

Flexbox与我们的媒体对象相结合,允许它重排内容下的操作
...
...
.media-body {display:flex; flex-wrap:wrap; } .media-content {flex-grow:1; flex-basis:400px; } .media-actions {align-self:center; }

我们用两个容器扩充了媒体对象的主体:一个用于内容,一个用于操作。像最后一个例子一样,我们设置flex-wrap来包装,所以当我们用完房间时,第二个容器将换行到下一行。当内容容器达到其最小宽度(使用flex-basis设置)时,操作将流向下一行。但是,这些操作现在将与内容对齐,而不是向右。

填写

从这两个示例中可以看出,构建响应式站点的最佳方法是,您无需创建大量媒体查询即可跨不同视口管理设计。通过允许设计的组件自然地填充它们所在的容器,充分利用网络的流动性。避免指定固定的宽度和高度,这将使您的场地过于脆弱。

未来

您需要评估您的项目,以确定使用JavaScript解决方案在您的网站上实施容器查询是否理想。在Shopify,它让我们快速行动,我们在一开始就接受了性能缺陷。获得容器查询的本地实现将是理想的,但在我们看到进展之前,我们需要更多的倡导和深入思考如何解决性能和循环问题。

ResizeObserver如果引入DOM,可以在JavaScript中提供更简单且可能更高性能的实现。要了解容器查询的未来,请查看响应问题社区小组(RICG)。

本文最初发表于285年第285期网络杂志Ë,专业网页设计师和开发人员杂志 - 提供最新的网络趋势,技术和技术。在这里订阅网

相关文章:



翻译字数超限