flex space-between最後一行對齊問題的解決方案

  • 2020 年 2 月 11 日
  • 筆記

背景

常見的一個圖文列表設計,通常是這樣的,兩端頂著容器,中間的間距平均分,如下圖的某東商品列表的設計:

列表是這樣自適應的,當視窗足夠放多少個商品就放多少個,然後各個商品項目之間的間距平均分。由於每個人的視窗都可能不同,因此所看到的間距或者每一行的個數都會不同。

方案

想到這種設計,我們學過flex就知道,非常像flex的justify-content: space-between的效果,因此我們自然這樣實現:

.flex {    list-style: none;    margin: 0;    padding: 0;    box-sizing: border-box;    display: flex;    flex-wrap: wrap;    justify-content: space-between;  }  .demo1 > .flex__item {    flex-basis: 200px;    margin-top: 1rem;    text-align: center;    box-sizing: border-box;  }    .demo1 > .flex__item img {    width: 100%;  }
<ul class="flex demo1">    <li class="flex__item">      <img src="http://via.placeholder.com/100" />      <p>        圖片      </p>    </li>    <li class="flex__item">      <img src="http://via.placeholder.com/100" />      <p>        圖片      </p>    </li>    <li class="flex__item">      <img src="http://via.placeholder.com/100" />      <p>        圖片      </p>    </li>    <li class="flex__item">      <img src="http://via.placeholder.com/100" />      <p>        圖片      </p>    </li>    <li class="flex__item">      <img src="http://via.placeholder.com/100" />      <p>        圖片      </p>    </li>  </ul>

demo: https://jsbin.com/yulevutodo/edit?html,css,output

我們看到效果,最後一行不正確,應該向左對齊才對,詳細比較過多種方案,個人覺得還是增加空白項這種方案最佳,就是往後面多加幾個空白項,你至少要放入 最大屏能顯示的個數減去1個就行了,當然放得更多也是顯示正常的,但是沒有必要。

<ul class="flex demo1">    <li class="flex__item">      <img src="http://via.placeholder.com/100" />      <p>        圖片      </p>    </li>    <li class="flex__item">      <img src="http://via.placeholder.com/100" />      <p>        圖片      </p>    </li>    <li class="flex__item">      <img src="http://via.placeholder.com/100" />      <p>        圖片      </p>    </li>    <li class="flex__item">      <img src="http://via.placeholder.com/100" />      <p>        圖片      </p>    </li>    <li class="flex__item">      <img src="http://via.placeholder.com/100" />      <p>        圖片      </p>    </li>  <!-- placeholder max column * placeholder - 1-->          <li class="flex__item placeholder"></li>          <li class="flex__item placeholder"></li>          <li class="flex__item placeholder"></li>          <li class="flex__item placeholder"></li>  </ul>
.flex {    list-style: none;    margin: 0;    padding: 0;    box-sizing: border-box;    display: flex;    flex-wrap: wrap;    justify-content: space-between;  }    .demo1 > .flex__item {    flex-basis: 200px;    margin-top: 1rem;    text-align: center;    box-sizing: border-box;  }    .demo1 > .flex__item img {    width: 100%;  }    .placeholder {    visibility: hidden !important;    height: 0 !important;    border: 0 !important;    padding: 0 !important;    margin: 0 !important;  }

demo: https://jsbin.com/koyoxupivo/edit?html,css,output

方案研究過程

一看到這種設計,我們真的就會自然而然想到了flex的 justify-content: space-between; 但由於最後一行的對齊問題,讓我們頭疼。那就不用 justify-content: space-between吧,改用默認的justify-content: flex-start試試,那麼靠右的間距就得計算了,如下:

     .list2 > .flex__item:nth-of-type(2n + 1) {          margin-right: calc((100% - 200px * 2) / 1);        }        .list3 > .flex__item:not(:nth-of-type(3n)) {          margin-right: calc((100% - 200px * 3) / 2);        }        .list4 > .flex__item:not(:nth-of-type(4n)) {          margin-right: calc((100% - 200px * 4) / 3);        }

一行放兩個項目時用.list2, 放3個項目時用.list3,放4個項目時用.list4等等等,僅僅這種只是做到了間距自適應,項目固定死了,我們想通過media去控制,雖然可以,但是顯然比上面複雜多了。如果說外框容器是定死的比如1000px,那麼每行的項目數目也是固定的,那可能還稍微好一些。

我們接著想,還不如直接用以前的display: inline-block 或者 float:left去實現呢,但是其實本質上跟 flex-start還是一樣的做法。

因此我覺得就只有放空項目方案是最佳的了,維護起來也方便。比如未來項目寬度優200px改成了100px,我們直接把200改成100再檢查一下空項目是否放的足夠。如果寬度也是自適應了,比如寬度佔32%,那把200px改成32%即可,100/32 = 3,因此任何視窗大小下,每行都是3個了,我們空項目只要放 3-1=2個即可。

還有更好的方法嗎

畢竟放了空項目,雖然說可以用vue/react等直接循環空項目出來,但還是感覺html還是有點臟。還有更好的方法嗎(除了用grid,因為grid的兼容性暫時還不行)?希望告知,感謝!

研究草稿

這個是我研究過程的草稿,比較亂:https://jsbin.com/qobuqakeri/edit?html,css,output