选择器和 @ 规则组合

Web 功能: 容器样式查询

问题

我们通常需要组合不同类型的过滤条件,例如选择器 + 媒体查询、媒体查询 + 容器查询等。

例如,将 (prefers-color-scheme: dark) 与定位到配色方案替换项的选择器(例如 :root:has(> head > meta[name="color-scheme"][content="dark"]) 或 :root.dark)结合使用,以便在浅色/深色模式下应用特定样式,而不管配色方案是如何设置的。

简单的方法会导致代码重复:

/* Light mode styles */
.card.featured {
  font-weight: 400;
}

#logo-dark {
  display: none;
}

@media (prefers-color-scheme: dark) {
  /* Dark mode styles */
  :root:not(.light) {
    .card.featured {
      font-weight: 300;
    }

    #logo-dark {
      display: inline;
    }

    #logo {
      display: none;
    }
  }
}

/* Dark mode styles, again */
:root.dark {
  .card.featured {
    font-weight: 300;
  }

  #logo-dark {
    display: inline;
  }

  #logo {
    display: none;
  }
}

建议的做法

将组合过滤条件的结果存储在自定义属性中,然后使用容器样式查询根据该属性设置规则。

重要提示:由于容器查询的工作方式,只有当我们可以在必须匹配的任何规则的祖先上设置自定义属性时,此技术才有效。

1. 将选择逻辑与应用的规则解耦

:root {
  --color-scheme: light;

  @media (prefers-color-scheme: dark) {
    --color-scheme: dark;
  }

  &:has(> head > meta[name="color-scheme"][content="dark"]) {
    --color-scheme: dark;
  }

  &:has(> head > meta[name="color-scheme"][content="light"]) {
    --color-scheme: light;
  }
}

2. 所应用规则的自定义属性的键

@container not style(--color-scheme: dark) {
  .card.featured {
    font-weight: 400;
  }

  #logo-dark {
    display: none;
  }
}

@container style(--color-scheme: dark) {
  .card.featured {
    font-weight: 300;
  }

  #logo {
    display: none;
  }
}

3. 可选:用于切换可见性的实用程序类

一个非常常见的用例是根据条件是否匹配来切换可见性。 实用程序类必须优先于任意组件样式(因此使用 !important),并且其显示的 display 未知,因此无法使用替换项,请使用 not style(...) 进行控制:

@container not style(--color-scheme: dark) {
  .if-dark {
    display: none !important;
  }
}

@container not style(--color-scheme: light) {
  .if-light {
    display: none !important;
  }
}

后备

后备分为两种类型,具体取决于分支的重要程度以及可接受的后备内容。

  1. 对于关键分支,即使不支持样式查询,所有状态也必须正常运行,因此您根本无法使用样式查询。 而是应使用上述简单方法,为每个状态复制规则。 只要实用程序类也以这种方式定义,就仍然可以使用。
  2. 对于非关键分支(其中默认状态可接受),您可以在任何 @container 规则之外定义基本样式,并且仅使用样式查询作为替换。 这保留了此方法的大部分精神,其主要缺点是覆盖引入的值的耦合。
#logo-dark {
  display: none;
}

@container style(--color-scheme: dark) {
  #logo-dark {
    display: inline; /* override */
  }

  #logo {
    display: none;
  }
}