发布于 2026-01-06 0 阅读
0

从零开始构建 Flex 布局以适应所有项目 Flex Box Layout DEV 的全球展示挑战赛,由 Mux 呈现:展示你的项目!

从零开始构建适用于所有项目的灵活布局

弹性盒布局

由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!

随着网格布局和弹性布局的日益普及,越来越多的开发者和公司不再使用框架,而是开始使用这些内置的 CSS 属性来构建布局。有时两者结合使用,有时则完全依赖其中一种。

我们先从 flex 开始,我发现它更有趣,因为它流畅易用,和往常一样,我会添加代码和解释以说明其用途。

控制箱式模型计算

这里有一个我通常会添加的全局变量,用来控制盒模型的计算,以确保所有元素都以这种更直观的方式进行尺寸调整。您可以在这里找到更多相关信息

  * { box-sizing: border-box; }

弹性盒布局

Flex布局默认不适用于行列式布局系统。这就是为什么你会看到有人说Grid布局是用于构建结构的3D布局,而Flex布局是用于展示内容的2D布局。

这相当准确,但你也可以通过在正确的属性上使用一些 flex 值来创建流畅的 3D 布局,让我们看看如何仅使用 flex 来模拟​​行列布局。

行元素

 .flexrow { 
   display: flex;
   flex-flow: row wrap;
 }
Enter fullscreen mode Exit fullscreen mode

这意味着将元素显示为 flex,并将流设置为行,如果 flex 子元素上的某些内容无法适应行,则需要换行。

细节:

显示:flex控制显示行为。

flex-flow是两个 flex 属性的封装,顺序为:flex-directionflex-wrap。在本例中,direction 为“row”,wrap 为 true/on。默认情况下,flex-wrap 属性设置为 nowrap,这对于我们的需求来说不太方便。

变通方法:

我分享两种不同的布局,用于不同的用途,它们可以组合、嵌套并“直接”使用。

1. 宽度相同的列

这种变通方法适用于有 N 列但所有列宽度完全相同的行。

 .flexrow.row-1-el > .element { 
   flex: 0 1 calc(100%/1); 
   max-width: calc(100%/1); 
 }
 .flexrow.row-2-el > .element { 
   flex: 0 1 calc(100%/2); 
   max-width: calc(100%/2);
 }
 .flexrow.row-3-el > .element { 
   flex: 0 1 calc(100%/3); 
   max-width: calc(100%/3);
 }
 /* and so... */
Enter fullscreen mode Exit fullscreen mode

请注意,唯一的区别在于类名和将布局宽度 100% 分割成的数字。

很容易理解,如果你想要一行包含两个元素(列),且这两个元素的宽度相同,你可以假设行宽为 100%,然后除以 2,得到两个宽度均为 50% 的元素。
由此我们可以得出以下结论:

<div class="flexrow row-2-el">
  <div class="element"> first column </div>
  <div class="element"> Second column </div>
</div>
Enter fullscreen mode Exit fullscreen mode

我们得到了两列,每列宽度为可用宽度的 50%。

列实现细节:

flex属性是 3 个属性的简写,这 3 个属性依次为:flex-growflex-shrinkflex-basis

在这个例子中,我们不希望这些元素以任何方式增长,因为我们设置的是相对于布局的固定值,而不是让弹性元素根据需要增长。同样,
我们也不希望这些元素缩小,原因也相同。`flex
-basis` 指定弹性元素的初始长度,我们为它们设置了计算出的百分位数,使它们占据我们想要或需要的区域。

正如我们之前提到的,flex-basis 是初始长度,为了在几乎所有情况下都能保持所需的宽度,我们还需要设置 max-width。如果我们希望列之间有分隔,我们会使用相同的计算公式,或者在计算公式的基础上减去一些边距。

不同断点对应不同的值:

由于我们将 flex 元素的子元素视为固定项(同时保持它们之间的 flex 行为),我们需要添加一些媒体查询,以便能够根据断点控制百分位宽度的值。

第一步——在 scss 文件顶部添加变量。

 $screen-xs: 480px;
 $screen-sm: 768px;
 $screen-md: 992px;
 $screen-lg: 1200px;
 $screen-xl: 1600px;
Enter fullscreen mode Exit fullscreen mode

断点定义示例:

 .flexrow.row-2-el > .element { 
      flex: 0 1 calc(100%/2);
      max-width: calc(100%/2);
 }

 @media(min-width: $screen-xs) {
   .flexrow.xs-row-2-el > .element { 
     flex: 0 1 calc(100%/2);
     max-width: calc(100%/2);
   } 
 }
Enter fullscreen mode Exit fullscreen mode

HTML 结构示例

现在是时候举个HTML结构示例来提供更多背景信息了:

<div class="flexrow row-1-el sm-row-2-el md-row-3-el>
  <div class="element> content </div>
  <div class="element> content </div>
  <div class="element> content </div>
</div>
Enter fullscreen mode Exit fullscreen mode

从 0 到 sm 断点,每行显示一个元素。从 sm 断点到 md 断点,每行显示两个元素。由于我们有 3 个元素,所以会看到一行显示两个元素,然后是一行显示一个元素。从 md 断点到无穷大,每行显示三个元素。

Sass/SCSS 代码优化

现在我们知道,为了适应 5 个断点和默认值,我们需要声明 6 个不同宽度,因此我们可以用循环或直接使用循环来编写 mixin,以保持代码的简洁性和可读性。

我们需要确定项目中需要多少列。您可以参考项目设计来确定这个值,或者先设定所需的列数,然后在需要时增加。

* !important:请注意,输出$end值将减 1。因此,如果您希望输出类别的范围为 1 到 10,则需要将值设置为 11。

 $ini: 1;
 $end: 101;

 @for $i from $ini to $end {
   .flexrow.row-#{$i}-el > .element { 
     flex: 0 1 calc(100%/#{$i}); 
     max-width: calc(100%/#{$i});
   }
   @media(min-width: $screen-xs) {
    flexrow.xs-row-#{$i}-el > div.element { 
       flex: 0 1 calc(100%/#{$i}); 
       max-width: calc(100%/#{$i});
     } 
   }
   @media(min-width: $screen-sm) {
     .flexrow.sm-row-#{$i}-el > div.element { 
       flex: 0 1 calc(100%/#{$i}); 
       max-width: calc(100%/#{$i});
     } 
   }
   @media(min-width: $screen-md) {
     .flexrow.md-row-#{$i}-el > div.element { 
       flex: 0 1 calc(100%/#{$i}); 
       max-width: calc(100%/#{$i});
     } 
   }
   @media(min-width: $screen-lg) {
     .flexrow.lg-row-#{$i}-el > div.element { 
       flex: 0 1 calc(100%/#{$i}); 
       max-width: calc(100%/#{$i});
     } 
   }
   @media(min-width: $screen-xl) {
     .flexrow.xl-row-#{$i}-el > div.element { 
       flex: 0 1 calc(100%/#{$i}); 
       max-width: calc(100%/#{$i});
     } 
   }
 }
Enter fullscreen mode Exit fullscreen mode

此时,`.elements` 元素内的内容在元素左上角对齐,因此您可能需要添加一些留白。此外,在使用 `display: flex` 来对齐、固定或嵌套 `.element` 元素内的元素时,指定文字的换行方式也很有帮助。

.element { 
  padding: 15px;
  word-wrap: break-word; 
}
Enter fullscreen mode Exit fullscreen mode

结果:

点击“在 Codepen 上编辑”按钮即可全屏查看,否则您可能只能在文章嵌入页面中看到较小的断点版本。
*
我添加了一个轮廓线用于测试,这样您就可以看到每个内容框的边界。

2. 可变宽度列

我们将保留原有的 .flexrow 类,它完全能够满足需求。

 .flexrow { 
   display: flex;
   flex-flow: row wrap;
 }
Enter fullscreen mode Exit fullscreen mode

现在让我们看看如何(请递归地)构建一组可以以不同尺寸组合在一起的列。

为此,我们可以得到大量的可能组合。

最终代码:

HTML示例代码:

<div class="flexrow">
  <div class="col-25">
    content
  </div>
  <div class="col-40">
    content
  </div>
  <div class="col-35">
    content
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

“列”的 CSS:

 $ini: 1;
 $end: 101;

 @for $i from $ini to $end {
   .col-#{$i} { 
     flex: 0 1 calc(#{$i}%); 
     max-width: calc(100%/#{$i});
   }
   @media(min-width: $screen-xs) {
    .xs-col-#{$i} { 
       flex: 0 1 calc(100%/#{$i}); 
       max-width: calc(100%/#{$i});
     } 
   }
   @media(min-width: $screen-sm) {
    .sm-col-#{$i} { 
       flex: 0 1 calc(100%/#{$i}); 
       max-width: calc(100%/#{$i});
     } 
   }
   @media(min-width: $screen-md) {
     .md-col-#{$i} { 
       flex: 0 1 calc(100%/#{$i}); 
       max-width: calc(100%/#{$i});
     } 
   }
   @media(min-width: $screen-lg) {
     .lg-col-#{$i} { 
       flex: 0 1 calc(100%/#{$i}); 
       max-width: calc(100%/#{$i});
     } 
   }
   @media(min-width: $screen-xl) {
     .xl-col-#{$i} { 
       flex: 0 1 calc(100%/#{$i}); 
       max-width: calc(100%/#{$i});
     } 
   }
 }
Enter fullscreen mode Exit fullscreen mode

实时示例:

在第一次迭代中,我做了一些奇怪的事情,后来我重新思考,找到了更好的方法。
例如,我想“如果用 75% 的比例加上两列呢?”
于是我做了一列 75% 的比例,外加两列 12.5% 的比例。

它有什么问题?

例如,你不会得到 100 个声明(从 1% 到 100%),而是会得到接近 200 个声明(从 0.5% 到 99.5%,每增加 0.5 分)。

但接下来你又会发现另一个问题。宽度的三分之一该怎么算呢?你需要加上 33.3333%,所以总共需要 66.6666%。
对于组合来说,你可能还需要其他中间值,这样一来,这种方法最终可能根本行不通。

如何解决

你可以将这两种方法结合起来使用。

假设你想要一行,其中 1 个元素占据可用宽度的 75%,另外 2 个元素占据剩余部分,每个元素的宽度相同。

 <div class="flexrow">
   <div class="col-75">
     75 percentile column
   </div>
   <div class="col-25 flexrow row-2-el nopadding">
     <div class="element">
       First half of 25%
     </div>
     <div class="element">
       Second half of 25%
     <div>
   </div>
 </div>
Enter fullscreen mode Exit fullscreen mode

我在这里所做的,是同时添加了 SCSS 循环,并使用第一种创建子元素的方法语义地创建了一个 div 结构,但您也可以使用第二种方法来处理这个问题:

 <div class="flexrow">
   <div class="col-75">
     75 percentile column
   </div>
   <div class="col-25 flexrow nopadding">
     <div class="col-50">
       First half of 25%
     </div>
     <div class="col-50">
       Second half of 25%
     <div>
   </div>
 </div>
Enter fullscreen mode Exit fullscreen mode

既然第二种方法可以适用于所有情况而第一种方法不能,那我为什么还要编写第一种方法呢?

我从一月份就开始测试这种弹性布局的使用方法,到目前为止,这两种技术结合起来可以很好地处理我遇到的任何布局。

例如,你可以使用第一个方法来处理动态生成的内容,而无需计数器。

希望您喜欢这篇文章,致以最诚挚的问候!

乔尔 :)

文章来源:https://dev.to/joelbonetr/building-a-flex-layout-from-scratch-to-fit-all-projects-3gbb