7

CSS新规范:样式查询

 1 year ago
source link: https://www.fly63.com/article/detial/12286
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

最近,Chrome团队发布了对一个新的css规范的实验性支持,即样式查询。简而言之,它让我们查询容器的样式,而不是只查询尺寸。在查询容器尺寸不够的情况下,这可能很有帮助。

CSS 容器查询

介绍样式查询之前,我们先来回顾容器查询。

CSS 容器查询(Container Queries)是一项新的 CSS 功能,允许开发人员根据元素的大小来应用样式。这意味着,开发人员可以为不同大小的设备或浏览器窗口应用不同的样式,而无需使用媒体查询或使用 JavaScript 来检测设备大小。

63b244a5ca3a5.jpg

我们来看看一个例子:

.o-grid__item {
  container-type: inline-size;
}

.c-article {
  /* The default style */
}

@container (min-width: 400px) {
  .c-article {
    /* The styles that will make the article horizontal**
    ** instead of a card style.. */
  }
}

首先,我们需要在定义 container-type。然后,使用 @container开始查询。一旦满足了这个条件,CSS将应用于该容器内的组件。

简单地说,样式查询让我们查询一个容器的CSS属性或CSS变量。

样式查询仍然是试验性的,目前只在Chrome Canary中实现。要测试它们,请进入chrome://flags并激活 "Experimental Web Platform features"的切换。

例如,我们可以检查容器是否有 display: flex,并在此基础上为子元素设计样式。

.page-header {
  display: flex;
}

@container style(display: flex) {
  .page-header__start {
    flex: 1;
    display: flex;
    align-items: center;
    border-right: 1px solid lightgrey;
  }
}

理想情况下,上述做法应该是可行的,但目前Chrome Canary中的样式查询原型仅局限于CSS变量。样式查询预计将在Chrome M111中出现。

现在,我们可以检查变量--boxed: true是否被添加到容器中,如果是,我们可以在此基础上改变子元素的样式。

请看下图:

63b244b1ba330.jpg

请注意,容器查询和样式查询的主要区别在于,前者是针对大小的查询,后者是针对样式的查询。

.card-container {
  --boxed: true;
}

@container style(--boxed: true) {
  .card {
    /* boxed styles */
  }
}

在探讨我们可以在哪里使用样式查询之前,我们先来回答大家常见的一个问题:样式查询能解决什么问题?容器查询还不够吗?

这是一个好问题。在容器查询中,我们可以根据一个组件的父级宽度来控制它的样式,这非常有用。不过,在某些情况下,我们可能不需要查询尺寸,而是想查询一个容器的计算样式。

为了让你有更好的了解,请看下图:

63b244b8db488.jpg

这是一篇来自CMS的文章正文。我们有一个默认的图片样式和另一个看起来有特色的样式。

下面是对应的代码

<figure>
  <img src="cheesecake.jpg" alt="" />
  <figcaption>....</figcaption>
</figure>
figcaption {
  font-size: 13px;
  padding: 4px 8px;
  background: lightgrey;
}

当我们开始对特色的进行造型时,我们需要覆盖上述内容,并有一个CSS类,我们可以用它进行造型。

.featured-figure {
  display: flex;
  flex-wrap: wrap;
}

.featured-figure figcaption {
  font-size: 16px;
  padding: 16px;
  border-left: 3px solid;
  margin-left: -6rem;
  align-self: center;
}

当我们开始为突出显示的元素添加样式时,我们需要覆盖上述样式并定义一个 CSS 类,以便可以对其进行样式设置。

.featured-figure {
  display: flex;
  flex-wrap: wrap;
}

.featured-figure figcaption {
  font-size: 16px;
  padding: 16px;
  border-left: 3px solid;
  margin-left: -6rem;
  align-self: center;
}

很酷,这个方法行。我们能不能做得更好?是的!使用样式查询,我们可以在 figure 中添加 display: flex 或一个 CSS 变量 --featured: true,然后基于这个进行样式设置。

<figure>
  <img src="cheesecake.jpg" alt="" />
  <figcaption>....</figcaption>
</figure>
figure {
  container-name: figure;
  --featured: true;
}

/* Featured figure style. */
@container figure style(--featured: true) {
  img {
    /* Custom styling */
  }

  figcaption {
    /* Custom styling */
  }
}

如果 --featured: true 不存在,我们将默认使用基本 figure 设计。我们可以使用 not 关键字来检查 figure 是否没有 display: flex。

/* Default figure style. */
@container figure not style(--featured: true) {
  figcaption {
    /* Custom styling */
  }
}

要知道的几个细节默认情况下,每个元素都是样式容器

所以根本不需要定义一个样式容器。默认情况下,它就在那里。

我们不能用类名来解决这个问题吗?

是的,我们可以。使用样式查询的目的是使 CSS 更易读并更容易修改。上述逻辑可以作为一个组件 CSS 写出,而无需将所有这些样式添加到条件类中。

事例:https://codepen.io/shadeed/pen/ZERZxzG/a583817975bae6b78308acb6939a9a54?editors=1100

减少 CSS 特定性问题

我喜欢使用样式查询的原因是,它将减少 CSS 特定性,因为我们将不太依赖 CSS 变化类或 html 数据属性来对组件变化进行样式设置。

在下面的 CSS 中,我们为 section 添加了基本样式。没有什么特别的。

.section {
  background-color: lightgrey;
}

.section__title,
.section__desc {
  color: #222;
}

我们需要一种方法来为它设置不同的主题,因此我们使用了变化类。

.section--dark {
  background-color: #222;
}

.section--dark .section__title,
.section--dark .section__desc {
  color: #fff;
}

使用样式查询,我们可以在 .section 组件周围使用容器,然后在不在 CSS 中创建更多特定性的情况下为标题和描述打标签。

@container style(--theme: dark) {
  .section {
    background-color: #222;
  }

  .section__title,
  .section__desc {
    color: #fff;
  }
}

这看起来干净多了。

接下来,我们探索几种样式查询可能有帮助的使用情况。

使用情况和示例

基于上下文的样式设置

63b244ca95c57.jpg

这是一种常见的使用情况,在同一包装器中我们使用了相同的组件但用法不同。在右侧,我们有一个文章组件,可能包含一个数字或不包含。

目前,我们可能会使用一个新的 CSS 类来解决样式设置问题,或者可能在文章组件本身上使用变化类。

.most-popular {
  counter-reset: list;
}

.most-popular article {
  /* custom styling */
}

或者我们可能在 HTML 中使用 data 属性。

.most-popular[>"true"] {
  counter-reset: list;
}

.most-popular[>"true"] .article {
  /* custom styling */
}

使用 CSS 样式查询,我们可以在父元素中添加一个 CSS 变量,并根据此对文章进行样式设置。看看这个:

.most-popular {
  --counter: true;
}

@container style(--counter: true) {
  .articles-list {
    counter-reset: list;
  }

  .article {
    display: flex;
    align-items: flex-start;
  }

  .article:before {
    counter-increment: list;
    content: counter(list);
  }
}

我们甚至不需要在文章组件上使用变化类。也不需要使用 CSS 嵌套。

示例:https://codepen.io/shadeed/pen/LYBYYWP/b53e0baa891dc48b0689e1f926f89b96?editors=1100

组件级的主题切换

我们构建的一些组件根据特定条件需要使用不同的主题。在下面的示例中,我们有一个包含不同统计组件的仪表板。

基于包装器,我们需要切换组件的主题。

63b244d3b038e.jpg

目前,我们可以使用特殊类根据它们的容器为自定义统计组件添加样式。

.special-wrapper .stat {
  background-color: #122c46;
}

.special-wrapper .stat__icon {
  background-color: #2e547a;
}

.special-wrapper .stat__title {
  background-color: #b3cde7;
}

上面的做法一点也没有错,也不坏,但因为我们嵌套了CSS,所以增加了特殊性。让我们探讨一下如何用样式查询来实现上述内容。

首先,我们需要在特殊包装器上定义一个切换按钮。然后,我们可以检查该开关是否处于激活状态,并对状态组件进行相应的设计。

.special-wrapper {
  --theme: dark;
  container-name: stats;
}

@container stats style(--theme: dark) {
  .stat {
    /* Add the dark styles. */
  }
}
63b244dedb200.jpg

在这种情况下,样式查询的有用之处在于,将上述样式放在 CSS 中的一个地方是有意义的。

/* stat.css */
.stat {
  /* default styling */
}

@container stats style(--theme: dark) {
  .stat {
    /* custom styling */
  }
}

在这个例子中,我们有一组用户的头像。我们需要根据在父代上设置的一个CSS变量,以不同的方式来布置它们。我从Atlassian设计系统中挑选了这个例子。

63b244e83892d.jpg
<div class="avatars-wrapper">
  <div class="avatars-list">
    <div class="avatar"></div>
    <!-- more avatars -->
  </div>
</div>

在CSS中,我给容器添加了一个名字,并定义了--appearance: default变量。

.avatars-wrapper {
  container-name: avatars;
}

.avatars-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
}

有了这个,我们就可以使用样式查询来改变基于--appearance变量的布局。

@container avatars style(--appearance: stack) {
  .avatar {
    box-shadow: 0 0 0 2px #fff;
  }

  .avatar + .avatar {
    margin-inline-start: -0.5rem;
  }
}

@container avatars style(--appearance: grid) {
  .avatars-list {
    gap: 0.5rem;
    max-width: 200px;
  }
}

地址:https://codepen.io/shadeed/pen/KKeYLXG/464bd92260d290df58e1387c71d1d30f?editors=1100

条件装饰样式

在某些情况下,我们可能需要根据文本元素在 HTML 中的位置为其添加条件装饰样式。

63b244f160710.jpg

标题和段落下方有一个旋转的背景效果。这是通过伪元素实现的:

<div class="content">
  <h2><!-- Title here --></h2>
  <p><!-- Description --></p>
</div>

要对它们进行样式设置,我们可以使用 CSS 变量并检查它是否已切换,然后相应地添加样式。在示例中,:after 伪元素被添加到 .content 容器的每个子元素。

.content {
  --decorated: true;
}

@container style(--decorated: true) {
  :after {
    content: "";
    position: absolute;
    inset: 0;
    background-color: var(--dec-color, green);
    opacity: 0.1;
    z-index: -1;
    transform: rotate(-1.5deg);
  }
}
63b244faf3d0f.jpg

地址:https://codepen.io/shadeed/pen/abKxgyW/a0e0639a118fac1b781a5de18c598789

RTL 样式:卡片组件

写 RTL 样式时,第一步是在 <html> 元素中添加 dir=rtl。一旦添加,每个元素的 direction CSS 属性都会变为 direction: rtl。

随着逻辑属性的兴起,我们不需要完全重写 CSS。考虑以下示例:

.item {
  margin-inline-start: 1rem;
}

对于从左到右的布局,上述内容将计算为 margin-left。对于从右到左的布局,它将是 margin-right。很酷,对吧?但是我们仍然没有检查渐变方向的逻辑 CSS。

样式查询可以用于解决这个问题。考虑以下示例:

63b245020a861.jpg

我们有一个组件,由两个元素组成,这两个元素都应根据文档改变方向:

  • 渐变:对于 LTR 布局,它从左到右。
  • 箭头方向:指向右边。
  • 上述内容无法使用逻辑 CSS 控制。目前,我们这样做:
html[dir="rtl"] .card {
  background: linear-gradient(to left, ...);
}

html[dir="rtl"] .card__cta {
  transform: scaleX(-1);
}

使用样式查询,我们可以查询容器并检查direction是否等于 rtl,并根据此对样式进行更改。

.card {
  --bg-angle: to right;
  background: linear-gradient(var(--bg-angle), #5521c3, #5893eb);
}

@container card style(direction: rtl) {
  .card {
    --bg-angle: to left;
  }

  .card__cta {
    transform: scaleX(-1);
  }
}

请注意,样式查询的当前原型不支持 style() 查询中的 CSS 属性。因此,我在示例中使用了 CSS 变量。

这是我在 bbc.com 上发现的真实问题。最初,我们有以下新闻组件。

63b2450a84203.jpg

根据其容器,样式应略有改变。考虑以下图:

63b2450fcb76d.jpg

注意组件现在有两个修改:

  • 白色背景。
  • 标题和描述容器四周填充。
  • 这是 BBC.com 上 CSS 的样式:
.media--padded {
  background: #fff;
}

.media--padded .media__content {
  padding: 0.75rem 0.75rem 3rem 0.75rem;
}

我们如何通过样式查询来解决这个问题呢?很简单,我们需要一种方法来告诉组件,如果你住在这个容器内,卡片的样式应该被填充。

.special-container {
  --card--padded: true;
}

@container style (--card-padded: true) {
  .media {
    background: #fff;
  }

  .media__content {
    padding: 0.75rem 0.75rem 3rem 0.75rem;
  }
}

CSS 样式查询是 CSS 的强大补充。我迫不及待地想看看社区中的其他人会用它们做什么。哦,我也忍不住想在 iShadeed 实验室中为样式查询创建一个新目录。敬请期待!

原文:https://ishadeed.com/article/css-container-style-queries/

链接: https://www.fly63.com/article/detial/12286


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK