下一代响应式Web设计:组件驱动式Web设计(3)

简介: 下一代响应式Web设计:组件驱动式Web设计

早在 2019 年底,@Zach Leatherman在寻找容器查询起源(地址:https://www.zachleat.com/web/origin-container-queries/时,找到的最早有关于容器查询的解决方案是 @Andy Hume基于 JavaScript 的选择器查询和响应式容器的解决方案(地址:https://github.com/ahume/selector-queries


2015 年, @Mat ‘Wilto’ Marquis在响应式图片社区小组引入了 元素,将响应式图片带到了响应式 Web 设计的世界,他在《Container Queries: Once More Unto the Breach》(地址:https://alistapart.com/article/container-queries-once-more-unto-the-breach/一文中概述了元素查询的挑战和使用案例演示了容器查询的特性。


然后,在2017年,@Ethan Marcotte写了一篇关于容器查询相关的文章(地址:https://ethanmarcotte.com/wrote/on-container-queries/,并提出了这样的看法:


在他最初关注的响应式 Web 设计的文章之后的几年里,Web设计师和开发人员的工作越来越集中在组件上,而不是整个页面,这使得媒体查询不那么理想。


从那时起,虽然有很多人主张使用媒体查询,但容器查询向前推进的速度还是不够理想。@L. David Baron在《Thoughts on an implementable path forward for Container Queries(地址:https://github.com/dbaron/container-queries-implementability中简明扼要地解释了容器查询向前推进慢的问题出在哪?


容器查询要求样式取决于组件的大小,但考虑到 CSS 的工作原理,组件中的样式会影响其大小。任意打破这个循环,既会产生奇怪的结果,又会干扰浏览器的工作,还会增加浏览器优化的成本。


除了 @David Baron 之外,2018年6月, @Greg Whitworth在荷兰阿姆斯特丹举办的 CSS Day + UX Special(地址:https://noti.st/events/elQrNX/css-day-ux-special活动上的主题分享《Over the moon for container queries》(地址:https://noti.st/gregwhitworth/UDul7E/over-the-moon-for-container-queries中也解释了容器查询在Web平台上推进慢的相关原因。更重要的是,@Greg Whitworth还提供了使用新的 JavaScript API 和 CSS 的新技术来实现容器查询的特性。@David Barrrron 也提出了一个可以避免这种困境的策略(地址:https://github.com/dbaron/container-queries-implementability,更重要的是 @Miriam Suzanne在 @David Baron 的策略基础上提出了 @container方法(地址:https://github.com/oddbird/css-sandbox/blob/main/src/rwd/query/explainer.md)地址:https://github.com/oddbird/css-sandbox/blob/main/src/rwd/query/explainer.md)


@container 方法通过对被查询的元素应用大小和布局的限制来实现。任何具有尺寸和布局限制的元素都可以通过一个新的 @container规则进行查询,其语法与现有的媒体查询类似。


这个提议已经被 W3C 的 CSS 工作组采纳(地址:https://drafts.csswg.org/css-contain-3/,并已经添加到 CSS Containment Module Level 3(地址:https://www.w3.org/TR/css-contain-3/模块中。有关于该功能的相关问题和各网格平台推进进度,可以点击这里查阅(地址:https://github.com/w3c/csswg-drafts/projects/18


image.gif图片.png


虽然 CSS Containment Module Level 3 还是 FPWD 版本,规范中所描述的语法不是最终版本,直到写这篇文章,其语法规则还在变,因此文章中所展示的语法有可能会变以及相关的示例有一天就无效了:


image.gif图片.png


  • 什么是容器查询



CSS 容器查询最大的特点是:



容器查询允许开发者定义任何一个元素为包含上下文,查询容器的后代元素可以根据查询容器的大小或计算样式的变化来改变风格!


换句话说,一个查询容器是通过使用容器类型属性(container-typecontainer)指定要能的查询类型来建立的。适用于其后代的样式规则可以通过使用@container条件组规则对其进行查询来设定条件。容器查询为响应式设计提供了一种更加动态的方法。这意味着,如果你将此卡片组件放在侧边栏或放在页面主体内部的网格中,则该组件本身根据容器而不是视口进行响应式的信息展示。
image.gif

图片.png

首先,把卡片放到一个容器元素中,比如.card__container


<!-- HTML -->
<div class="card__container">
  <div class="card">
    <img src="https://picsum.photos/2568/600?random=1" width="2568" height="600" alt="" class="card__thumbnail" />
    <div class="card__badge">Must Try</div>
    <h3 class="card__title">Best Brownies in Town</h3>
    <p class="card__describe">High quality ingredients and best in-class chef. Light, tender, and easy to make~</p>
    <button class="card__button">Order now</button>
  </div>
</div>


也就是说,当卡片组件被放在一个容器中时,代表着它被包含在该容器中,比如上面代码中的.card__container。这也意味着,我们可以使用 CSS 的 container来查询.card__container 的宽度,并在@container.card 设置不同的样式规则。从而达到设计师真正的意图:图片.png


比如,容器宽度(.card__container)分别在 >400px>550px>700px 时为.card设置不同样式:


图片.png


代码可能像下面这样:


/* Default */
.card {
  // ...
}
/* CSS Container Queries*/
.card__container {
  container-type: inline-size;
}
/* container's width > 400px*/
@container size(width > 400px) {
  .card {
    // ...
  }
}
/* container's width > 550px*/
@container size(width > 550px) {
  .card {
    // ...
  }
}
/* container's width > 700px*/
@container size(width > 700px) {
  .card {
    // ...
  }
}


image.gif图片.png


 Untitled@airenCodePen

(地址:https://codepen.io/airen/pen/ZEvoBYL

(地址:https://codepen.io/airen

(地址:https://codepen.io/



拖动卡片右下角的滑块,改变 .card__container 容器大小,你可以看到卡片组件(.card)UI效果的变化:


图片.png

@container规则,其工作方式与使用@media的媒体查询类似,但相反,@container查询父容器以获取信息,而不是视口和浏览器的UserAgent


  • 容器查询的使用



到目前为止,CSS 容器查询的语法规则已经经历了多个版本更新,上面示例中展示是最新的使用方式。下面这几篇文章中可以索引到其每个版本的使用方式的差异:

  1. 初探CSS容器查询
    (地址:https://www.w3cplus.com/css/container-queries.html
  2. 容器查询给设计带来的变化
    (地址:https://www.w3cplus.com/css/container-queries-for-design.html
  3. 容器查询中的 container@container
    (地址:https://www.w3cplus.com/css/container-queries-with-container-and-at-container.html


接下来,通一个容器查询卡片的示例来向大家展示如何使用 CSS 容器查询。


定义一个包含性上下文


要使用 CSS 容器查询特性,首先要定义一个包含性上下文(Containment Context)。这个有点类似于使用 Flexbox 和 Grid 布局(定义Flexbox 或 Grid 上下文使用的是 display 属性),只不过,定义一个包含性的上下文使用的不是我们熟知的 display 属性,而是一个新的CSS属性,即 container在一个元素上显式使用 container 可以告诉浏览器以后要针对这个容器进行查询,以及具体如何查询该特定的容器。比如,上面演示的示例中,我们在 .card__container 元素上(.card的父容器)显式设置了 container-type 的值为 inline-size


.card__container {
  container-type: inline-size
}


上面的代码告诉浏览器,可以基于.card__container容器的内联轴(Inline Axis)方向尺寸变化进行查询。也就是说,当.card__container容器宽度大小变化到指定的某个值时,其后代元素的样式就可以进行调整。container-typecontainer 属性中的一个子属性,另外,还可以显式使用 container-name 来命名你的容器,即给一个包含性上下文指定一个具体的名称:


.card__container {
  container-name: card
}


这种方式对于同一个上下文中有多个包含性上下文时非常有意义,可以更明确地知道哪些查询会影响元素。

你可以使用简写属性container,只不过需要在 container-typecontainer-name 之间添加斜杠分割符/


.card__container {
  container-type: inline-size;
  container-name: card;
}
/* 等同于 */
.card__container {
  container: inline-size / card;
}


如果一个容器查询被应用到一个没有定义的包含祖先元素上,查询将无法应用。也就是说,无论是 body 还是 html 元素,都没有默认的回退包含上下文。另外,定义包含上下文名称时不能是 CSS 的关键词,比如 defaultinheritinitial 等。



注意:container-name 可以省略,如果省略将会使用其初始值none,但 container-type 不可省略,如果省略的话则表示未显式声明包含性上下文!


定义一个容器查询

现在我们知道使用 container(或其子属性 container-typecontainer-name)对一个元素显式声明包含上下文(对一个元素应用包含性)。有了这个包含性上下文之后,就可以使用 CSS 的 @ 规则@container来对应用了包含性元素进行查询,即对容器进行查询。@container 规则的使用和 @media 以及 @supports相似:


@container containerName size(width > 45rem) {
  /* 应用了包含性上下文后代元素的 CSS */
}
@container size(width > 45rem) {
  /* 应用了包含性上下文后代元素的 CSS */
}



这两种方式都是正确的使用姿势,第一个示例中的 containerName 指的是 container-name 显式声明的包含性上下文的名称。如果在@container 中没有指定查询的容器名称,那么这个查询将是针对离样式变化最近的声明了包含性上下文的元素进行查询。比如:



@container size(width > 30em) {
  .card {
    border-radius: 20px;
  }
}


表示这个查询将是针对 .card 元素最近的显式声明了包含性上下文的元素进行查询。



代码中的size() 函数是容器查询中的新语法规则。这也是容器查询语法变化之一,即 对查询类型进行了更明确的规定。因为规范已经提高到不仅可以根据尺寸(size)属性查询,还可以根据样式(style)属性进行查询。



image.gif图片.png


正如 Terrible Mia(容器查询规范设计者)在 Twitter 上分享的一样,可以使用
style() 函数对样式进行查询:


@container style(--card: large) {
  /* CSS Style */
}
@container size(width > 30em) and style(--card: large) {
  /* CSS Style */
}



到写这篇文章的时候,还没有浏览器支持对样式进行查询。另外,示例中用于 @container 的查询条件(width > 30em) 相当于 (min-width: 30em)。使用数学表达式要比使用 min-widthmax-width更易于理解,自 Media Queries Level 4(地址:https://www.w3.org/TR/mediaqueries-4/#mq-range-context开始, 在 @media 规则中,也可以使用我们熟悉的数学表达式,比如>=<=等来替代以往不易于理解的min-max-


image.gif图片.png


上面示例代码中同时出现 container@container,但他们并不是指的同一个属性,前者是一个CSS属性,后者是一个CSS代码块。而且两者有本质的区别:



  1. containercontainer-typecontainer-name 的简写属性,用来显式声明某个元素是一个查询容器,并且定义查询容器的类型(可以由container-type指定)和查询容器的名称(由container-name指定)。
  2. @container(带有@规则),它类似于条件CSS中的@media@supports规则,是一个条件组规则,其条件是一个容器查询,它是大小(size)和(或)样式(style)查询的布尔组合。只有当其条件为真(true),@container规则块中的样式都会被用户代理运用,否则将被视为无效,被用户代理忽略。


容器查询卡片



我想大家对容器查询的理论和概念有了一个初步的认识。接下来,我们把这些东西放到一起,来具体看看前面展示的容器卡片示例是如何实现的。



自从响应式 Web 设计的出现以及移动终端设备越来越多,在设计中也有移动端优先(Mobile First)还是桌面端优先(Desktop First)的争执:



image.gif图片.png


如果你对这方面讨论感兴趣,可以阅读 Ahmad Shadeed 的 《 The State Of Mobile First and Desktop First 》一文。 (地址:https://ishadeed.com/article/the-state-of-mobile-first-and-desktop-first/

就我个人而言,到目前为止,在开发跨组件状态的“断点”时,将容器查询与考虑“移动端优先”的设计是最有意义的。也就是说,将最窄的视图作为默认样式,然后通过容器查询处理更大宽度的样式更新。image.gif图片.png

如上图所示,我们从左往右来实现卡片不同状态断点下的UI效果。先从最窄的卡片开始(最左侧,Default 状态)。构建这个卡片组件,所需要的 HTML 结构如下:


<div class="card__container">
  <div class="card">
    <img src="https://picsum.photos/2568/600?random=1" width="2568" height="600" alt="" class="card__thumbnail" />
    <h3 class="card__title">Container Queries Rule</h3>
    <p class="card__describe">Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quis magni eveniet natus nulla distinctio eaque?</p>
    <button class="card__button">Order now</button>
  </div>
</div>


我们通过 CSS Grid 来完成卡片的布局。先从最窄的开始,添加下面CSS代码:



.card {
  display: grid;
  gap: 1rem;
  margin: 5vh auto;
  border-radius: 0.5rem;
  box-shadow: 0 0.25rem 0.5rem -0.15rem hsla(0 0% 0% / 55%);
  background-color: #fff;
}
.card__thumbnail {
  max-width: 100%;
  aspect-ratio: 16 / 9;
  height: auto;
  object-fit: cover;
  border-radius: 0.5rem 0.5rem 0 0;
}
.card__title {
  font-weight: 700;
  font-size: clamp(1.2rem, 1.2rem + 3vw, 1.5rem);
  padding: 0 20px;
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
}
.card__describe {
  color: #666;
  line-height: 1.4;
  padding: 0 20px;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
}
.card__button {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  border: none;
  border-radius: 10rem;
  background-color: #feca53;
  padding: 10px 20px;
  color: #000;
  text-decoration: none;
  box-shadow: 0 3px 8px rgb(0 0 0 / 7%);
  transition: all 0.2s linear;
  font-weight: 700;
  justify-self: end;
  margin: 0 20px 20px 0;
  cursor: pointer;
}
.card__button:hover {
  background-color: #ff9800;
}



图片.png


正如上面的效果所示,卡片组件可以随着其容器(.card__container)宽度自动变化,在窄屏下效果看上去还不错,但在宽屏下,效果看上去有点怪怪的。不过不用担心,这仅是最初的效果。我们期望的是通过容器查询的特性,在容器不同断点下改变卡片组件的布局。按照前面所介绍的,我们需要先创建一个包含性上下文,即在 .card__container 上使用 container 显式声明该元素是一个包容性上下文。


.card__container {
  container: inline-size;
}


效果如下:


图片.pngimage.gif


 Untitled  @airen  CodePen (地址:https://codepen.io/airen/pen/MWrXNGM (地址:https://codepen.io/airen (地址:https://codepen.io/)

可以在上面示例中尝试拖动卡片右下角滑块改变卡片容器宽度,你将看到的效果如下:



图片.png


有了这样一个卡片组件之后,如果将其放在不同的位置,即使是同一页面,同一视窗断点下,也会根据其容器断点自动匹配最为适合的布局(或UI效果)。比如:


image.gif图片.png


 Untitled  @airen  CodePen (地址:https://codepen.io/airen/pen/WNdKgMK (地址:https://codepen.io/airen (地址:https://codepen.io/)

尝试调整上面示例中视窗的大小:


图片.pngimage.gif


  • 媒体查询 vs. 容器查询



通过上面的示例的介绍,我想你对容器查询特性已经有了一个较清晰的认识了。从使用角度来看,容器查询和媒体查询是非常的相似,那么有人可能会问,有了容器查询是不是就不再需要媒体查询特性了呢?在回答这个问题之前,我们简单的来看两者的差异。



众所周知,媒体查询查询的浏览器视窗宽度(当然还有其他查询特性),而容器查询查询的是组件其父容器(具有包含性上下文的祖先元素)的宽度(或样式)。下图可能可以清晰的阐述两者的差异:


image.gif图片.png



就我个人认为,两者不是谁替代谁的关系,更应该是两者共存的关系。容器查询特性的出现,我们可以不再局限于视窗断点来调整布局或UI样式,还可以基于容器断点来调整布局或UI。换句话说,媒体查询是一种宏观的布局(Macro Layout),可以用于整体页面布局;而容器查询可以调整组件的每个元素,创建了一种微观的布局(Micro Layout)。



图片.pngimage.gif


  • 容器查询解决的是什么问题?



众所周知,响应式设计的概念的核心是 CSS 媒体查询的出现,它允许开发者根据浏览器视窗的尺寸来设置各种样式规则。也正因此,响应式设计和CSS媒体查询开启了更多的 Web 布局解决方案,以及多年来围绕响应视窗尺寸创建的最佳实践。而且,近些年来,设计系统和组件库也得到了更广泛的普及。对于更多开发者而言,更大的期望是:



一次建成,随地部署!



这也意味着一个单独开发的 Web 组件可以在任何情况下工作,以使建立复杂的界面更加有效和一致。只不过,这些组件会组合在一起,形成一个Web页面或Web应用界面。目前,在只有媒体查询的情况下,往往需要额外的一层来协调跨视窗大小变化的组件的突变。在这些情况下,你可能不得不在更多的断点下使用更多的类名来设置不同的样式规则。甚至更惨的是,即使这样做仍然很多情况之下也无法达到最理想的UI表面。



很多时候,响应式Web设计不是关于浏览器视窗尺寸而是关于容器的尺寸大小,比如:



image.gif图片.png


庆幸的是,CSS容器查询的出现,使我们超越了只考虑浏览器视窗尺寸的范围,并允许任何组件或元素对定义的容器尺寸做出响应。因此,虽然你可能仍然使用响应式来给Web页面布局,但Web页面的任何一个组件都可能通过容器查询来定义自己的样式变化。然后,它可以根据它是在一个窄的还是宽的容器中显示,来调整它的样式。


容器查询使我们不再只考虑浏览器视窗尺寸大小,而是允许任何组件或元素对定义的容器尺寸做出响应!


也就是说,有了CSS容器查询,你就能以一种非常精确和可预测的方式定义一个组件的全部样式。


图片.png


  • 设计时考虑容器查询



虽然响应式设计给Web设计师带来了更多的可有性,但响应式设计还是有很多的局限性。对于Web设计师而言,更期待的是能够根据组件容器尺寸来提供不同的设计风格。依旧拿卡片组件来举例:



图片.png


也就是说,CSS容器查询特性来了之后,作为一名Web设计师,在设计Web页面(或组件)时,就需要基于容器尺寸考虑如何设计。这样一来,可以向Web开发人员提供组件的细节和变化,Web开发人员也可以基于这些细节进行编码(进行开发)。


不过,这并不意味着容器查询特性之后响应式设计是就失去了意义。在未来,容器查询和响应式设计是共存的,简单地说,Web设计师在设计组件时可能会将组件分为以下几个部分:

  1. 基于视窗(CSS媒体查询)
  2. 基于容器(CSS容器查询)
  3. 通用型(不受影响的组件)


比如:

图片.png



相关文章
|
1月前
|
编解码 前端开发 JavaScript
构建高效响应式Web界面:现代前端框架的比较
【4月更文挑战第9天】在移动设备和多样屏幕尺寸盛行的时代,构建能够适应不同视口的响应式Web界面变得至关重要。本文深入探讨了几种流行的前端框架——Bootstrap、Foundation和Tailwind CSS,分析它们在创建响应式设计中的优势与局限。通过对比这些框架的栅格系统、组件库和定制化能力,开发者可以更好地理解如何选择合适的工具来优化前端开发流程,并最终实现高性能、跨平台兼容的用户界面。
|
2月前
|
前端开发 开发者 UED
构建响应式Web界面:Flexbox的力量
【2月更文挑战第25天】 在现代网页设计中,创建能够适应不同屏幕尺寸的布局是至关重要的。Flexbox,一种CSS布局模式,提供了强大的工具来轻松地设计和调整灵活的响应式界面。本文将深入探讨Flexbox的核心概念,并通过实例展示如何使用它来构建美观、灵活且易于维护的响应式Web界面。
|
7天前
|
SQL 分布式计算 资源调度
常用大数据组件的Web端口号总结
这是关于常用大数据组件Web端口号的总结。通过虚拟机名+端口号可访问各组件服务:Hadoop HDFS的9870,YARN的ResourceManager的8088和JobHistoryServer的19888,Zeppelin的8000,HBase的10610,Hive的10002。ZooKeeper的端口包括客户端连接的2181,服务器间通信的2888以及选举通信的3888。
19 2
常用大数据组件的Web端口号总结
|
13天前
|
移动开发 JavaScript 前端开发
【专栏:HTML进阶篇】HTML模板与Web组件:可复用的网页元素
【4月更文挑战第30天】HTML模板和Web组件提升网页开发效率和可维护性。HTML模板,如&lt;template&gt;元素和服务器端模板引擎,用于创建可复用的HTML结构。Web组件是自定义的HTML元素,结合影子DOM和模板,实现封装的可重用组件。两者助力构建高效、现代的网页和网站。
|
1月前
|
编解码 前端开发 开发者
构建响应式Web界面:Flexbox与Grid布局的深度对比
【4月更文挑战第4天】 在现代前端开发中,构建灵活且响应式的用户界面是至关重要的。随着移动设备浏览量的增加,能够适应不同屏幕尺寸和分辨率的布局技术变得必不可少。Flexbox和Grid是CSS提供的两种强大的布局机制,它们各自以独特的方式解决了响应式设计的挑战。本文将深入探讨Flexbox和Grid的核心概念、使用场景和性能考量,为开发者提供在面对不同布局需求时做出明智选择的依据。
|
2月前
|
编解码 前端开发 开发者
构建响应式Web界面:Flexbox的力量
【2月更文挑战第28天】 在现代网页设计中,创建能在不同设备上保持一致性和功能性的响应式界面是至关重要的。Flexbox,一个CSS布局模块,为前端开发者提供了强大工具来轻松实现灵活的布局设计。本文将深入探讨Flexbox的核心概念、使用场景以及如何通过它来优化响应式设计流程。
|
2月前
|
前端开发 开发者 UED
构建响应式Web界面:Flexbox与Grid布局的深度解析
【2月更文挑战第28天】 在现代前端开发中,打造灵活且适应不同屏幕尺寸的用户界面是至关重要的。随着移动设备的普及,响应式设计已经成为网页制作不可或缺的一部分。本文将深入探讨两种强大的CSS布局模块——Flexbox和Grid,它们如何简化布局创建过程,并赋予设计师更大的灵活性去构建动态和流畅的响应式界面。通过对这两种技术的比较、使用场景分析以及代码示例,读者将能够更好地理解何时以及如何使用这些工具来提升前端项目的质量和效率。
22 0
|
2月前
|
编解码 前端开发 开发者
构建响应式Web界面:Flexbox布局的全面指南
【2月更文挑战第28天】 在当今多变的设备屏幕尺寸和分辨率中,创建一个能够适应不同视口的响应式Web界面至关重要。本文深入探讨了CSS Flexbox布局模块,它是一种设计灵活且强大的方式来创建复杂的响应式布局。我们将透过概念解析、关键属性讲解以及实际案例分析,帮助前端开发者掌握Flexbox的核心原理和应用技巧,以实现流畅的页面布局调整和优化用户体验。
|
2月前
|
前端开发 测试技术 开发者
构建响应式Web界面:Flexbox布局的力量
【2月更文挑战第24天】在现代Web开发中,创建能够适应不同屏幕尺寸的响应式界面已成为一项标准实践。Flexbox,一个CSS模块,因其灵活性和强大功能在前端开发者中广受欢迎。本文将深入探讨Flexbox的核心概念、常见用例以及如何利用它来构建美观、灵活且易于维护的响应式布局。通过实例演示,读者将学会如何有效地应用Flexbox技术,提升前端项目的质量和用户体验。
|
2月前
|
开发框架 Dart 前端开发
构建响应式Web界面:Flutter的跨界前端技术
【2月更文挑战第23天】随着移动互联网的飞速发展,响应式Web设计成为现代前端开发的重要趋势。在众多框架中,Google推出的Flutter以其高效的渲染性能、跨平台能力及丰富的组件生态,为前端开发者带来了新的选择。本文将深入探讨如何利用Flutter进行高效、美观的响应式界面构建,同时剖析其与传统前端技术的差异和优势。