【问题标题】:Can media queries resize based on a div element instead of the screen?媒体查询可以根据 div 元素而不是屏幕调整大小吗?
【发布时间】:2012-08-28 10:05:33
【问题描述】:

我想使用媒体查询根据元素所在的div 元素的大小调整元素的大小。我不能使用屏幕大小,因为div 就像网页中的小部件一样使用,它的大小可以变化。

更新

看起来现在正在做这方面的工作: https://github.com/ResponsiveImagesCG/cq-demos

【问题讨论】:

  • 小部件的大小如何变化?您的页面是固定宽度(例如 960 像素),视口高于 1024 像素,还是两者都是流畅的?这还不清楚,知道会很有用
  • 小部件的大小可能会有所不同,就像我们在 Facebook 应用程序中显示的一样,我们显示的小部件与我们在普通网页上显示的小部件不同
  • 这个工作得很好,而且是一个相对较小的构建(~4kb 缩小)github.com/tysonmatanich/elementQuery
  • 好问题。我遇到的最相关的案例是具有许多插件和许多主题的产品/解决方案/框架。一些插件适用于某些主题,但有时您必须在自定义 CSS 中“修复它们”才能使用特定主题。如果插件开发人员可以选择根据屏幕大小和容器大小进行不同的设计,那么插件和主题的组合会更好,并且需要更少的自定义 CSS hack。

标签: css media-queries


【解决方案1】:

从布局的角度来看,使用现代技术是可能的。

它是由 Heydon Pickering 编造的(我相信)。他在这里详细介绍了这个过程:http://www.heydonworks.com/article/the-flexbox-holy-albatross

Chris Coyier 拿起它并在此处进行演示:https://css-tricks.com/putting-the-flexbox-albatross-to-real-use/

为了重申这个问题,我们在下面看到 3 个相同的组件,每个由三个橙色 div 组成,标记为 abc

后两个块垂直显示,因为它们在水平空间上受到限制,而顶部组件 3 个块是水平布局的。

它使用flex-basis CSS 属性和 CSS 变量来创建这种效果。

.panel{
  display: flex;
  flex-wrap: wrap;
  border: 1px solid #f00;
  $breakpoint: 600px;
  --multiplier: calc( #{$breakpoint} - 100%);
  .element{
    min-width: 33%;
    max-width: 100%;
    flex-grow: 1;
    flex-basis: calc( var(--multiplier) * 999 );
  }
}

Demo

Heydon 的文章有 1000 字的详细解释,我强烈推荐阅读。

2021/22 更新

正如其他答案中提到的,容器查询即将到来。它有一个完整的规范,它的用法在 MDN 上有详细说明:

https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries

还有一个 polyfill 可以让还不支持它的浏览器加速:

https://github.com/GoogleChromeLabs/container-query-polyfill

这里有一个很好的概述视频:

https://www.youtube.com/watch?v=gCNMyYr7F6w

【讨论】:

    【解决方案2】:

    您可以使用ResizeObserver API。它仍处于早期阶段,因此并非所有浏览器都支持它(但有几个 polyfill 可以帮助您)。

    此 API 允许您在调整 DOM 元素大小时附加事件侦听器。

    Demo 1 - Demo 2

    【讨论】:

    【解决方案3】:

    经过近 十年 的工作——通过提案、概念验证、讨论和更广泛的 Web 开发人员社区的其他贡献——CSS 工作组终于奠定了一些必要的基础容器查询written into a future edition of the CSS Containment spec!有关此类功能如何工作和使用的更多详细信息,请查看 Miriam Suzanne 的extensiveexplainer

    希望我们很快就会看到这样一个系统的强大的跨浏览器实现。这是一个艰苦的等待,但我很高兴,由于循环依赖或无限循环或你有什么,我们不再必须接受它作为 CSS 的不可克服的限制(这些仍然是某些方面的潜在问题)提议的设计,但我相信 CSSWG 会找到办法)。


    媒体查询的设计目的不是基于页面中的元素。它们被设计为基于设备或media types 工作(因此它们被称为 media 查询)。 widthheight 和其他基于尺寸的媒体功能均指基于屏幕的媒体中视口或设备屏幕的尺寸。它们不能用于引用页面上的某个元素。

    如果您需要根据页面上某个 div 元素的大小应用样式,则必须使用 JavaScript 来观察该 div 元素大小的变化,而不是媒体查询。

    或者,自此答案的原始发布以来引入了更现代的布局技术,例如 flexbox 和自定义属性等标准,您可能根本不需要媒体或元素查询。 Djave provides an example.

    【讨论】:

    • 我听说过某种方法可以使用带有媒体查询的函数来获取包含元素的大小。有什么方法可以将它与媒体查询结合起来调整元素的大小?
    • 您必须使用 JS 定期获取元素的宽度并做出相应的反应(定期 = 每秒左右,否则会减慢某些浏览器的速度;因此 = 通过切换类来设置小部件的样式,如果你想要最快的方法)。
    • 要在本地完成这项工作,我们需要@element 查询。 W3C 有一些关于@media 查询的押韵/原因的很好的文档:w3.org/TR/css3-mediaqueries/#width(此链接将您带到讨论宽度的部分 --- 媒体类型的宽度,而不是其中包含的元素)
    • 这是我一直在寻找的 @container@element,其中孩子响应父大小而不是浏览器/媒体大小。遗憾的是,它似乎还没有准备好。
    【解决方案4】:

    对于我来说,我通过设置 div 的最大宽度来做到这一点,因此对于小部件不会受到影响,并且由于最大宽度样式而调整了大部件的大小。

      // assuming your widget class is "widget"
      .widget {
        max-width: 100%;
        height: auto;
      }
    

    【讨论】:

    • 问题中提到widget大小可能会有所不同,设置max-width不会在容器宽的时候改变widget的大小。 .widget 只是作为小部件 div 类的示例。
    【解决方案5】:

    我也在考虑媒体查询,但后来发现:

    只需创建一个包装器<div>,其百分比值为padding-bottom,如下所示:

    div {
      width: 100%;
      padding-bottom: 75%;
      background:gold; /** <-- For the demo **/
    }
    &lt;div&gt;&lt;/div&gt;

    这将导致&lt;div&gt; 的高度等于其容器宽度的 75%(纵横比为 4:3)。

    这种技术还可以与媒体查询和一些关于页面布局的特殊知识相结合,以获得更细粒度的控制。

    这足以满足我的需要。这也可能足以满足您的需求。

    【讨论】:

      【解决方案6】:

      正如@BoltClock 在接受的答案中所写,目前仅使用 CSS 是不可能的,但您可以使用 JavaScript 解决这个问题。

      我创建了一个容器查询(又名元素查询)prolyfill 来解决此类问题。它的工作方式与其他脚本略有不同,因此您不必编辑元素的 HTML 代码。您所要做的就是包含脚本并在您的 CSS 中使用它,如下所示:

      .element:container(width > 99px) {
          /* If its container is at least 100px wide */
      }
      

      https://github.com/ausi/cq-prolyfill

      【讨论】:

        【解决方案7】:

        几年前我遇到了同样的问题,并资助了一个插件的开发来帮助我的工作。我已将插件作为开源发布,因此其他人也可以从中受益,您可以在 Github 上获取它:https://github.com/eqcss/eqcss

        有几种方法可以根据我们对页面上元素的了解来应用不同的响应式样式。以下是 EQCSS 插件允许您用 CSS 编写的一些元素查询:

        @element 'div' and (condition) {
          $this {
            /* Do something to the 'div' that meets the condition */
          }
          .other {
            /* Also apply this CSS to .other when 'div' meets this condition */
          }
        }
        

        那么使用 EQCSS 的响应式样式支持哪些条件?

        重量查询

        • px 中的最小宽度
        • % 中的最小宽度
        • px 中的最大宽度
        • % 中的最大宽度

        身高查询

        • px 中的最小高度
        • % 中的最小高度
        • px 中的最大高度
        • % 中的最大高度

        计数查询

        • 最少字符
        • 最大字符数
        • 分钟线
        • 最大线数
        • min-children
        • 最大儿童

        特殊选择器

        在 EQCSS 元素查询中,您还可以使用三个特殊的选择器来更具体地应用您的样式:

        • $this(匹配查询的元素)
        • $parent(与查询匹配的元素的父元素)
        • $root(文档的根元素,&lt;html&gt;

        元素查询允许您从单独的响应式设计模块组成布局,每个模块都对它们在页面上的显示方式有一点“自我意识”。

        使用 EQCSS,您可以设计一个从 150 像素宽到 1000 像素宽的小部件看起来不错,然后您可以使用任何模板(在任何网站上)自信地将该小部件放入任何页面的任何侧边栏中,并且

        【讨论】:

          【解决方案8】:

          我认为您可以完全使用 css 完成您想要的唯一方法是为您的小部件使用流体容器。如果容器的宽度是屏幕的百分比,那么您可以根据容器的宽度使用媒体查询来设置样式,因为您现在将知道每个屏幕的尺寸是什么容器的尺寸。例如,假设您决定将容器的屏幕宽度设为 50%。那么对于 1200px 的屏幕宽度,你知道你的容器是 600px

          .myContainer {
            width: 50%;
          }
          
          /* you know know that your container is 600px 
           * so you style accordingly
          */
          @media (max-width: 1200px) { 
            /* your css for 600px container */
          }
          

          【讨论】:

          • 不,它在屏幕上看起来很难看。屏幕尺寸变化更快,但元素出现在屏幕上的时间更晚且更小。
          【解决方案9】:

          iframe 内的媒体查询可以用作元素查询。我已经成功地实现了这一点。这个想法来自 Zurb 最近关于Responsive Ads 的帖子。没有Javascript!

          【讨论】:

            【解决方案10】:

            我刚刚创建了一个 javascript shim 来实现这个目标。如果您愿意,可以看一下,这是一个概念验证,但请注意:这是一个早期版本,还需要一些工作。

            https://github.com/marcj/css-element-queries

            【讨论】:

              【解决方案11】:

              这个问题很模糊。正如 BoltClock 所说,媒体查询只知道设备的尺寸。但是,您可以将媒体查询与下行选择器结合使用来执行调整。

              .wide_container { width: 50em }
              
              .narrow_container { width: 20em }
              
              .my_element { border: 1px solid }
              
              @media (max-width: 30em) {
                  .wide_container .my_element {
                      color: blue;
                  }
              
                  .narrow_container .my_element {
                      color: red;
                  }
              }
              
              @media (max-width: 50em) {
                  .wide_container .my_element {
                      color: orange;
                  }
              
                  .narrow_container .my_element {
                      color: green;
                  }
              }
              

              唯一的其他解决方案需要 JS。

              【讨论】:

                猜你喜欢
                • 2021-11-09
                • 1970-01-01
                • 2017-01-19
                • 2014-04-28
                • 2013-05-12
                • 2021-10-23
                相关资源
                最近更新 更多