具有动态内容的 Flexbox 响应式超级菜单

Posted

技术标签:

【中文标题】具有动态内容的 Flexbox 响应式超级菜单【英文标题】:Flexbox Responsive Mega Menu with Dynamic Content 【发布时间】:2017-01-30 04:20:41 【问题描述】:

我正在创建一个大型动态导航菜单,我希望它看起来像这样:

[----------- 100% PAGE WIDTH -----------] | GROUP A | GROUP C | GROUP F | GROUP G | | item | item | item | item | | item | | item | item | | | GROUP D | item | item | | GROUP B | item | item | | | item | | | | | item | GROUP E | | | | | item | | | |---------------------------------------| | | | | [------------- END OF PAGE -------------]

见我的JS Fiddle Example。

* 
  padding: 0;
  margin: 0;

body 
  background: #ccc;
  font-family: helvetica, arial;
  color: #444;

ul 
  list-style: none;

.mega-menu 
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
  padding: 15px;
  height: 50vh;
  background: #fff;

.mega-menu > li 
  display: flex;
  flex-direction: column;
  font-size: .7rem;
  padding-bottom: 15px;

.title 
  font-size: .7rem;
  font-weight: bold;
  line-height: 1;
  padding-bottom: 5px
<ul class="mega-menu">
  <li>
    <a class="title">News</a>
    <ul>
      <li>Top Stories</li>
      <li>Trending Stories</li>
      <li>Sports</li>
      <li>U.S.</li>
      <li>Global</li>
    </ul>
  </li>

  <li>
    <a class="title">Shows</a>
    <ul>
      <li>HBO</li>
      <li>CBS</li>
      <li>NBC</li>
      <li>CNN</li>
    </ul>
  </li>

  <li>
    <a class="title">Topics</a>
    <ul>
      <li>Top Stories</li>
      <li>Trending Stories</li>
      <li>Sports</li>
      <li>U.S.</li>
      <li>Global</li>
    </ul>
  </li>

  <li>
    <a class="title">Shows</a>
    <ul>
      <li>CBS</li>
      <li>NBC</li>
    </ul>
  </li>

  <li>
    <a class="title">Networks</a>
    <ul>
      <li>HBO</li>
      <li>CBS</li>
      <li>NBC</li>
      <li>CNN</li>
    </ul>
  </li>

  <li>
    <a class="title">Groups</a>
    <ul>
      <li>Top Stories</li>
      <li>Trending Stories</li>
      <li>Sports</li>
      <li>U.S.</li>
      <li>Global</li>
    </ul>
  </li>

  <li>
    <a class="title">Sections</a>
    <ul>
      <li>Top Stories</li>
      <li>Trending Stories</li>
      <li>Sports</li>
      <li>U.S.</li>
      <li>Global</li>
    </ul>
  </li>

  <li>
    <a class="title">Pilots</a>
    <ul>
      <li>HBO</li>
      <li>CBS</li>
      <li>NBC</li>
    </ul>
  </li>

  <li>
    <a class="title">Locations</a>
    <ul>
      <li>Denver</li>
      <li>Baltimore</li>
      <li>LA</li>
      <li>New York</li>
      <li>San Francisco</li>
      <li>New Orleans</li>
      <li>Jacksonville</li>
      <li>Calvery</li>
      <li>August</li>
    </ul>
  </li>

  <li>
    <a class="title">Cities</a>
    <ul>
      <li>Denver</li>
      <li>Baltimore</li>
      <li>LA</li>
      <li>New York</li>
      <li>San Francisco</li>
      <li>New Orleans</li>
      <li>Jacksonville</li>
      <li>Calvery</li>
      <li>August</li>
    </ul>
  </li>

  <li>
    <a class="title">News</a>
    <ul>
      <li>Top Stories</li>
      <li>Trending Stories</li>
      <li>Sports</li>
      <li>U.S.</li>
      <li>Global</li>
    </ul>
  </li>

  <li>
    <a class="title">Shows</a>
    <ul>
      <li>HBO</li>
      <li>CBS</li>
      <li>NBC</li>
      <li>CNN</li>
    </ul>
  </li>

  <li>
    <a class="title">Topics</a>
    <ul>
      <li>Top Stories</li>
      <li>Trending Stories</li>
      <li>Sports</li>
      <li>U.S.</li>
      <li>Global</li>
    </ul>
  </li>

  <li>
    <a class="title">Shows</a>
    <ul>
      <li>CBS</li>
      <li>NBC</li>
    </ul>
  </li>

  <li>
    <a class="title">Networks</a>
    <ul>
      <li>HBO</li>
      <li>CBS</li>
      <li>NBC</li>
      <li>CNN</li>
    </ul>
  </li>

  <li>
    <a class="title">Groups</a>
    <ul>
      <li>Top Stories</li>
      <li>Trending Stories</li>
      <li>Sports</li>
      <li>U.S.</li>
      <li>Global</li>
    </ul>
  </li>

  <li>
    <a class="title">Sections</a>
    <ul>
      <li>Top Stories</li>
      <li>Trending Stories</li>
      <li>Sports</li>
      <li>U.S.</li>
      <li>Global</li>
    </ul>
  </li>

  <li>
    <a class="title">Pilots</a>
    <ul>
      <li>HBO</li>
      <li>CBS</li>
      <li>NBC</li>
    </ul>
  </li>

  <li>
    <a class="title">Locations</a>
    <ul>
      <li>Denver</li>
      <li>Baltimore</li>
      <li>LA</li>
      <li>New York</li>
      <li>San Francisco</li>
      <li>New Orleans</li>
      <li>Jacksonville</li>
      <li>Calvery</li>
      <li>August</li>
    </ul>
  </li>

  <li>
    <a class="title">Cities</a>
    <ul>
      <li>Denver</li>
      <li>Baltimore</li>
      <li>LA</li>
      <li>New York</li>
      <li>San Francisco</li>
      <li>New Orleans</li>
      <li>Jacksonville</li>
      <li>Calvery</li>
      <li>August</li>
    </ul>
  </li>

  <li>
    <a class="title">News</a>
    <ul>
      <li>Top Stories</li>
      <li>Trending Stories</li>
      <li>Sports</li>
      <li>U.S.</li>
      <li>Global</li>
    </ul>
  </li>

  <li>
    <a class="title">Shows</a>
    <ul>
      <li>HBO</li>
      <li>CBS</li>
      <li>NBC</li>
      <li>CNN</li>
    </ul>
  </li>

  <li>
    <a class="title">Topics</a>
    <ul>
      <li>Top Stories</li>
      <li>Trending Stories</li>
      <li>Sports</li>
      <li>U.S.</li>
      <li>Global</li>
    </ul>
  </li>

  <li>
    <a class="title">Shows</a>
    <ul>
      <li>CBS</li>
      <li>NBC</li>
    </ul>
  </li>

  <li>
    <a class="title">Networks</a>
    <ul>
      <li>HBO</li>
      <li>CBS</li>
      <li>NBC</li>
      <li>CNN</li>
    </ul>
  </li>

  <li>
    <a class="title">Groups</a>
    <ul>
      <li>Top Stories</li>
      <li>Trending Stories</li>
      <li>Sports</li>
      <li>U.S.</li>
      <li>Global</li>
    </ul>
  </li>

  <li>
    <a class="title">Sections</a>
    <ul>
      <li>Top Stories</li>
      <li>Trending Stories</li>
      <li>Sports</li>
      <li>U.S.</li>
      <li>Global</li>
    </ul>
  </li>

  <li>
    <a class="title">Pilots</a>
    <ul>
      <li>HBO</li>
      <li>CBS</li>
      <li>NBC</li>
    </ul>
  </li>

  <li>
    <a class="title">Locations</a>
    <ul>
      <li>Denver</li>
      <li>Baltimore</li>
      <li>LA</li>
      <li>New York</li>
      <li>San Francisco</li>
      <li>New Orleans</li>
      <li>Jacksonville</li>
      <li>Calvery</li>
      <li>August</li>
    </ul>
  </li>

  <li>
    <a class="title">Cities</a>
    <ul>
      <li>Denver</li>
      <li>Baltimore</li>
      <li>LA</li>
      <li>New York</li>
      <li>San Francisco</li>
      <li>New Orleans</li>
      <li>Jacksonville</li>
      <li>Calvery</li>
      <li>August</li>
    </ul>
  </li>

  <li>
    <a class="title">News</a>
    <ul>
      <li>Top Stories</li>
      <li>Trending Stories</li>
      <li>Sports</li>
      <li>U.S.</li>
      <li>Global</li>
    </ul>
  </li>

  <li>
    <a class="title">Shows</a>
    <ul>
      <li>HBO</li>
      <li>CBS</li>
      <li>NBC</li>
      <li>CNN</li>
    </ul>
  </li>

  <li>
    <a class="title">Topics</a>
    <ul>
      <li>Top Stories</li>
      <li>Trending Stories</li>
      <li>Sports</li>
      <li>U.S.</li>
      <li>Global</li>
    </ul>
  </li>

  <li>
    <a class="title">Shows</a>
    <ul>
      <li>CBS</li>
      <li>NBC</li>
    </ul>
  </li>

  <li>
    <a class="title">Networks</a>
    <ul>
      <li>HBO</li>
      <li>CBS</li>
      <li>NBC</li>
      <li>CNN</li>
    </ul>
  </li>

  <li>
    <a class="title">Groups</a>
    <ul>
      <li>Top Stories</li>
      <li>Trending Stories</li>
      <li>Sports</li>
      <li>U.S.</li>
      <li>Global</li>
    </ul>
  </li>

</ul>

要求

    如果页面宽度增加,我希望有 更多 列,如果缩小,我希望有 less 列。

    李>

    如果我要添加两倍的项目,我希望列的高度变高,以便为其他项目留出空间。

    每组之间的填充/空白应相同。

    理想情况下我不会使用 javascript(但如果那是唯一的方法)。

问题

当我缩小屏幕高度/宽度时,内容会从菜单的右侧溢出。

想法

我已经搜索了一种 CSS 解决方案,但找不到一个不会在不均匀组之间添加间距的解决方案。 (例如Uneven whitespace)

我能想到的就是使用 JavaScript 动态设置 flexbox 父级的高度(增加高度直到最后一个项目组 (TITLE F) 完全显示并且不会溢出屏幕。

【问题讨论】:

您是否尝试过媒体查询来更改布局? 由于内容量是动态的并且可以改变菜单所需的高度,我认为媒体查询没有帮助。 我需要继续思考这个问题,但这是一个非常酷的问题。 Flex column wrap 在大多数浏览器中都有很多问题。它还没有真正准备好迎接黄金时段的 IMO。请参阅herehereherehere。如果可以,请坚持使用row wrap:jsfiddle.net/wc8c4ccm/2(只是一个基本模板/不适合您的内容) 我同意@Michael_B。您可以尝试 flex 或多列布局,但听起来两者都不能完全涵盖您的目标。 【参考方案1】:

可能是这样的(jsfiddle):

.mega-menu 
  -webkit-column-count:1;
  -moz-column-count:1;
  column-count:1;
  padding: 15px 15px 0;
  background: #fff;

@media (min-width: 200px) .mega-menu-webkit-column-count:2;-moz-column-count:2;column-count:2;
@media (min-width: 300px) .mega-menu-webkit-column-count:3;-moz-column-count:3;column-count:3;
@media (min-width: 400px) .mega-menu-webkit-column-count:4;-moz-column-count:4;column-count:4;
// ...
@media (min-width: 1800px) .mega-menu-webkit-column-count:18;-moz-column-count:18;column-count:18;
@media (min-width: 1900px) .mega-menu-webkit-column-count:19;-moz-column-count:19;column-count:19;
@media (min-width: 2000px) .mega-menu-webkit-column-count:20;-moz-column-count:20;column-count:20;
.mega-menu > li 
  display:inline-block;
  font-size: .7rem;
  padding-bottom: 15px;

它可能至少需要扩展到 4K 显示器的宽度。如果你有 SASS 或类似的,那会让事情变得不那么乏味。

它不提供内容感知列宽,让您猜测可能的最小列宽。

当您有很多项目要显示但没有滚动时,您提到的菜单从右侧脱落的问题实际上并不能通过任何解决方案来解决。考虑到较窄的显示宽度通常也具有较短的显示高度。屏幕越小,你能适应的就越少。可能需要安排较小的屏幕以减少菜单选项。

【讨论】:

在 775x500 的情况下,一些应该堆叠在一起的列在单个列中加倍。那里发生了什么? 我刚刚添加了li width: 100% ,到目前为止看起来很有希望。 jsfiddle.net/f18cfLxk 到目前为止,我看到的最大缺点是如果将组的数量减少到三个或四个,它仍然会创建一堆不必要的列。 @Justin 如果没有足够的内容,它会创建未使用的列。另一种方法是创建超宽列(尽管与列布局结合起来并不真正有用)。不幸的是,您的问题落入了两种可能的 CSS 解决方案、列或 flexbox 之间的裂缝中。因此,Javascript 助手可能是您的最佳选择。 我将使用 JavaScript 解决方案,但这仍然是一个很好的答案。谢谢!

以上是关于具有动态内容的 Flexbox 响应式超级菜单的主要内容,如果未能解决你的问题,请参考以下文章

html 超级简单的flexbox响应导航

如何使超级鱼下拉菜单响应?

如何在导航下方的响应式布局中显示 Div/ul/List 但与我的内容重叠?

Html/css:使用适合内容宽度的 figcaption 创建响应式图片库网格

始终在带有 flexbox 的按钮下方直接显示下拉菜单

响应式 flexbox 和重新排序子子项