How to reorder divs using flex box?

前端 未结 1 2002
误落风尘
误落风尘 2020-11-29 13:11

I am trying to keep a seo friendly and semantic structure for my DOM, without repeating whole elements to display them in various positions.

My layout is based on

1条回答
  •  囚心锁ツ
    2020-11-29 13:36

    In general, you can't do this with Flexbox alone, though there might be a compromise based on each given case.

    With Flexbox alone, using fixed height, you can accomplish this

    * {
      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;
    }
    Top/Right
    Center/Left
    Bottom/Right

    In this case, where no fixed height is allowed, you can combine Flexbox and float.

    By set up it for mobile using Flexbox where you add the center item first in the markup and then, with order, move it between the top and bottom.

    With a media query you then simply make the flex container a block element and use float to position the left to the left and the right to the 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%;
      }
    }
    Center/Left
    Top/Right
    Bottom/Right


    Update

    Here is another version combining Flexbox with position: absolute, which also vertically center the items in desktop mode

    Updated, added a script to control so the absolute positioned element won't get bigger than the right items, and if so, adjust the flex containers height.

    Note, the script is by no means optimized, it is only there to show how a fix in certain situations

    (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%;
      }
    }
    Center/Left
    with more
    content
    than any
    of the
    other items
    other items
    other items
    other items
    other items
    Top/Right
    with more
    content
    Bottom/Right
    with more


    With script one can also reorder/move items between elements.

    Stack snippet

    You can also combine this with a media query, and use it to do the actual re-order of the elements

    $( 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;
    }
    
    
    
    A
    B
    C
    Show me 2nd
    Show me 5th


    Update 2 (answered at another question but later moved here)

    If we talk about smaller items, like a header or smaller menus, one can do what many website platform providers like "squarespace", "weebly", "wordpress", etc does. Their templates holds different markup structures, where an item sometimes exist twice, one visible for desktop, another for mobile.

    Also, being so small, there will be less to nothing when it comes to performance (and personally I don't see anymore issue with this than having duplicate CSS rules, one for each screen size, and happily do this instead of introducing script).

    Fiddle demo

    Stack snippet

    .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"  */
      }
    }
    Flower
    Tree
    Flower
    Bee

    0 讨论(0)
提交回复
热议问题