关于元素媒体查询的想法

Avatar of Chris Coyier
Chris Coyier

DigitalOcean 为您旅程的每个阶段提供云产品。 立即开始使用 $200 的免费积分!

想象一下,像这些 Transformer Tabs 这样的东西,在响应式设计中作为流体列中的一个小部件。 根据浏览器窗口宽度,此设计可能是 4 列、2 列或 1 列宽。 当它从 4 列变为 2 列时,该列可能暂时变宽,即使屏幕变窄。 在为这些标签编写媒体查询逻辑时,最好考虑小部件有多少可用空间,而不是整个窗口,因为这可能完全无关,尤其是在重用此小部件时。

Jonathan Neal 对此有一些想法,包括您可能没有想到的复杂部分,例如小部件的内容如何影响其父容器并导致无限循环。

Jonathan 的网站现在已离线,因此我将在此处复制此博文的内容以供后代。

这篇文章的灵感来自我的朋友,也是 normalize.css 的共同创建者, Nicolas Gallagher.

我们需要在元素/组件/小部件级别而不是视窗级别使用原生 CSS 媒体查询。 网上就是这样做的。 — @necolas

因此,没有任何大张旗鼓,我想分享我对元素媒体查询的看法,然后在评论中打开讨论。

想法 #1:标记将是什么

我们将使用一个 伪类,因为我们正在针对元素的状态。 伪类的示例包括 :hover:focus:checked

我们不会使用伪元素,因为我们不针对元素内的影子元素。 伪元素的一些示例包括 ::first-letter::before::after。 不要被 IE7&8 误导,:before 不是正确的语法。 实际上,如果您不支持 IE7&8,则应该开始使用正确的语法以摆脱这种遗留的不一致性。

[:]: 符号由本文档引入,以区分伪类和伪元素。 为了与现有样式表兼容,用户代理还必须接受 CSS 级别 1 和 2 中引入的伪元素的先前单冒号符号(即:first-line、:first-letter、:before 和 :after)。 — 选择器 W3C 工作草案

我们将以其前身的命名伪类 media,使用圆括号包装查询,类似于 :not:contains

.widget:media(max-width: 30em) {color: tomato;}

多个查询需要多个圆括号。

.widget:media((max-width: 30em) and (min-width: 30em)) {color: bisque;}

想法 #2:em 将如何工作

em 的大小将相对于元素的字体大小,就像它对现有 CSS 值的工作方式一样。 rem 单位将用于定位文档的字体大小。

html {font-size: 16px;} 
.parent {font-size: 12px;} 
.parent > *:media(max-width: 30em) {/* applied up to 360px */}  
.parent > *:media(max-width: 30rem) {/* applied up to 480px */}

这带来了现有媒体查询的一个问题。 目前,当我们将 html 的字体大小定义为 12px 时,@media (max-width: 30em) 会评估为 360px 还是 480px? 如果我们认为 @media “存在”于 html 元素上,那么答案是 360px。 另一方面,如果我们认为 @media “存在”于超越 html 的某个以太中,那么答案是 480px。 可悲的是,大多数浏览器同意后一种解释。 因此,作为对元素媒体查询讨论的附带好处,我们应该指定 @media 查询中 em 的大小应该相对于 html 元素的字体大小。

想法 #3:如何处理无限循环

无限循环将在出现问题的块处冻结。 虽然无限循环更有可能在元素媒体查询中发生,但这个问题自 :hover 以来就一直存在。 因此,一个清晰的规范将是双倍有用。

.widget {color: salmon;width: 100%;} 
.widget:media(max-width: 320px) {color: whitesmoke;width: 321px;} 
/* the infinite loop is stopped, .widget is whitesmoke with a width of 321px */

同样,这将解决经典的 CSS 循环问题。

.widget {color: plum;} 
.widget:hover {color: orange;display: none;} 
/* the infinite loop is stopped, .widget is not displayed, but is otherwise orange */

问答

元素媒体查询应该能够定位页面,例如 .widget:media(page-max-width: 30em).widget:media(device-max-width: 30em) 吗?

是的,利用这种语法可以真正提高样式表的可读性。 我可以想象很多开发人员更喜欢这些类型的 :media 伪类查询而不是传统的 @media 查询。 事实上,许多开发人员已经在使用 SASS 中的嵌套来尝试执行类似的操作。

:media 伪类中的查询数量是否会增加选择器权重,因此 .widget:media((min-width: 2em) and (max-width: 30em)) 会胜过 .widget:media(max-width: 30em) 吗?

不会,因为 @media 查询不是选择器,因此没有权重。 相反,*:not(#foo) 的权重高于 *:not(.foo),因为伪类正在评估选择器,而选择器始终增加权重。 另一方面,@media (min-width: 5em) and (max-width: 500em) 的权重并不高于 @media (max-width: 500em)

灵感

Necolas 的推文Chris Coyier 关于 CSS 特定性MediaClass(为元素媒体查询提供 polyfill),以及与 Ian Hickson 的精彩对话,他教会了我 ::: 之间的区别。