内容折叠

Avatar of Chris Coyier
Chris Coyier

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

不到一年前,Trent Walton 发布了 内容编排,其中他哀叹了响应式布局的一些困难和局限性。

有时,当内容重新流向时,似乎所有的网站架构和规划都将付诸东流。

你必须承认,相当多的响应式设计最终会变成

  1. 将所有内容挤入一列
  2. 将侧边栏推到底部

*咳嗽* 这个网站就是这样 *咳嗽*

Trent 提到,可能更合适的做法是将内容“交错排列”。

交错排列

也就是说,将内容片段以更周到或更有用的方式折叠在一起,形成单列。

实际示例:广告折叠

考虑在大型浏览器窗口大小下的布局。 两列。 文章位于左侧的宽列中,广告位于右侧的窄列中。

在较窄的浏览器窗口大小下,我们决定降至单列。 此布局可能是使用浮动完成的,浮动至今仍然是最常见的布局方法。 不幸的是,这可能意味着将两列都设置为 100% 宽,并让它们的源顺序决定哪一个在上面。 意思是:将所有广告推到底部。 这可能不太理想。 更妙的做法可能是将广告折叠到内容中。

但是怎样做呢?

可能有很多方法可以做到这一点。 使用 JavaScript,您可以测量窗口宽度并在 DOM 中重新排列内容。 这对我来说似乎很繁重,但浏览器的支持会很好。 我更倾向于依靠 CSS 来做这种事情。 这正是 CSS 的(应该)用处。 网格布局 可能为我们提供了一些可能性,但对于本教程,让我们使用最新的 CSS 区域,这是 Adobe 的贡献。

友情提示:这些东西非常新,可能会发生变化。 当我在 2012 年 3 月写这篇文章时,这个演示在 Chrome 中有效。 现在在 2013 年 1 月,它不再有效了。 Chrome 15-18 具有部分支持,然后 它在 19 中被拉掉了,尽管 Chrome 仍然报告支持该属性。

HTML

<section class="main-content">

  <article> ... </article>

  <div class="ad-region-1">
    <!-- empty, ads flow into here as needed -->
  </div>

  <article> ... </article>

  <div class="ad-region-2">
    <!-- empty, ads flow into here as needed -->
  </div>

  <article> ... </article>

  <div class="ad-region-3">
    <!-- empty, ads flow into here as needed -->
  </div>

</section>

<aside>
   <!-- Fallback content in this flow region, probably clone #ad-source -->
</aside>

<!-- Source of flowing content, essentially hidden as an element -->
<div id="ad-source">
  <a href="#"><img src="ads/1.jpg"></a>
  <a href="#"><img src="ads/2.jpg"></a>
  <a href="#"><img src="ads/3.jpg"></a>
  <a href="#"><img src="ads/4.png"></a>
</div>

请注意,"内容"(我们的广告)位于页面底部的 <div> 中。 一旦我们设置了 CSS 区域,该元素将基本上被隐藏,其中的内容将流入我们告诉它的区域。

CSS

我们首先告诉我们的内容持有 div#ad-source 将其内容流入“命名流”。

#ad-source {
  -webkit-flow-into: ads;
  -ms-flow-into: ads;
}

我只在这里使用两个供应商前缀,因为这是目前唯一的支持。 我建议不要使用无前缀版本,因为这些东西在最终实现中可能会发生变化。

'ads' 是我们随意编造的任意名称。 它可以是任何东西,就像给 CSS 动画命名一样。

现在,我们设置了内容流入的区域。 首先,流入 aside,然后流入文章之间的交错 div。

aside, [class^='ad-region'] {
  -webkit-flow-from: ads;
  -ms-flow-from: ads;
}

在我们的示例中,在宽浏览器窗口宽度下,aside 足够大,可以容纳所有内容。 在较窄的宽度下,通过媒体查询,我们隐藏 aside,迫使内容流入 div。

[class^='ad-region'] {
  display: none;
  height: 155px;
  width: 100%; /* Weird that this is required */
}

@media (max-width: 800px) {
  [class^='ad-region'] {
    display: block;
  }
  [class^='ad-region']:last-child {
    height: 300px; /* I wish height auto worked */
  }
  aside {
    display: none;
  }
}

语义

所以,我们在周围放了一些空元素。 语义不强。 我也不确定这对可访问性有什么影响。 我确实知道 DOM 没有改变。 所有内容,无论它“流向”哪里,仍然在“源”中(具有 flow-into 属性的元素)。

不过,事情是这样的:区域是与布局样式无关的。 在这个示例中,我们仍然使用浮动进行布局,但您使用的布局样式实际上并不重要。 区域与 CSS 网格 配合使用可能更强大、更具语义(我只是不知道)。

浏览器支持

CSS 区域在Chrome 16 到 20中发布,然后在 21-22 中置于“启用 CSS 区域”标志下,现在在 Chrome 23+ 中置于“启用实验性 WebKit 功能”标志下。 它在Safari 5.2(可作为开发版或 WebKit 夜间版)中有效。 据说它在 IE 10 中有效,但我无法使其生效。

演示和下载

为了您的快乐

查看演示   下载文件

请注意上面的浏览器支持,它非常有限。

另请注意,在某些相当宽的浏览器窗口宽度下,aside 中的广告会被切断。 我将其保留在那里是为了说明区域不会自然地扩展高度,您需要自己考虑这一点。

更新:这个演示曾经有效,后来被破坏,现在又可以使用了。 我通过 Adobe 的 CSS 区域 Polyfill 使其生效。 当规范和浏览器支持稳定下来后,这将需要重新审视。

浏览器检测

这种 HTML 和 CSS 本身在不支持 CSS 区域的浏览器中会很糟糕。 页面底部会随机出现一组广告。 相反,我添加了一些 JavaScript(基于此)来测试它,并根据支持情况向 html 元素应用类。

// Generic Testing Function
var supports = (function() {  
   var div     = document.createElement('div'),  
       vendors = 'Khtml Ms O Moz Webkit'.split(' '),  
       len     = vendors.length;  
  
   return function(prop) {  
      if (prop in div.style) return true;  
  
      prop = prop.replace(/^[a-z]/, function(val) {  
         return val.toUpperCase();  
      });  
  
      while (len--) {  
         if (vendors[len] + prop in div.style) {   
            return true;  
         }  
      }  
      return false;  
   };  
})();  
  
// Test
if ( supports('flowInto') ) { 
   $("html").addClass('cssregions');  
} else {
   $("html").addClass('no-cssregions'); 
}

这样,我们可以做这样的事情来确保回退正常。

#ad-source {
  display: none;
}
.cssregions #ad-source {
  display: block;
  -webkit-flow-into: ads;
  -ms-flow-into: ads;
}

此外,将 div#ad-source 的内容复制到 aside 中,以便至少在最宽的浏览器窗口宽度下,广告会出现在那里。

这应该可以正常工作,但它在 Chrome 中报告了误报,因为 Chrome 在 Chrome 23 中删除了对它的支持。 不过,您可以打开支持……
  1. 使用浏览器栏导航到 chrome://flags
  2. 如果您运行的是 Chrome 21 或 Chrome 22,请找到“启用 CSS 区域”标志并启用它。
  3. 如果您运行的是 Chrome 23 或更高版本,请找到“启用实验性 WebKit 功能”标志并启用它。
  4. 通过单击左下角的“立即重新启动”按钮重新启动浏览器。

如果您想将此测试添加到 Modernizr,您可以执行以下操作。

Modernizr.addTest('regions', Modernizr.testAllProps('flow-into'));

希望他们在未来的版本中将其作为一种选择添加。

我希望改进的地方

  • 我希望您可以根据内容流入的容器元素样式化内容。 这可能是一个问题,因为在不同容器中的不同样式可能会导致重新流向,从而将内容推回到容器之外,从而导致无限循环的悲伤,但也许对此有一些解决方案。
  • 我希望块级元素即使使用 flow-from 属性也仍然是块级元素。 很奇怪,您必须将它们设置为 width: 100%;
  • 我希望 height: auto; 在具有最后一段流入内容的区域上有效。 我理解大多数流区域无法做到这一点,因为这样它们就会扩展以适合所有内容,而不是继续流入,但最后一个区域应该能够知道它剩下的内容并自然扩展。
  • 我希望你能flow-fromflow-into同一个元素。这样,一个语义元素就可以成为源,只有当它缩小或消失时,其他区域才会被填充。