目錄
:is 偽類選擇器
支援多層層疊連用
:is 的别名 :matches() 与 :any()
:where 伪类选择器
组合、嵌套
:not 伪类选择器
MDN 的错误例子?一个有意思的现象
:not 的优先级问题
:not(*) 问题
:not() 不能嵌套 :not()
:not() 实战解析
:not 兼容性
:has 伪类选择器
:has() 父选择器 -- 嵌套结构的父元素选择
:has() 父选择器 -- 同级结构的兄元素选择
:has() 兼容性,给时间一点时间
首頁 web前端 css教學 聊聊CSS3中的4個邏輯選擇器(快速著手)

聊聊CSS3中的4個邏輯選擇器(快速著手)

Jul 15, 2022 am 10:56 AM
css3 選擇器 邏輯選擇器

<p>這篇文章跟大家介紹CSS3中的邏輯選擇器,聊聊裡面的 4 位成員,希望對大家有幫助!

<p>聊聊CSS3中的4個邏輯選擇器(快速著手)

<p>在CSS 選擇器家族中,新增這樣一類比較新的選擇器-- 邏輯選擇器,目前共有4 位成員:

  • :is
  • :where
  • :not
  • :has
<p>本文將帶領大家了解、深入它們。做到學以致用,寫出更現代化的選擇者。 【推薦學習:css影片教學


:is 偽類選擇器

<p>:is() CSS偽類別函數將選擇器清單作為參數,並選擇該清單中任一個選擇器可以選擇的元素。

<p>在之前,對於多個不同父容器的同個子元素的一些共性樣式設置,可能會出現如下CSS 代碼:

header p:hover,
main p:hover,
footer p:hover {
  color: red;
  cursor: pointer;
}
登入後複製
登入後複製
<p>而如今有了:is() 偽類,上述程式碼可以改寫成:

:is(header, main, footer) p:hover {
  color: red;
  cursor: pointer;
}
登入後複製
<p>它並沒有實作某種選擇器的新功能,更像是一種語法糖,類似JavaScript ES6 中的Class() 語法,只是對原有功能的重新封裝設計,實現了更容易的表達一個操作的語法,簡化了某些複雜程式碼的寫法。

語法糖(syntactic sugar)是指程式語言中可以更容易的表達一個操作的語法,它可以使程式設計師更容易去使用這門語言,操作可以變得更清晰、方便,或更符合程式設計師的程式設計習慣。用比較簡單易懂的方式去理解就是,在之前的某個語法的基礎上改變了一種寫法,實現的功能相同,但是寫法不同了,主要是為了讓開發人員在使用過程中更方便易懂。
<p>一圖勝前言(引用至New CSS functional pseudo-class selectors :is() and :where()):

<p>

支援多層層疊連用

<p>再來看看這種情況,原本的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>
登入後複製
<p>如果要將上述HTML 中,<div>< div> 下的<span><i> 的color 設定為red,正常的CSS 可能是這樣:

div span,
div i,
p span,
p i {
    color: red;
}
登入後複製
<p>有了:is() 後,程式碼可以簡化為:

:is(div, p) :is(span, i) {
    color: red;
}
登入後複製
<p>結果如下:

<p>

##這裡,也支援<p>: is() 的層疊連用。透過 :is(div, p) :is(span, i) 的排列組合,可以組合出上述 4 行的選擇器,達到相同的效果。

當然,這個例子比較簡單,看不出​​ <p>: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;
}
登入後複製
可以利用<p>:is() 優化為:

:is(ol, ul, menu, dir) :is(ol, ul, menu, dir) :is(ul, menu, dir) {
  list-style-type: square;
}
登入後複製
不支援偽元素

有個特例,不能用<p>:is() 來選取::before::after 兩個偽元素。譬如:

注意,只是不支持偽元素,偽類,譬如
:focus:hover 是支持的。
div p::before,
div p::after {
    content: "";
    //...
}
登入後複製
不能寫成:<p>

div p:is(::before, ::after) {
    content: "";
    //...
}
登入後複製

:is 選擇器的優先權

看這樣有意思的情況:<p>

<div>
    <p class="test-class" id="test-id">where & is test</p>
</div>
<div>
    <p class="test-class">where & is test</p>
</div>
登入後複製
我們給帶有<p>.test-class 的元素,設定一個預設的顏色:

div .test-class {
    color: red;
}
登入後複製
如果,這個時候,我們引入<p>:is() 進行匹配:

div :is(p) {
    color: blue;
}
登入後複製
此時,由於<p>div :is(p) 可以看成div p,優先權是沒有div .test-class 高的,因此,被選取的文字的顏色是不會改變的。

但是,如果,我們在 <p>:is() 選擇器中,加上一個 #test-id,情況就不一樣了。

div :is(p, #text-id) {
    color: blue;
}
登入後複製
依照理解,如果把上述選擇器拆分,上述程式碼可以拆分成:<p>

div p {
    color: blue;
}
div #text-id {
    color: blue;
}
登入後複製
那麼,我們有理由猜想,帶有<p>#text-id<p> 元素由於有了更高優先級的選擇器,顏色將會變成blue,而另一個div p 由於優先級不夠高的問題,導致第一段文字依舊是green

但是,這裡,神奇的是,兩段文字都變成了<p>blue

<p>

CodePen Demo - - the specificity of CSS :is selector<p>

https://codepen.io/Chokcoco/pen/rNJaGvb<p>

<p>这是由于,:is() 的优先级是由它的选择器列表中优先级最高的选择器决定的。我们不能把它们割裂开来看。

<p>对于 div :is(p, #text-id)is:() 内部有一个 id 选择器,因此,被该条规则匹配中的元素,全部都会应用 div #id 这一级别的选择器优先级。这里非常重要,再强调一下,对于 :is() 选择器的优先级,我们不能把它们割裂开来看,它们是一个整体,优先级取决于选择器列表中优先级最高的选择器

:is 的别名 :matches() 与 :any()

<p>:is() 是最新的规范命名,在之前,有过有同样功能的选择,分别是:

:is(div, p) span {}
// 等同于
:-webkit-any(div, p) span {}
:-moz-any(div, p) span {}
:matches(div, p) span {}
登入後複製
<p>当然,下面 3 个都已经废弃,不建议再继续使用。而到今天(2022-04-27):is() 的兼容性已经非常不错了,不需要兼容 IE 系列的话可以考虑开始用起来(配合 autoprefixer),看看 CanIUse:

<p>

:where 伪类选择器

<p>了解了 :is 后,我们可以再来看看 :where,它们两个有着非常强的关联性。:where 同样是将选择器列表作为其参数,并选择可以由该列表中的选择器之一选择的任何元素。

<p>还是这个例子:

:where(header, main, footer) p:hover {
  color: red;
  cursor: pointer;
}
登入後複製
<p>上述的代码使用了 :where,可以近似的看为:

header p:hover,
main p:hover,
footer p:hover {
  color: red;
  cursor: pointer;
}
登入後複製
登入後複製
<p>这就有意思了,这不是和上面说的 :is 一样了么?

<p>那么它们的区别在什么地方呢?

:is:where 的区别

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

<p>来看这样一个例子:

<div>
    <p>where & is test</p>
</div>
登入後複製
<p>CSS 代码如下:

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

<p>

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

<p>上述的例子还不是特别明显,我们再稍微改造下:

<div id="container">
    <p>where & is test</p>
</div>
登入後複製
<p>我们给 div 添加上一个 id 属性,改造上述 CSS 代码:

:is(div) p {
    color: red;
}
:where(#container) p {
    color: green;
}
登入後複製
<p>即便如此,由于 :where(#container) 的优先级为 0,因此文字的颜色,依旧为红色 red。:where() 的优先级总是为 0 这一点在使用的过程中需要牢记。

组合、嵌套

<p>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;
}
登入後複製
<p>这里简单总结下,:is:where 都是非常好的分组逻辑选择器,唯一的区别在于:where() 的优先级总是为 0,而:is() 的优先级是由它的选择器列表中优先级最高的选择器决定的。

:not 伪类选择器

<p>下面我们介绍一下非常有用的 :not 伪类选择器。

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

<p>举个例子,HTML 结构如下:

<div class="a">div.a</div>
<div class="b">div.b</div>
<div class="c">div.c</div>
<div class="d">div.d</div>
登入後複製
div:not(.b) {
    color: red;
}
登入後複製
<p>div:not(.b) 它可以选择除了 class 为 .b 元素之外的所有 div 元素:

<p>

MDN 的错误例子?一个有意思的现象

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

/* Selects any element that is NOT a paragraph */
:not(p) {
  color: blue;
}
登入後複製
<p>意思是,:not(p) 可以选择任何不是 <p> 标签的元素。然而,上面的 CSS 选择器,在如下的 HTML 结构,实测的结果不太对劲。

<p>p</p>
<div>div</div>
<span>span</span>
<h1>h1</h1>
登入後複製
<p>结果如下:

<p>

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

<p>CodePen Demo -- :not pesudo demo

<p>https://codepen.io/Chokcoco/pen/KKZbWjy

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

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

/* Selects any element that is NOT a paragraph */
:not(p) {
  border: 1px solid;
}
登入後複製
<p>

<p>OK,这次 <p> 没有边框体现,没有问题!实际使用的时候,需要注意这一层继承的问题!

:not 的优先级问题

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

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

<p>并且,在 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) {
}
登入後複製
<p>与 :is() 类似,:not() 选择器本身不会影响选择器的优先级,它的优先级是由它的选择器列表中优先级最高的选择器决定的。

:not(*) 问题

<p>使用 :not(*) 将匹配任何非元素的元素,因此这个规则将永远不会被应用。

<p>相当于一段没有任何意义的代码。

:not() 不能嵌套 :not()

<p>禁止套娃。:not 伪类不允许嵌套,这意味着 :not(:not(...)) 是无效的。

:not() 实战解析

<p>那么,:not() 有什么特别有意思的应用场景呢?我这里列举一个。

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

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

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

<p>看个简单的 Demo:

<button>Test 1</button>
登入後複製
button:active {
  background: #eee;
}
button:focus {
  outline: 2px solid red;
}
登入後複製
<p>使用鼠标点击:

<p>

<p>可以看到,使用鼠标点击的时候,触发了元素的 :active 伪类,也触发了 :focus伪类,不太美观。但是如果设置了 outline: none 又会使键盘用户的体验非常糟糕。因为当键盘用户使用 Tab 尝试切换焦点的时候,会因为 outline: none 而无所适从。

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

button:active {
  background: #eee;
}
button:focus {
  outline: 2px solid red;
}
button:focus:not(:focus-visible) {
  outline: none;
}
登入後複製
<p>看看效果,分别是在鼠标点击 Button 和使用键盘控制焦点点击 Button:

<p>

<p>CodePen Demo -- :focus-visible example

<p>https://codepen.io/Chokcoco/pen/abBbPrE

<p>可以看到,使用鼠标点击,不会触发 :foucs,只有当键盘操作聚焦元素,使用 Tab 切换焦点时,outline: 2px solid red 这段代码才会生效。

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

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

button:focus {
  outline: unset;
}
button:focus-visible {
  outline: 2px solid red;
}
登入後複製
<p>解释一下,button:focus:not(:focus-visible) 的意思是,button 元素触发 focus 状态,并且不是通过 focus-visible 触发,理解过来就是在支持 :focus-visible 的浏览器,通过鼠标激活 :focus 的 button 元素,这种情况下,不需要设置 outline

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

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

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

:not 兼容性

<p>经历了 CSS Selectors Level 3 & CSS Selectors Level 4 两个版本,到今天(2020-05-04),除去 IE 系列,:not 的兼容性已经非常之好了:

<p>

:has 伪类选择器

<p>OK。最后到所有逻辑选择器里面最重磅的 :has 出场了。它之所以重要是因为它的诞生,填补了在之前 CSS 选择器中,没有核心意义上真正的父选择器的空缺。

<p>:has 伪类接受一个选择器组作为参数,该参数相对于该元素的 :scope 至少匹配一个元素。

<p>实际看个例子:

<div>
    <p>div -- p</p>
</div>
<div>
    <p class="g-test-has">div -- p.has</p>
</div>
<div>
    <p>div -- p</p>
</div>
登入後複製
div:has(.g-test-has) {
    border: 1px solid #000;
}
登入後複製
<p>我们通过 div:has(.g-test-has) 选择器,意思是,选择 div 下存在 class 为 .g-test-has 的 div 元素。

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

<p>效果如下:

<p>

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

:has() 父选择器 -- 嵌套结构的父元素选择

<p>我们再通过几个 DEMO 加深下印象。: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>
登入後複製
div:has(>h2>span) {
    margin-left: 24px;
    border: 1px solid #000;
}
登入後複製
<p>这里,要求准确选择 div 下直接子元素是 h2,且 h2 下直接子元素有 span 的 div 元素。注意,选择的最上层使用 :has() 的父元素 div。结果如下:

<p>

<p>这里体现的是嵌套结构,精确寻找对应的父元素

:has() 父选择器 -- 同级结构的兄元素选择

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

<p>看这个 DEMO:

<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>
登入後複製
<p>我们想找到兄弟层级关系中,后面接了 <h2> 元素的  .has-test 元素,可以这样写:

.has-test:has(+ h2) {
    margin-left: 24px;
    border: 1px solid #000;
}
登入後複製
<p>效果如下:

<p>

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

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

<p>上述 DEMO 汇总,你可以戳这里 CodePen Demo -- :has Demo

<p>https://codepen.io/Chokcoco/pen/poaJjwm

:has() 兼容性,给时间一点时间

<p>比较可惜的是,:has() 在最近的 Selectors Level 4 规范中被确定,目前的兼容性还比较惨淡,截止至 2022-05-04,Safari 和 最新版的 Chrome(V101,可通过开启 Experimental Web Platform features 体验)

<p>

Chrome 下开启该特性需要,1. 浏览器 URL 框输入 chrome://flags,2. 开启 #enable-experimental-web-platform-features
<p>耐心等待,给给时间一点时间,这么好的选择器马上就能大规模应用了。

<p>(学习视频分享:web前端入门

以上是聊聊CSS3中的4個邏輯選擇器(快速著手)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

css3怎麼實現花邊邊框 css3怎麼實現花邊邊框 Sep 16, 2022 pm 07:11 PM

在css中,可以利用border-image屬性來實作花邊邊框。 border-image屬性可以使用圖片來建立邊框,即給邊框加上背景圖片,只需要將背景圖片指定為花邊樣式即可;語法「border-image: url(圖片路徑) 向內偏移值圖像邊界寬度outset 是否重複;」。

css中id選擇符的標識是什麼 css中id選擇符的標識是什麼 Sep 22, 2022 pm 03:57 PM

在css中,id選擇符的識別是“#”,可以為標有特定id屬性值的HTML元素指定特定的樣式,語法結構“#ID值 {屬性 : 屬性值;}”。 ID屬性在整個頁面中是唯一不可重複的;ID屬性值不要以數字開頭,數字開頭的ID在Mozilla/Firefox瀏覽器中不起作用。

使用:nth-child(n+3)偽類選擇器選擇位置大於等於3的子元素的樣式 使用:nth-child(n+3)偽類選擇器選擇位置大於等於3的子元素的樣式 Nov 20, 2023 am 11:20 AM

使用:nth-child(n+3)偽類選擇器選擇位置大於等於3的子元素的樣式,具體程式碼範例如下:HTML程式碼:&lt;divid="container"&gt;&lt;divclass="item"&gt ;第一個子元素&lt;/div&gt;&lt;divclass="item"&

javascript選擇器失效怎麼辦 javascript選擇器失效怎麼辦 Feb 10, 2023 am 10:15 AM

javascript選擇器失效是因為程式碼不規範導致的,其解決方法:1、把引入的JS程式碼去掉,ID選擇器方法即可有效;2、在引入「jquery.js」之前引入指定JS程式碼即可。

CSS新特性學習:方向裁切overflow:clip CSS新特性學習:方向裁切overflow:clip Oct 11, 2022 pm 07:12 PM

這篇文章將介紹一個新特性,從 Chrome 90 開始,overflow 新增的新特性 -- overflow: clip,使用它,輕鬆的對溢出方向進行控制。

css中的選擇器包含超文本標記選擇器嗎 css中的選擇器包含超文本標記選擇器嗎 Sep 01, 2022 pm 05:25 PM

不包括。 css選擇器有:1、標籤選擇器,是透過HTML頁面的元素名稱定位具體HTML元素;2、類別選擇器,是透過HTML元素的class屬性的值定位具體HTML元素;3、ID選擇器,是透過HTML元素的id屬性的值定位具體HTML元素;4、通配符選擇器“*”,可以指所有類型的標籤元素,包括自訂元素;5、屬性選擇器,是透過HTML元素已經存在屬性名或屬性值來定位具體HTML元素。

詳解用SVG為 favicon 新增標識 詳解用SVG為 favicon 新增標識 Sep 07, 2022 am 10:30 AM

怎麼使用SVG為 favicon 新增標識?以下這篇文章為大家介紹一下使用 SVG 產生帶有標識的 favicon的方法,希望對大家有幫助!

一文了解lxml支援的選擇器有哪些 一文了解lxml支援的選擇器有哪些 Jan 13, 2024 pm 02:08 PM

lxml是一個功能強大的Python庫,用於處理XML和HTML文件。作為解析工具,它提供了多種選擇器來幫助使用者方便地從文件中提取所需的資料。本文將詳細介紹lxml支援的選擇器。 lxml支援以下幾種選擇器:標籤選擇器(ElementTagSelector):透過標籤名稱來選擇元素。例如,透過使用<tagname>來選擇具有特定標籤名稱的元

See all articles