如何使用弹性框重新排序 div?

Posted

技术标签:

【中文标题】如何使用弹性框重新排序 div?【英文标题】:How to reorder divs using flex box? 【发布时间】:2018-02-03 15:08:28 【问题描述】:

我试图为我的 DOM 保持一个 seo 友好和语义结构,而不是重复整个元素以将它们显示在不同的位置。

我的布局基于display: flex 项目。我尝试实现以下目标:

需要了解的重要事项:

我不想根据窗口宽度显示/隐藏 div(以避免不必要的重复) 所有 div 都没有已知或固定的高度 在台式机上 div 应该垂直居中,而右列构建一个标签组(表现得像一个 div) 布局需要至少支持 IE11+

是否有唯一的 css 解决方案来实现这一点?

如果没有,使用 javascript 将绿色的 div 剪下并将其内容粘贴到粉红色的 div 中会很容易。但是我确实担心使用它的性能和“闪烁”,尽管调整浏览器的大小会使它变得更加复杂。我是否让这变得不必要的复杂?

这里是一个显示工作解决方案但使用 javascript 的小提琴:

CODEPEN DEMO

【问题讨论】:

Flexbox 有一个 order 属性正是为了这个目的。如果您希望 html 中的第二个 div 显示在顶部,您可以在 CSS 中为该 div 执行 order: 1 基本上,这对于 flexbox 来说是非常困难,如果不是不可能的话。许多浏览器不支持任何必需的属性。 CSS Grid 可能是一个选项。 @cjl750 感谢您的提示。如果您仔细阅读或查看演示(我在其中使用过),您会发现这并不能解决问题,但可以作为解决问题的开始。 @Paulie_D 关于 CSS 网格的一个问题是,它们经常使用 floats。使用浮点数很容易实现,而您需要将一个对象定义为“更高”的对象。如果我不能做到这一点,我认为很难找到一个有效的浮动解决方案......而不是我猜的 javascript。 CSS Grid 与float没有任何关系。这是一种完全不同的布局方法......因此大写“G”。 【参考方案1】:

一般来说,您不能单独使用 Flexbox 来做到这一点,尽管可能会根据每个给定的情况做出妥协。

单独使用 Flexbox,使用固定高度,就可以做到这一点

* 
  box-sizing: border-box;


body, html 
  margin: 0;


.flex 
  width: 90%;
  margin: 5vh auto;
  height: 90vh;
  background: rgba(0, 0, 0, 0.05);  
  display: flex;
  flex-flow: column wrap;

.flex div 
  flex: 1;
  width: 50%;

.flex div:nth-child(2) 
  order: -1;

.flex::before 
  content: '';
  height: 100%;


@media (max-width:768px) 
  .flex div 
    width: auto;
  
  .flex::before 
    display: none;
  
 .flex div:nth-child(2) 
    order: 0;
  



/*  styling  */
.flex-child 
  color: white;
  font-size: 2em;
  font-weight: bold;

.flex-child:nth-child(1) 
  background: #e6007e;

.flex-child:nth-child(2) 
  background: #f4997c;

.flex-child:nth-child(3) 
  background: #86c06b;
<div class="flex">
  <div class="flex-child">
    <div>Top/Right</div>
  </div>
  <div class="flex-child">
    <div>Center/Left</div>
  </div>
  <div class="flex-child">
    <div>Bottom/Right</div>
  </div>
</div>

在这种情况下,不允许固定高度,您可以将 Flexbox 和 float 结合使用。

通过使用 Flexbox 为移动设备设置它,您首先在标记中添加 center 项,然后使用 ordertop 和 底部。

通过媒体查询,您只需将 flex 容器 设为块元素并使用floatleft 定位在左侧,right 向右。

* 
  box-sizing: border-box;


body, html 
  margin: 0;


.flex 
  max-width: 1024px;
  width: 90%;
  margin: 5vh auto;
  height: 90vh;
  background: rgba(0, 0, 0, 0.05);
  
  display: flex;
  flex-direction: column;


.flex-child 
  color: white;
  font-size: 2em;
  font-weight: bold;
  padding: 5%;
  flex-basis: 33.333%;

  display: flex;
  align-items: center;


.flex-child:nth-child(1) 
  background: #e6007e;
  order: 1;

.flex-child:nth-child(2) 
  background: #f4997c;

.flex-child:nth-child(3) 
  background: #86c06b;
  order: 2;


@media (min-width: 768px) 
  .flex 
    display: block;
  
  .flex-child 
    width: 50%;
  
  .flex-child:nth-child(1) 
    float: left;
    height: 100%;
  
  .flex-child:nth-child(2),
  .flex-child:nth-child(3) 
    float: right;
    height: 50%;
  
<div class="flex">
  <div class="flex-child">
    <div>Center/Left</div>
  </div>
  <div class="flex-child">
    <div>Top/Right</div>
  </div>
  <div class="flex-child">
    <div>Bottom/Right</div>
  </div>
</div>

更新

这是另一个结合 Flexbox 和position: absolute 的版本,它也可以在桌面模式

中垂直居中项目

已更新,添加了一个脚本来控制,因此绝对定位的元素不会比正确的项目大,如果是这样,请调整 flex 容器的高度。

请注意,该脚本绝不是优化的,它只是显示在某些情况下如何修复

(function() 

  window.addEventListener("resize", resizeThrottler, false);

  var fp = document.querySelector('.flex');
  var fi = fp.querySelector('.flex-child:nth-child(1)');
  var resizeTimeout;
  function resizeThrottler() 
    // ignore resize events as long as an actualResizeHandler execution is in the queue
    if ( !resizeTimeout ) 
      resizeTimeout = setTimeout(function() 
        resizeTimeout = null;
        actualResizeHandler();
     
       // The actualResizeHandler will execute at a rate of 15fps
       , 66);
    
  

  function actualResizeHandler() 
    // handle the resize event
    if (fp.offsetHeight <= fi.offsetHeight) 
      fp.style.cssText = 'height: '+fi.offsetHeight+'px';
     else 
      fp.style.cssText = 'height: auto';
    
  

  window.addEventListener('load', function() 
    actualResizeHandler();
  )
  
());
* 
  box-sizing: border-box;


body, html 
  margin: 0;


.flex 
  position: relative;
  max-width: 1024px;
  width: 90%;
  margin: 5vh auto;
  height: 90vh;
  background: rgba(0, 0, 0, 0.05);
  
  display: flex;
  flex-direction: column;


.flex-child 
  color: white;
  font-size: 2em;
  font-weight: bold;
  padding: 5%;


.flex-child:nth-child(1) 
  order: 1;

.flex-child:nth-child(3) 
  order: 2;


.flex-child:nth-child(1) div 
  background: #e6007e;

.flex-child:nth-child(2) div 
  background: #f4997c;

.flex-child:nth-child(3) div 
  background: #86c06b;


@media (min-width: 768px) 
  .flex 
    justify-content: center;
  
  .flex-child 
    width: 50%;
  
  .flex-child:nth-child(1) 
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
  
  .flex-child:nth-child(n+2) 
    margin-left: 50%;
  
<div class="flex">
  <div class="flex-child">
    <div>Center/Left<br>with more<br>content<br>than any<br>of the<br>other items<br>other items<br>other items<br>other items<br>other items</div>
  </div>
  <div class="flex-child">
    <div>Top/Right<br>with more<br>content</div>
  </div>
  <div class="flex-child">
    <div>Bottom/Right<br>with more</div>
  </div>
</div>

使用脚本还可以在元素之间重新排序/移动项目。

堆栈sn-p

您还可以将其与媒体查询结合使用,并使用它对元素进行实际的重新排序

$( document ).ready(function() 
  $(window).resize(function() 
    if ($( window ).width() < 600 ) 
      $(".one").insertBefore("#b");
     else 
      $(".one").insertBefore(".two");
    
  );
);
.outer, #flex, #flex2 
  display: flex;
  flex-direction: column;

#a 
  order: 4;
  background: #ccc;

#b 
  order: 1;
  background: #aaa;

#c 
  order: 3;
  background: #d33;

.one 
  order: 2;
  background: #aaa;

.two 
  order: 5;
  background: #aaa;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="outer">
  <div id="flex">
    <div id="a">A</div>
    <div id="b">B</div>
    <div id="c">C</div>
  </div>

  <div id="flex2">
    <div class="one">Show me 2nd</div>
    <div class="two">Show me 5th</div>
  </div>

</div>

更新 2(已回复 at another question 但后来移至此处)

如果我们谈论较小的项目,例如标题或较小的菜单,则可以执行许多网站平台提供商(例如“squarespace”、“weebly”、“wordpress”等)所做的事情。他们的模板包含不同的标记结构,其中一个项目有时存在两次,一个在桌面上可见,另一个在移动设备上可见。

此外,如此之小,在性能方面几乎没有什么问题(而且我个人认为这没有什么问题,而不是重复的 CSS 规则,每个屏幕尺寸都有一个规则,并且很乐意这样做而不是介绍脚本)。

Fiddle demo

堆栈sn-p

.container 
  display: flex;

.container > div 
  width: 50%;

.container div:nth-child(-n+2) 
  border: dashed;
  padding: 10px;

.container > div:nth-child(1) 
  display: none;                                  /*  hide outer "Flower"  */


@media (max-width:768px) 
  .container 
    flex-direction: column;
  
  .container div 
    width: auto;
  
 .container div:nth-child(1) 
    display: block;                               /*  show outer "Flower"  */
  
  .container div:nth-child(3) div:nth-child(1) 
    display: none;                                /*  hide inner "Flower"  */
  
<div class="container">
  <div>Flower</div>
  <div>Tree</div>
  <div>
    <div>Flower</div>
    <div>Bee</div>
  </div>
</div>

【讨论】:

感谢您的回答和时间。虽然此代码在固定高度 (50%) 下工作,但它在未知高度下无法完成相同的工作。这就是使用float 作为解决方案的问题。在我的情况下,在没有已知高度的情况下将其垂直居中的部分很重要。 @MarianRick 我更新了它以桌面模式为中心...顺便说一句,你投反对票了吗?? 再次感谢。正如我试图在图像中暗示的那样,它不是关于将每个 div 的内容集中在右列中。这是关于将两个 div “作为一个标签团队”居中。这样它们就表现为一个单独的 div,它与左 div 垂直对齐。这就是为什么在粉色 div 上方和绿色 div 下方有空白区域。你明白我的意思还是我应该创建一个例子? 是的。不是为了伤害或冒犯您,而是为了保存本网站内容的质量。目前,您的解决方案解决了问题中提出的另一个问题。当然,如果它针对问题中所述的确切问题,我会更改它。在这个 codepen 中有一个使用 javascript 的工作演示。我开始质疑,如果没有 js 是否可能:codepen.io/marianrick/pen/wqxVOg?editors=1010 @MarianRick 好吧,当有人积极地帮助你时,投反对票是一种不好的方式来表达感谢你帮助我。当我停止询问和改进,给你留下一个我能理解的无效解决方案时......不过,当有人以任何方式帮助你时,我发现很难理解反对票......

以上是关于如何使用弹性框重新排序 div?的主要内容,如果未能解决你的问题,请参考以下文章

使用弹性框如何在 div 下居中文本

如何在不影响其兄弟位置的情况下将 div 绝对定位在弹性框中? [复制]

如何将弹性框放置在页面的中心? [复制]

如何在弹性框外显示悬停或工具提示

如何在特定级别重新排序多索引数据框列

哪个 CSS 选择器可用于选择处于包裹状态的弹性框项目?