Skip to content

W3C的选择器

相关的html新标签

figure、figcaption、pre、blockquote

html
<figure>
  <img src="image.png" alt="">
  <figcaption>caption and descriptions</figcaption>
</figure>

<figure>
  <figcaption>code</figcaption>
  <pre>
    function log(val) {
      console.log(val)
    }
    
    log('hello world')      
  </pre>
</figure>

<figure>
  <figcaption>Shakespeare: </figcaption>
  <blockquote>Nutrition books in the world. There is no book in life, there is no sunlight; wisdom without
    books, as if the birds do not have wings.</blockquote>
</figure>

:has的使用

用一句话来描述: :has() 选择器是一个关系型伪类选择器,也被称为函数型伪类选择器,它和 :is():not() 以及 :where() 函数型选择器被称为 CSS 的逻辑组合选择器。

css
/* 卡片不带标题的样式规则 */
.card {
    display: flex;
    border-radius: 10px;
    max-width: 40vw;
    background-color: #F5F5F5;
}

.card img {
    display: block;
    max-width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    object-position: center;
}

/* 卡片带标题的样式规则 */
.card:has(figcaption) {
    flex-direction: column;
    gap: 1rem;
    padding: 20px;
}

有趣的知识:对比一下区别

css
section:not(:has(h1, h2, h3, h4, h5, h6))
section:has(:not(h1, h2, h3, h4, h5, h6))
  1. section:not(:has(h1, h2, h3, h4, h5, h6))

语法分析:

  • section:选择所有 section 元素。
  • :not():是一个排除伪类,它会排除符合条件的元素。
  • :has(h1, h2, h3, h4, h5, h6):表示选中那些包含 <h1><h6> 的 section 元素。

所以这个选择器的意思是:

  • 选择那些 没有包含任何 <h1><h6> 元素的 section 元素。

关键点:

  • 它选择的是 不含标题标签(即 <h1><h6>)的 section 元素。
  1. section:has(:not(h1, h2, h3, h4, h5, h6))

语法分析:

  • section:选择所有 section 元素。

  • :has():这个伪类用来选中那些包含符合特定条件的子元素的父元素。

  • :not(h1, h2, h3, h4, h5, h6):表示选中那些 不包含 <h1><h6> 元素的子元素。
    所以这个选择器的意思是:

  • 选择那些 包含至少一个不属于 <h1><h6> 的子元素 的 section 元素。

关键点:

  • 它选中的是那些**含有其他元素(非标题元素)**的 section,并不要求这些 section 内部完全没有 <h1><h6>,但是要求必须有其他非标题元素。

举个更明确的例子

html
<section>
  <p>This section has no headings, just a paragraph.</p>
</section>

<section>
  <h2>Title</h2>
  <p>This section has a heading.</p>
</section>

<section>
  <h1>Title</h1>
  <div>Some other content</div>
</section>

<section>
  <h1>Title</h1>
  <h3>Another Title</h3>
</section>

第一个选择器:section:not(:has(h1, h2, h3, h4, h5, h6))

  • 会选中 第一个 section,因为它没有任何标题标签(没有 <h1><h6>)。
  • 第二个 section 被排除,因为它含有 <h2>,符合 :has() 的条件。
  • 第三个 section 被排除,因为它包含 <h1>,符合 :has() 的条件。
  • 第四个 section 被排除,因为它包含 <h1><h3>,符合 :has() 的条件。

第二个选择器:section:has(:not(h1, h2, h3, h4, h5, h6))

  • 会选中 第一个 section,因为它包含了 <p>,这是一个不是标题的元素。
  • 第二个 section 被选中,因为它有 <p>,并且 <p> 不是标题元素。
  • 第三个 section 被选中,因为它包含 <div>,而 <div> 不是标题元素。
  • 第四个 section 不会被选中,因为它只有标题元素(<h1><h3>),没有其他非标题元素。

主要区别:

  1. section:not(:has(h1, h2, h3, h4, h5, h6)):它选择的是没有包含任何标题元素的 section 元素。
  2. section:has(:not(h1, h2, h3, h4, h5, h6)):它选择的是 包含其他类型元素(非标题)的 section 元素。

总结:

  • 第一个选择器更严格,它排除了所有包含标题的 section 元素。
  • 第二个选择器则是宽松一点,它只要求 section 中必须有其他类型的元素,而不要求标题必须不存在。

组合选择器

“组合选择器”是一种特殊字符,表示选择器之间的关系类型。常见的组合选择器主要有:

  • 空格字符,例如 a b ,称之为后代组合选择器,匹配直接或嵌套的子元素;
  • > 字符,例如 a > b ,称之为直接子元素组合选择器,仅匹配顶层未嵌套的子元素;
  • + 字符,例如 a + b ,称之为相邻兄弟组合选择器,仅匹配紧随其后的下一个兄弟元素;
  • ~ 字符,例如 a ~ b ,称之为通用兄弟组合选择器,匹配基础选择器(a)之后的一个或多个兄弟元素(b)

伪类选择器

伪类元素使用了两个冒号 (::) 而不是一个冒号 (:),这是 CSS3 规范中的一部分要求,目的是为了区分伪类和伪元素,大多数浏览器都支持下面这两种表示方式。

  • 状态伪类选择器,比如 :hover:active:visited:target:focus 等;
  • 焦点伪类选择器,比如 :focus-within:focus-visible 等;
  • 结构型伪类选择器,比如 :nth-child:nth-last-child:first-child:last-child:only-child:nth-of-type:nth-last-of-type:first-of-type:last-of-type:only-of-type 等;
  • 表单伪类选择器,比如 :autofill:enabled:disabled:read-only:read-write, :placeholder-shown :default:checked:indeterminate:valid:invalid:in-range:out-of-range:required:optional 等;
  • 目标伪类选择器,比如 :target
  • 语言伪类选择器,比如 :dir():lang() 等;
  • 函数伪类选择器,比如 :not():is():where() 等。

has的使用,另外,需要注意的是,CSS 工作组决定禁止在 :has() 内部使用所有现有的伪元素,比如 ::before::after::marker::first-line 等。

css
/* ul 包含最多 3 个( 3 个或更少,不包括 0 ) li 项 */
ul:has(> :nth-child(-n+3):last-child) {
    border: 3px solid palegreen;
}

/* ul 包含最多 3 个( 3 个或更少,包括 0 个) li 项 */
ul:not(:has(> :nth-child(3))) {
    border: 3px solid limegreen;
}

/* ul 正好包含 5 个 li 项 */
ul:has(> :nth-child(5):last-child) {
    border: 3px solid plum;
}

/* ul 至少包含 10 个 (10 个或更多)li 项 */
ul:has(> :nth-child(10)) {
    border: 3px solid pink;
}

/* ul 包含 7 ~ 9 个 li 项*/
ul:has(> :nth-child(7)):has(> :nth-child(-n+9):last-child) {
    border: 3px solid tomato;
}
/** 不支持:has时的备选方案 */
@supports not selector(:has(works)) { 
    .card { 
        flex-direction: column; 
        align-items: flex-start; 
    } 
}

:target 实现模态框

html
<a href="#target-content" id="button">Open CSS Modal via <code>:target</code></a>
<div id="target-content">
    <a href="#" class="close"></a>
    <div id="target-inner">
        <h2>CSS Modal</h2>
    </div>
</div>
<style>
    target-content {
    pointer-events: none;
    opacity: 0;
    transition: opacity 200ms;
}
target-content:target {
    pointer-events: all;
    opacity: 1;
}
</style>

选择多个范围的组

html
<ul>
    <li class="rect"></li>
    <li class="rect"></li>
    <li data-range></li>
    <li class="circle"></li>
    <li class="circle"></li>
    <li class="circle"></li>
    <li class="circle"></li>
    <li data-range></li>
    <li class="star"></li>
    <li class="star"></li>
    <li class="star"></li>
    <li class="rect"></li>
</ul>
css
/**选中 data-range 开始和结束之间所有 li (即所有 .circle 元素) */
[data-range] ~ :has(~ [data-range])  {
    width: 100px;
    border: 2px solid #09f;
    outline: 4px solid rgb(0 0 0 / .5);
}

/**
* [data-range]:has(~ [data-range]) 给范围起始元素(第一个设置 data-range 的 li 元素)设置样式*/
[data-range]:has(~ [data-range]) {
    background-color: #987;
    outline: 2px solid red;
}
/* [data-range] ~ [data-range] 给范围结束元素(第二个设置 data-range 的 li 元素)设置样式*/
[data-range] ~ [data-range] {
    background-color: #90f;
    outline: 2px solid orange;
}

多个范围选择

html
<ul>
    <li data-range="start"></li>
    <li class="rect"></li>
    <li class="rect"></li>
    <li data-range="end"></li>
    <li data-range="start"></li>
    <li class="circle"></li>
    <li class="circle"></li>
    <li class="circle"></li>
    <li class="circle"></li>
    <li data-range="end"></li>
    <li data-range="start"></li>
    <li class="star"></li>
    <li class="star"></li>
    <li class="star"></li>
    <li data-range="end"></li>
    <li class="rect"></li>
</ul>
css
/* 选择范围组中开始和结束元素 */
[data-range] {
    box-shadow: 0 0 0 6px red;
    border-radius: 2px;
}

/* 选择范围组中起始元素 */
[data-range="start"] {
    outline:3px solid yellow;
}

/* 选择范围组中结束元素 */
[data-range="end"] {
    outline: 3px solid #e90;
}

/* 选择范围组内的第一个元素 */
[data-range="start"] + :has(~ [data-range="end"]):not([data-range]) {
    width: 80px;
    border: 4px solid #09f;
}

/* 选择范围组内的最后一个元素 */
[data-range="start"] ~ :has(+ [data-range="end"]):not([data-range]) {
     width: 80px;
     border: 4px solid;
}

/* 选择范围组内的所有元素 */
[data-range="start"] ~ :has(~ [data-range="end"]):not([data-range]) {
    width: 80px;
    border: 4px solid;
    box-shadow: 0 0 0 4px rgb(0 0 0 / .125);
}