如何正确使用:has和:nth-last-child

如何,正确,使用,has,nth,last,child · 浏览次数 : 117

小编点评

**文章简介** 文章介绍如何使用 CSS 样式查询来动态改变布局,以及如何使用 :has 和 :nth-last-child 等语法来检测和改变 logo 的尺寸。 **CSS样式** 以下 CSS样式用于动态调整 logo 的尺寸: ```css .post-author:has(img:nth-last-child(n + 2)) { --multiple-avatars: true; } ``` **技术** * CSS样式查询 * :has 和 :nth-last-child 语句 * :multiple-avatars 变量 **应用** * 动态调整 logo 的尺寸 * 控制多个 logo 的大小和排列 * 处理 Logo 的齐放问题 **示例** 以下代码展示如何使用 :nth-last-child 和 :has 语句来动态调整 logo 的尺寸: ```css ul:has(li:nth-last-child(n + 8)) img { max-width: 160px; height: 35px; } ``` **结论** 文章介绍如何使用 CSS样式查询来动态调整布局,以及如何使用 :has 和 :nth-last-child 等语法来检测和改变 logo 的尺寸。

正文

我们可以用CSS检查,以了解一组元素的数量是否小于或等于一个数字。例如,一个拥有三个或更多子项的grid。你可能会想,为什么需要这样做呢?在某些情况下,一个组件或一个布局可能会根据子元素的数量而改变。

这在CSS中已经存在很多年了,但现在通过CSS :has,它变得更加强大。我们可以把nth-last-child选择器和:has结合起来,以达到神奇的效果!你没听错。

在这篇文章中,我将强调几个例子,说明我们可以将一个CSS选择器和:has结合起来,形成一个有条件的组件/布局状态。

总览

  • 介绍:nth-last-child

  • CSS中的数量查询限制

    • 不可能根据元素的数量来设计父元素的样式
    • 让它们在不同的视口尺寸上奏效
    • 为了控制间距要付出更多
  • 使用案例

    • 基于子项数量而变化的Grid
    • 动态标题布局
    • 动态新闻部分
    • 模态框操作
    • 用户头像
    • 时间轴
    • logo网格
  • 总结

介绍:nth-last-child

这篇文章的主要要素之一是:nth-last-child伪类。我们可以使用该选择器来模拟计算子元素。

来看看它是如何工作的。我将尽可能用直白的话来解释。

请看下图:

我们有一个五个卡片的列表。我们将用这个例子来证明我们可以用:nth-last-child做什么。

在下列CSS中,n + 3意味着:

li:nth-last-child(n + 3) {
    /* styles */
}

从末端选择前三项,从第三项开始计算。

让我们仔细看看。首先,我们需要从末端计算三个项。这样一来,第三项实际上就是我们从末端开始计算的第一项。

我们从第三项算起直到最后,这里是被选中的项:

CSS中的数量查询限制

我们可以使用:nth-last-child作为CSS的数量查询。

请看下图:

我们有一个信息清单,当我们有5个或更多的项时,它的显示方式会不同。

<ul>
   <li></li>
   <li></li>
   <li></li>
   <!-- more items -->
</ul>
li {
    /* default styles */
}

/* If the list has 5 or more items */
li:nth-last-child(n + 5),
li:nth-last-child(n + 5) ~ li {
  width: 50%;
  display: inline-block;
  border-bottom: 0;
}

虽然这很有效,但在某些方面仍然有点局限性。

不可能根据元素的数量来设计父元素的样式

想象一下,当有5个或更多的项时,我们需要为每个<li>添加display: flex。我们不能用 :nth-last-child 伪类选择器来做这个。

原因是,添加display: flex将迫使每个项留在自己的行中,这与要实现的设计不一致。

li:nth-last-child(n + 5),
li:nth-last-child(n + 5) ~ li {
  width: 50%;
  display: flex;
  flex-direciton: column;
}

我们可以用display: inline-flex来解决这个问题,但对我来说,这仍然不是最佳解决方案。原因是,浏览器会考虑到HTML元素之间的间距,它们应该是这样的:

<ul>
   <li></li><li></li><li></li>
   <!-- more items -->
</ul>

如果我们不这样做,display: inline-flex的效果将与display: flex相同。解决这个问题的一个方法是将宽度减少1%。

li:nth-last-child(n + 5),
li:nth-last-child(n + 5) ~ li {
  width: 49%;
  display: flex;
  flex-direciton: column;
}

让它们在不同的视口尺寸上奏效

如果没有对父类进行控制的能力,就不能那么直接地对列表的布局进行设计。例如,当容器或视口宽度较小时,我们需要每行显示1个项。

为了控制间距要付出更多

当有3个或更少的项时,间距是水平的,而当有5个或更多时,间距是垂直的。我们可以通过将页边距从水平方向翻转到垂直方向,或者通过使用CSS gap与Flexbox来手动管理。但是,在这种情况下,我们又不得不使用inline-flex

CSS :nth-last-child伪类是构建条件性布局的关键。通过将它与CSS :has选择器相结合,我们可以检查一个父元素是否至少有特定数量的项,并对其进行相应的样式设计。这种可能性是无穷无尽的!

使用案例

基于子项数量而变化的Grid

当我们需要基于子项数量而更改gird布局时,这在目前的CSS中是不可能的。在CSS的grid中,我们可以使用minmax()基于可用空间来动态改变grid。

下面是我对CSS网格minmax()的看法:

.list {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 1rem;
}

结果看起来是这样:

这一点都不完美。我们没有太多的控制,因为我们需要调整minmax()中的150px的值。当有4个或更少的项时,它可以很好地工作,而当有5个或更多的项时就会出现问题。

解决办法是什么?我们可以用CSS :has检查是否有超过5个项目或更多,并在此基础上改变minmax()的值。

/* default grid */
.list {
    --item-size: 200px;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(var(--item-size), 1fr));
    gap: 1rem;
}

/* If the grid has 5+ items, change the --item-size width to 150px */
.list:has(li:nth-last-child(n + 5)) {
    --item-size: 150px;
}

我只是改变了--item-size变量,使代码更容易阅读,并避免重复。

动态标题布局

在下图中,我们有一个标题,当导航项有4个或更多时,应该改变其布局。通过CSS :has:nth-last-child,我们可以检测并改变布局。

.site-header:has(li:nth-last-child(n + 4)) {
    .site-header__wrapper > * {
        flex: initial;
    }

    .site-header__start {
        order: 2;
    }

    .site-header__middle {
        order: -1;
        text-align: start;
    }

    .site-header__end {
        margin-left: auto;
    }
}

以上是Sass的代码。如果用CSS写,可能看起来有点多。

.site-header:has(li:nth-last-child(n + 4)) .site-header__wrapper > * {
    flex: initial;
}

.site-header:has(li:nth-last-child(n + 4)) .site-header__start {
    order: 2;
}

.site-header:has(li:nth-last-child(n + 4)) .site-header__middle {
    order: -1;
    text-align: start;
}

.site-header:has(li:nth-last-child(n + 4)) .site-header__end {
    margin-left: auto;
}

我们能做得更好吗?可以。但这还没有得到很好的支持(目前来说)。我们可以添加一个布尔CSS变量,当标题有4个或更多的项目时,它将被切换,然后使用样式查询来改变标题。

.site-header:has(li:nth-last-child(n + 4)) {
    --layout-2: true;
}

有了这个,当导航项有4个或更多时,我们设置变量--layout-2

/* This will only works if the --layout-2 CSS variable is set */
@container style(--layout-2: true) {
  .site-header__wrapper {
    > * {
      flex: initial;
    }
  }

  .site-header__start {
    order: 2;
  }

  .site-header__middle {
    order: -1;
    text-align: start;
  }

  .site-header__end {
    margin-left: auto;
  }
}

动态新闻部分

下面是一个新闻部分的设计,当项目数为3或更多时,它应该改变其布局。

通过组合CSS的:has:nth-last-child,我们可以创建一个切换的CSS变量,它将被一个样式查询所检查。

首先,我将假设默认的卡片样式是水平的。

<div class="layout">
    <article class="card"></article>
    <article class="card"></article>
    <article class="card"></article>
</div>
.layout {
  display: grid;
  grid-gap: 1rem;
}

.card {
  display: flex;
  gap: 1rem;
  align-items: center;
}

然后,我需要检查.card元素的数量。

.layout:has(.card:nth-last-child(n + 4)) {
  --layout-4: true;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
}

现在,我们有一个CSS变量--layout-4,只有当我们有4个或更多的项时才会被切换。我们可以用一个样式查询来检查,并相应地更新.card的样式。

@container style(--layout-4: true) {
    .card {
        flex-direction: column;
    }

    .card__thumb {
        flex: 1;
        width: 100%;
        aspect-ratio: 4 / 3;
    }
}

模态框操作

在一个设计系统中,我们可能需要根据我们有多少个操作来动态地控制模态操作的排列。

请看下图:

比如说,如果只有一个操作,它应该居中。否则,向右对齐它们。

下面是CSS:

.modal__footer {
    display: flex;
    justify-content: center;
    gap: 0.5rem;
}

/* If there are 2 buttons or more */
.modal__footer:has(a:nth-last-child(n + 2)) {
    justify-content: flex-end;
}

很简单,对不对。

用户头像

在编辑网站上,一篇文章可能由多个作者撰写。一个常见的模式是,当我们有多个作者时,用负间距堆叠作者的图像。

仅仅通过使用数量查询,我们就可以最低限度的实现,也就是:

  • 添加负间距(互相堆叠头像)。
  • 当有多个头像时,缩小头像的尺寸。
img:nth-last-child(n+2) ~ img {
    border: 2px solid #fff;
    margin-left: -0.25rem;
    width: 30px;
    height: 30px;
}

上面的方法可行,但它有局限性。如果我们想对容器本身进行样式设计呢?那么,这就是CSS :has变得强大的地方。

首先,我们需要检查并切换CSS变量:

.post-author:has(img:nth-last-child(n + 2)) {
    --multiple-avatars: true;
}

如果CSS变量为true,就为多个头像应用下面的样式:

@container style(--multiple-avatars: true) {
    .avatars-list {
        display: flex;
        background-color: #efefef;
        padding: 8px 12px;
        border-radius: 50px;
    }

    img:not(:first-child) {
        border: solid 2px #fff;
        margin-left: -0.25rem;
    }
}

时间线

另一个有趣的例子是时间线组件,它的CSS效果很好。

在这个例子中,我想让时间线在有4个或更多项时,从垂直列表切换到交替式。

首先,使用:nth-last-child:has

.timeline-wrapper:has(.timeline__item:nth-last-child(n + 4)) {
    --alternating: true;
}

如果符合上述条件,将采用以下CSS:

@container style(--alternating: true) {
    /* Alternating timeline styles. */
}

在这里使用样式查询的有用之处在于,我们可以在另一个页面上重复使用这些样式。它不一定非得是一个有条件的CSS。

我可能会做这样的事情:

.timeline-wrapper--page-10 {
    --alternating: true;
}

请不要介意.timeline-wrapper--page-10,这是个故意的随机类名。这个CSS变量可以被分配到我们想要的任何地方,而且这个CSS开箱即用。

只要写一次,就能在很多情况下发挥作用。

logo网格

在CSS中,要处理的一个棘手问题是对齐多个标识,并确保它们都看起来不错。通过条件性CSS,我们可以检测logo的数量,并将其尺寸缩小一些。

ul:has(li:nth-last-child(n + 8)) img {
    max-width: 160px;
    height: 35px;
}

总结

这是我所做的有趣的文章之一。结合现代的CSS功能可以让我们以令人兴奋的新方式来构建布局,这篇文章的例子也不例外。

根据项目的数量来改变样式可能不是一次性的用法,它可以被提取到不同的用例中。通过使用样式查询,我们可以只写一次,并在任何地方重用它们。

以上就是本文的全部内容,如果对你有所帮助,欢迎点赞、收藏、转发~

与如何正确使用:has和:nth-last-child相似的内容:

如何正确使用:has和:nth-last-child

我们可以用CSS检查,以了解一组元素的数量是否小于或等于一个数字。例如,一个拥有三个或更多子项的`grid`。你可能会想,为什么需要这样做呢?在某些情况下,一个组件或一个布局可能会根据子元素的数量而改变。 这在CSS中已经存在很多年了,但现在通过CSS `:has`,它变得更加强大。我们可以把`nt

如何正确使用 ThreadLocal,你真的用对了吗?

本文主要从源码的角度解析了 ThreadLocal,并分析了发生内存泄漏的原因及正确用法,最后对它的应用场景进行了简单介绍。

如何正确使用多线程和锁机制来构建可靠的程序

通过阅读本文,读者将了解到多线程和锁机制在并发编程中的重要性,以及如何避免常见的并发问题,确保程序的安全性和可靠性。

nuxt3正确使用keepalive页面缓存组件缓存

最近使用 nuxt@3.x 版本做SEO优化项目比较多,之前也踩坑过,所以记录一下在 nuxt3 中路由缓存的正确使用方法,本人也之前在GitHub社区中提交过反馈问题,最后是在 3.8.2 版本解决了路由缓存问题。下面讲解如何正确使用keepalive做到页面缓存,组件缓存。 # 环境版本如下 n

[转帖]Redis命令DEL与UNLINK的区别,如何正确删除大Key!

https://www.itxm.cn/post/47824.html 背景 在这篇文章中做过使用del命令删除大key的实验,结果是del命令随着key的增大,主线程阻塞的时间就越长。 这与之前看redis5.0.8版本的代码中关于多线程删除操作的感官不符,于是决定先查看redis关于删除操作的代

在spring boot3中使用native image

简介 在之前spring boot3文章中我们介绍了,spring boot3的一个重要特性就是支持把spring boot3的应用编译成为GraalVM的Native Image。 今天我们用具体的例子来给大家演示一下如何正确的将spring boot3的应用编译成为native image。 安

如何使用iptables防火墙模拟远程服务超时

# 前言 超时,应该是程序员很不爱处理的一种状态。当我们调用某服务、某个中间件、db时,希望对方能快速回复,正确就正常,错误就错误,而不是一直不回复。目前在后端领域来说,如java领域,调用服务时以同步阻塞调用为主,此时一般会阻塞当前线程,等待结果。如果我们设置了超时时间还好,一段时间等不到就报错了

【Azure API 管理】APIM如何实现对部分固定IP进行访问次数限制呢?如60秒10次请求

问题描述 使用Azure API Management, 想对一些固定的IP地址进行访问次数的限制,如被限制的IP地址一分钟可以访问10次,而不被限制的IP地址则可以无限访问? ChatGPT 解答 最近ChatGPT爆火,所以也把这个问题让ChatGPT来解答,然后人工验证它的回答正确与否? 根据

JUC中的AQS底层详细超详解

摘要:当你使用java实现一个线程同步的对象时,一定会包含一个问题:你该如何保证多个线程访问该对象时,正确地进行阻塞等待,正确地被唤醒? 本文分享自华为云社区《JUC中的AQS底层详细超详解,剖析AQS设计中所需要考虑的各种问题!》,作者: breakDawn 。 java中AQS究竟是做什么的?

JavaScript 如何验证 URL

前言 当开发者需要为不同目的以不同形式处理URL时,比如说浏览器历史导航,锚点目标,查询参数等等,我们经常会借助于JavaScript。然而,它的频繁使用促使攻击者利用其漏洞。这种被利用的风险是我们必须在我们的JavaScript应用程序中实现URL验证的原因。 URL验证检查URL是否遵循正确的U