从零开始构建适用于所有项目的灵活布局
弹性盒布局
由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!
随着网格布局和弹性布局的日益普及,越来越多的开发者和公司不再使用框架,而是开始使用这些内置的 CSS 属性来构建布局。有时两者结合使用,有时则完全依赖其中一种。
我们先从 flex 开始,我发现它更有趣,因为它流畅易用,和往常一样,我会添加代码和解释以说明其用途。
控制箱式模型计算
这里有一个我通常会添加的全局变量,用来控制盒模型的计算,以确保所有元素都以这种更直观的方式进行尺寸调整。您可以在这里找到更多相关信息。
* { box-sizing: border-box; }
弹性盒布局
Flex布局默认不适用于行列式布局系统。这就是为什么你会看到有人说Grid布局是用于构建结构的3D布局,而Flex布局是用于展示内容的2D布局。
这相当准确,但你也可以通过在正确的属性上使用一些 flex 值来创建流畅的 3D 布局,让我们看看如何仅使用 flex 来模拟行列布局。
行元素
.flexrow {
display: flex;
flex-flow: row wrap;
}
这意味着将元素显示为 flex,并将流设置为行,如果 flex 子元素上的某些内容无法适应行,则需要换行。
细节:
显示:flex控制显示行为。
flex-flow是两个 flex 属性的封装,顺序为:flex-direction和flex-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... */
请注意,唯一的区别在于类名和将布局宽度 100% 分割成的数字。
很容易理解,如果你想要一行包含两个元素(列),且这两个元素的宽度相同,你可以假设行宽为 100%,然后除以 2,得到两个宽度均为 50% 的元素。
由此我们可以得出以下结论:
<div class="flexrow row-2-el">
<div class="element"> first column </div>
<div class="element"> Second column </div>
</div>
我们得到了两列,每列宽度为可用宽度的 50%。
列实现细节:
flex属性是 3 个属性的简写,这 3 个属性依次为:flex-grow、flex-shrink和flex-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;
断点定义示例:
.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);
}
}
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>
从 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});
}
}
}
此时,`.elements` 元素内的内容在元素左上角对齐,因此您可能需要添加一些留白。此外,在使用 `display: flex` 来对齐、固定或嵌套 `.element` 元素内的元素时,指定文字的换行方式也很有帮助。
.element {
padding: 15px;
word-wrap: break-word;
}
结果:
点击“在 Codepen 上编辑”按钮即可全屏查看,否则您可能只能在文章嵌入页面中看到较小的断点版本。
*我添加了一个轮廓线用于测试,这样您就可以看到每个内容框的边界。
2. 可变宽度列
我们将保留原有的 .flexrow 类,它完全能够满足需求。
.flexrow {
display: flex;
flex-flow: row wrap;
}
现在让我们看看如何(请递归地)构建一组可以以不同尺寸组合在一起的列。
为此,我们可以得到大量的可能组合。
最终代码:
HTML示例代码:
<div class="flexrow">
<div class="col-25">
content
</div>
<div class="col-40">
content
</div>
<div class="col-35">
content
</div>
</div>
“列”的 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});
}
}
}
实时示例:
在第一次迭代中,我做了一些奇怪的事情,后来我重新思考,找到了更好的方法。
例如,我想“如果用 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>
我在这里所做的,是同时添加了 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>
既然第二种方法可以适用于所有情况而第一种方法不能,那我为什么还要编写第一种方法呢?
我从一月份就开始测试这种弹性布局的使用方法,到目前为止,这两种技术结合起来可以很好地处理我遇到的任何布局。
例如,你可以使用第一个方法来处理动态生成的内容,而无需计数器。
希望您喜欢这篇文章,致以最诚挚的问候!
乔尔 :)
文章来源:https://dev.to/joelbonetr/building-a-flex-layout-from-scratch-to-fit-all-projects-3gbb