CSS的逻辑组合伪类

CSS 的逻辑组合伪类有 4 种,分别是::not()、:is()、:where()和:has()。

否定伪类:not()

:not 伪类选择器用来匹配不符合一组选择器的元素。由于它的作用是防止特定的元素被选中,它也被称为反选伪类(negation pseudo-class)。

也叫否定伪类,是在元素与括号里面的参数不匹配的时候,就会对这个伪类进行匹配。比如:

:not(span):{color:red}

这就会匹配不是 span 元素的其他所有元素,包括 html 和 body。

否定伪类:not()的几个特点:

  1. :not()的优先级是 0,因为它的优先级是由括号里面的参数来定的;
  2. :not()伪类可以同时判断多个选择器,比如input:not(:disabled):not(:read-only)
    {},表示匹配不属于禁用状态同时也不处于只读状态的 input 元素;
  3. not()支持多个表达式,比如:.cs-li:not(li, dd)
    {},还有另外一种写法:.cs-li:not(li):not(dd) {}。但是这两种写法,要考虑兼容性问题;
  4. :not()也支持选择符,比如:input:not(.a > .b) { border: red solid; };

有趣的是,在 MDN 介绍 :not 的页面,有这样一个例子:

/* Selects any element that is NOT a paragraph 选择任何非段落的元素 */
:not(p) {
  color: blue;
}

意思是,:not(p) 可以选择任何不是 p标签的元素。然而,上面的 CSS 选择器,在如下的 HTML 结构,实测的结果不太对劲。

<p>p</p>
<div>div</div>
<span>span</span>
<h1>h1</h1>

结果如下:
在这里插入图片描述

结果:not(p) 仍然可以选中 p 元素。尝试了多个浏览器,得到的效果都是一致的。

这是为什么呢?这是由于 :not(p) 同样能够选中 body,那么 body 的 color 即变成了 blue,由于 color 是一个可继承属性,p 标签继承了 body 的 color 属性,导致看到的 p 也是蓝色。

我们把它改成一个不可继承的属性,试试看:

/* Selects any element that is NOT a paragraph */
:not(p) {
   border: 1px solid;
}

再看下效果:
在这里插入图片描述
OK,这次 p 标签没有边框体现,没有问题!实际使用的时候,需要注意这一层继承的问题!

:not 的优先级问题

下面是一些使用 :not 需要注意的问题。

:not、:is、:where 这几个伪类不像其它伪类,它不会增加选择器的优先级。它的优先级即为它参数选择器的优先级。

并且,在 CSS Selectors Level 3,:not() 内只支持单个选择器,而从 CSS Selectors Level 4 开始,:not() 内部支持多个选择器,像是这样:

/* CSS Selectors Level 3,:not 内部如果有多个值需要分开 */
p:not(:first-of-type):not(.special) {
}
/* CSS Selectors Level 4 支持使用逗号分隔*/
p:not(:first-of-type, .special) {
}

与 :is() 类似,:not() 选择器本身不会影响选择器的优先级,它的优先级是由它的选择器列表中优先级最高的选择器决定的。

:not() 实战解析

来一个特别的例子:

在 W3 CSS selectors-4 规范 中,新增了一个非常有意思的 :focus-visible 伪类。

:focus-visible 这个选择器可以有效地根据用户的输入方式(鼠标 vs 键盘)展示不同形式的焦点。

有了这个伪类,就可以做到,当用户使用鼠标操作可聚焦元素时,不展示 :focus 样式或者让其表现较弱,而当用户使用键盘操作焦点时,利用 :focus-visible,让可获焦元素获得一个较强的表现样式。

看个简单的 Demo:

<button>Test 1</button>
<button>Test 2</button>
<button>Test 3</button>

<style>
button:active {
  background: #eee;
}
button:focus {
  outline: 2px solid red;
}
</style>

鼠标点击效果:
在这里插入图片描述
可以看到,使用鼠标点击的时候,触发了元素的 :active 伪类,也触发了 :focus伪类,不太美观。

但是如果设置了 outline: none 又会使键盘用户的体验非常糟糕。因为当键盘用户使用 Tab 尝试切换焦点的时候,会因为 outline: none 而无所适从。

因此,可以使用 :focus-visible 伪类改造一下:

button:active {
  background: #eee;
}
button:focus {
  outline: 2px solid red;
}
button:focus:not(:focus-visible) {
  outline: none;
}

看看效果,分别是在鼠标点击 Button 和使用键盘控制焦点点击 Button:
在这里插入图片描述
可以看到,使用鼠标点击,不会触发 :foucs,只有当键盘操作聚焦元素,使用 Tab 切换焦点时,outline: 2px solid red 这段代码才会生效。

这样,我们就既保证了正常用户的点击体验,也保证了无法使用鼠标的用户的焦点管理体验,在可访问性方面下了功夫。

值得注意的是,这里为什么使用了 button:focus:not(:focus-visible)这么绕的写法而不是直接这样写:

button:focus {
  outline: unset;
}
button:focus-visible {
  outline: 2px solid red;
}

解释一下,button:focus:not(:focus-visible) 的意思是,button 元素触发 focus 状态,并且不是通过 focus-visible 触发,理解过来就是在支持 :focus-visible 的浏览器,通过鼠标激活 :focus 的 button 元素,这种情况下,不需要设置 outline。

为的是兼容不支持 :focus-visible 的浏览器,当 :focus-visible 不兼容时,还是需要有 :focus 伪类的存在。

因此,这里借助 :not() 伪类,巧妙的实现了一个实用效果的方案降级。

这里有点绕,需要好好理解理解。

:not 兼容性

除去 IE 系列,:not 的兼容性已经非常之好了
在这里插入图片描述

任意匹配伪类:is()

:is()伪类,是把括号里面的选择都分配出去。语法如下:

:is(article, section) p {}

:is(.article[class], section) p {}

.some-class:is(article:not([id]), section) p {}

is 这个伪类最大的作用,就是在简化选择器。比如我们要设置多个 div 内的图片样式,样式代码如下:

.div-a > img, .div-b > img, .div-c > img, .div-d > img {   
 display: block;    
 width: 100%; 
 height: 100%;  
 border-radius: 50%;
}

通过 is 伪类来简化一下:

:is(.div-a,.div-b,.div-c,.div-d)>img{
   display: block; 
   width: 100%;
   height: 100%;  
   border-radius: 50%;
}

单个选择器可以包含任意数量的:is()伪类。

例如,下面的复杂选择器将绿色文本颜色应用于所有h1、h2和p元素,这些元素是具有section或.primary类的.secondary的子元素,并且不是article的第一个子元素:

article section.primary:not(:first-child) h1,
article section.primary:not(:first-child) h2,
article section.primary:not(:first-child) p,
article section.secondary:not(:first-child) h1,
article section.secondary:not(:first-child) h2,
article section.secondary:not(:first-child) p {
  color: green;
}

用is可以写为:

article section:not(:first-child):is(.primary, .secondary) :is(h1, h2, p) {
  color: green;
}

在这里插入图片描述

支持多层层叠连用

原本的 CSS 代码如下:

<div><i>div i</i></div>
<p><i>p i</i></p>
<div><span>div span</span></div>
<p><span>p span</span></p>
<h1><span>h1 span</span></h1>
<h1><i>h1 i</i></h1>

如果要将上述 HTML 中,div 和 p 下的 span 和 i 的 color 设置为 red,正常的 CSS 可能是这样:

div span,
div i,
p span,
p i {
    color: red;
}

有了 :is() 后,代码可以简化为:

:is(div, p) :is(span, i) {
    color: red;
}

当然,这个例子比较简单,看不出 :is() 的威力。下面这个例子就比较明显,这么一大段 CSS 选择器代码:

ol ol ul,     ol ul ul,     ol menu ul,     ol dir ul,
ol ol menu,   ol ul menu,   ol menu menu,   ol dir menu,
ol ol dir,    ol ul dir,    ol menu dir,    ol dir dir,
ul ol ul,     ul ul ul,     ul menu ul,     ul dir ul,
ul ol menu,   ul ul menu,   ul menu menu,   ul dir menu,
ul ol dir,    ul ul dir,    ul menu dir,    ul dir dir,
menu ol ul,   menu ul ul,   menu menu ul,   menu dir ul,
menu ol menu, menu ul menu, menu menu menu, menu dir menu,
menu ol dir,  menu ul dir,  menu menu dir,  menu dir dir,
dir ol ul,    dir ul ul,    dir menu ul,    dir dir ul,
dir ol menu,  dir ul menu,  dir menu menu,  dir dir menu,
dir ol dir,   dir ul dir,   dir menu dir,   dir dir dir {
  list-style-type: square;
}

可以利用 :is() 优化为:

:is(ol, ul, menu, dir) :is(ol, ul, menu, dir) :is(ul, menu, dir) {
  list-style-type: square;
}
不支持伪元素

注意::is()不能匹配::before和::after伪元素

不能写成:

div p:is(::before, ::after) {
    content: "";
    //...
}
:where()伪类

:where()伪类的功能和 is 是一样的,只是它的优先级一直都是 0,会忽略括号内参数的优先级。比如:

:where(.article, section) p {

}

优先级就是 p 标签的优先级。

:where()的零特异性对于CSS重置可能是实用的,当没有特定的样式可用时,CSS重置应用标准样式的基线。通常,重置会应用默认字体、颜色、填充和边距。

例如:

/* reset */
:where(h2) {
  margin-block-start: 1em;
}

:where(article :first-child) {
  margin-block-start: 0;
}

你现在可以覆盖任何CSS重置样式,而不管它的特殊性,也不需要更多的选择器或!important:

h2 {
  margin-block-start: 2em;
}
:is 和 :where 的区别

首先,从语法上,:is 和 :where 是一模一样的。它们的核心区别点在于 优先级。

来看这样一个例子:

<div>
    <p>where & is test</p>
</div>

css:

:is(div) p {
    color: red;
}
:where(div) p {
    color: green;
}

正常按我们的理解而言,:is(div) p 和 :where(div) p 都可以转化为 div p,由于 :where(div) p 后定义,所以文字的颜色,应该是 green 绿色,但是,实际的颜色表现为 color: red 红色:

这是因为,:where() 和 :is() 的不同之处在于,:where() 的优先级总是为 0 ,但是 :is() 的优先级是由它的选择器列表中优先级最高的选择器决定的。

组合、嵌套

CSS 选择器的一个非常大的特点就在于组合嵌套。:is 和 :where 也不例外,因此,它们也可以互相组合嵌套使用,下述的 CSS 选择器都是合理的:

/* 组合*/
:is(h1,h2) :where(.test-a, .test-b) {
  text-transform: uppercase;
}
/* 嵌套*/
.title:where(h1, h2, :is(.header, .footer)) {
  font-weight: bold;
}

简单总结下,:is 和 :where 都是非常好的分组逻辑选择器,唯一的区别在于:where() 的优先级总是为 0,而:is() 的优先级是由它的选择器列表中优先级最高的选择器决定的

关联伪类:has()

:has() 伪类接受一个选择器组作为参数,该参数相对于该元素的 :scope 至少匹配一个元素。就是匹配某个选择器。例如:

a:has(span) { 
  color:red 
}

a 元素内的 span 标签的字体颜色设置为 red。

例如:下面的CSS用于为任何包含一个或多个a或img标签的section链接添加一个蓝色的两像素边框:

a:has(img, section) {
  border: 2px solid blue;
}

例如:

<div>
    <p>div -- p</p>
</div>
<div>
    <p class="g-test-has">div -- p.has</p>
</div>
<div>
    <p>div -- p</p>
</div>

<style>
div:has(.g-test-has) {
    border: 1px solid #000;
}
</style>

注意,这里选择的不是 :has() 内包裹的选择器选中的元素,而是使用 :has() 伪类的宿主元素。

效果如下:
在这里插入图片描述

可以看到,由于第二个 div 下存在 class 为 .g-test-has 的元素,因此第二个 div 被加上了 border。

:has()的引入允许了过去没有JavaScript就不可能实现的可能性。例如,当任何必需的内部字段无效时,您可以设置外部表单和以下提交按钮的样式:

/* 当任何所需的内部字段无效时,显示红色边框 */
fieldset:has(:required:invalid) {
  border: 3px solid red;
}
/* 当无效时更改提交按钮样式 */
fieldset:has(:required:invalid) + button[type='submit'] {
  opacity: 0.2;
  cursor: not-allowed;
}

此示例添加包含子菜单项列表的导航链接子菜单指示符:

nav li:has(ol, ul) a::after {
  display: inlne-block;
  content: ">";
}

或者可以添加调试风格,比如突出显示所有的

元素,而不带内部的img:

figure:not(:has(img)) {
  border: 3px solid red;
}
:has() 父选择器 – 嵌套结构的父元素选择

:has() 内还可以写的更为复杂一点。例如:

<div>
  <span>div span</span>
</div>
<div>
  <ul>
      <li>
          <h2><span>div ul li h2 span</span></h2>
      </li>
  </ul>
</div>
<div>
  <h2><span>div h2 span</span></h2>
</div>

<style>
div:has(>h2>span) {
  margin-left: 24px;
  border: 1px solid #000;
}
</style>

这里,要求准确选择 div 下直接子元素是 h2,且 h2 下直接子元素有 span 的 div 元素。注意,选择的最上层使用 :has() 的父元素 div。结果如下:
在这里插入图片描述
这里体现的是嵌套结构,精确寻找对应的父元素。

还有一种情况,在之前也比较难处理,同级结构的兄元素选择。

例如:

<div class="has-test">div + p</div>
<p>p</p>

<div class="has-test">div + h1</div>
<h1>h1</h1>

<div class="has-test">div + h2</div>
<h2>h2</h2>

<div class="has-test">div + ul</div>
<ul>ul</ul>

我们想找到兄弟层级关系中,后面接了 h2 元素的 .has-test 元素(就是.has-test 元素的前一个),可以这样写:

.has-test:has(+ h2) {
    margin-left: 24px;
    border: 1px solid #000;
}

效果如下:
在这里插入图片描述

这里体现的是兄弟结构,精确寻找对应的前置兄元素。

这样,一直以来,CSS 没有实现的父选择器,借由 :has() 开始,也能够做到了。这个选择器,能够极大程度的提升开发体验,解决之前需要比较多 JavaScript 代码才能够完成的事。

例如:在鼠标hover到一个项时,其前后两项也会变化
在这里插入图片描述

关键代码:

li:has(+li:hover), /* 选中被hover的li的前一个li,即当一个元素后面紧跟一个被hover的li时,选中它 */
li:hover + li {    /* 选中被hover的li的后一个li,这个是大家都知道的 */
  font-size: 1.5em;
  width: 40px;
  height: 40px;
}

还可以根据子元素的数量使用不同的布局
在这里插入图片描述
关键代码:

/* 意思是当ul中第二个子元素也是最后一个子元素时,选中ul里面的所有li,让它们的宽度为75,即半宽。
四个子元素时也做同样处理
*/
ul:has(li:nth-child(2):last-child)   li,
ul:has(li:nth-child(4):last-child)   li {
  width: 75px;
  height: 75px;
}

ul:has(li:nth-child(8):last-child)   li {
  width: 37.5px;
  height: 37.5px;
}
/*
这个意思是当ul中正好有5个元素时,选中其中的前面两个,把宽度调为一半
*/
ul:has(li:nth-child(5):last-child)   li:nth-child(-n + 2) {
  width: 75px;
  height: 75px;
}
:has() 兼容性,需要一点时间

比较可惜的是,:has() 在最近的 Selectors Level 4 规范中被确定,目前的兼容性还比较惨淡
在这里插入图片描述
Chrome 下开启该特性需要,1. 浏览器 URL 框输入 chrome://flags,2. 开启 #enable-experimental-web-platform-features

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/224659.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

走迷宫(详细分析)

目录 一、课题描述 输入样例&#xff1a; 输出样例&#xff1a; 二、需求分析 输入的形式和输入值的范围&#xff1a; 输出的形式&#xff1a; 程序所能达到的功能&#xff1a; 三、概要设计 四、流程图 五 、代码详细注释 六、测试数据和结果 一、课题描述 以一个…

2024年江苏省职业院校技能大赛信息安全管理与评估 第三阶段学生组(样卷)

2024年江苏省职业院校技能大赛信息安全管理与评估 第三阶段学生组&#xff08;样卷&#xff09; 竞赛项目赛题 本文件为信息安全管理与评估项目竞赛-第三阶段样题&#xff0c;内容包括&#xff1a;网络安全渗透、理论技能与职业素养。 本次比赛时间为180分钟。 介绍 GeekSe…

上海亚商投顾:沪指窄幅震荡 多只高位股午后跳水

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 沪指昨日窄幅震荡&#xff0c;创业板指冲高回落。锂电池板块集体反弹&#xff0c;西藏矿业、吉翔股份、永兴材…

01-Redis核心数据结构与高性能原理

一、Redis的单线程和高性能 1. Redis是单线程吗&#xff1f; Redis的单线程主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的&#xff08;说白了也就是执行命令的时候是由一个线程来完成的&#xff09;&#xff0c;这也是 Redis 对外提供键值存储服务的主要流程。…

基于epoll实现Reactor服务器

了解epoll底层逻辑 在我们调用epoll_create的时候会创建出epoll模型&#xff0c;这个模型也是利用文件描述类似文件系统的方式控制该结构。 在我们调用epoll_create的时候&#xff0c;就会在内核管理中创建一个epoll模型&#xff0c;并且建管理模块地址给file结构体&#xff…

python数据分析基础

前言 2023年10月以来&#xff0c;一位在商学院就读的可爱同学遇上了一门课——python数据分析&#xff0c;并遇到了许多问题&#xff0c;找上了我&#xff0c;就此&#xff0c;我也开始了学习之路&#xff0c;虽然很浅显&#xff0c;但这些东西对部门同学来说也是受用的&#…

TypeScript中的单件设计模式

基本概念 &#xff08;1&#xff09; 了解设计模式 设计模式通俗的讲&#xff0c;就是一种更好的编写代码方案&#xff0c;打个比喻&#xff1a;从上海到武汉&#xff0c;你可以选择做飞机&#xff0c;做轮船&#xff0c;开车&#xff0c;骑摩托车多种方式&#xff0c;把出行…

短视频购物系统源码:构建创新购物体验的技术深度解析

短视频购物系统作为电商领域的新宠&#xff0c;其背后的源码实现是其成功的关键。本文将深入探讨短视频购物系统的核心技术和源码设计&#xff0c;以揭示其如何构建创新购物体验的技术奥秘。 1. 技术架构与框架选择 短视频购物系统的源码首先考虑的是其技术架构。常见的选择…

ExoPlayer架构详解与源码分析(10)——H264Reader

系列文章目录 ExoPlayer架构详解与源码分析&#xff08;1&#xff09;——前言 ExoPlayer架构详解与源码分析&#xff08;2&#xff09;——Player ExoPlayer架构详解与源码分析&#xff08;3&#xff09;——Timeline ExoPlayer架构详解与源码分析&#xff08;4&#xff09;—…

AI大模型:启动参数总结整理

虽然通过调整启动大模型的参数&#xff0c;对生成效果的提升是有限的&#xff0c;但适当的调整&#xff0c;还是能满足一些常用的场景的~ 一. 【max_length】 令牌生成最大数 用于控制生成文本的最大长度&#xff0c;默认为 20。它的值对应于输入提示的长度加上max_new_token…

10_企业架构NOSQL数据库之MongoDB

企业架构NOSQL数据库之MongoDB 学习目标和内容 1、能够简单描述MongoDB的使用特点 2、能够安装配置启动MongoDB 3、能够使用命令行客户端简单操作MongoDB 4、能够实现基本的数据操作 5、能够实现MongoDB基本安全设置 6、能够操作安装php的MongoDB扩展 一、背景描述及其方案设计…

【AI】以大厂PaaS为例,看人工智能技术方案服务能力的方向(1/2)

目录 一、深度学习能力 二、计算框架 2.1 语音 2.2 OCR 2.3 人脸/体识别 2.4 图像审核 2.5 图像识别 2.6 视频 2.7 自然语言理解 2.8 知识图谱 今天以百度智能云为例&#xff0c;梳理下人工智能技术方案服务能力&#xff0c;主要有哪些方向的应用和拓展。 纯属学习&…

JDK 9 模块化系统 (Module System) 和 多版本兼容 Jar (Multi-Release Jar)

博文目录 文章目录 Module System原因JDK 模块化模块描述文件关键字 启用模块化测试结论 Multi-Release jar (MRJAR)原因原理结论用 IDEA 创建多版本兼容 Jar项目结构pom.xml测试 Module System 原因 Java 9引入了模块化系统的主要原因是为了解决Java平台面临的复杂性和可维…

OpenCV图像相似性比对算法

背景 在做图像处理或者计算机视觉相关的项目的时候&#xff0c;很多时候需要我们对当前获得的图像和上一次的图像做相似性比对&#xff0c;从而找出当前图像针对上一次的图像的差异性和变化点&#xff0c;这需要用到OpenCV中的一些图像相似性和差异性的比对算法&#xff0c;在O…

C练习题13

单项选择题(本大题共20小题,每小题2分,共40分。在每小题给出的四个备选项中,选出一个正确的答案,并将所选项前的字母填写在答题纸的相应位置上。) 1.结构化程序由三种基本结构组成、三种基本结构组成的算法是() A.可以完成任何复杂的任务 B. 只能完成部分复杂的任务 C. 只能完…

打破常规思维:Scrapy处理豆瓣视频下载的方式

概述 Scrapy是一个强大的Python爬虫框架&#xff0c;它可以帮助我们快速地开发和部署各种类型的爬虫项目。Scrapy提供了许多方便的功能&#xff0c;例如请求调度、数据提取、数据存储、中间件、管道、信号等&#xff0c;让我们可以专注于业务逻辑&#xff0c;而不用担心底层的…

TrustZone之物理地址空间

除了两个安全状态外&#xff0c;该体系结构还提供了两个物理地址空间&#xff1a;安全和非安全。 在非安全状态下&#xff0c;虚拟地址始终转换为非安全物理地址。这意味着在非安全状态下的软件只能看到非安全资源&#xff0c;但永远看不到安全资源。如图所示&#xff1a; 在安…

大数据Doris(三十三):Doris高级设置

文章目录 Doris高级设置 一、增大内存

准确!!!在 CentOS 8 上配置 PostgreSQL 14 的主从复制

在 CentOS 8 上配置 PostgreSQL 14 的主从复制&#xff0c;并设置 WAL 归档到特定路径 /home/postgres/archive 的步骤如下&#xff1a; 主服务器配置&#xff08;主机&#xff09; 配置 PostgreSQL&#xff1a; 编辑 postgresql.conf 文件&#xff1a; vim /data/postgres/p…

Java二阶知识点总结(一)Maven

一、Maven概念 Maven是一个项目管理工具&#xff0c;其主要作用有2点 依赖管理&#xff1a;管理项目依赖的各种jar包自动构建&#xff1a;项目构建的过程&#xff0c;从编译、测试、运行、打包到安装的过程可以一键执行 二、Maven工程的目录结构 src/main/java&#xff1a;…
最新文章