Flexbox和Sass Grid教程(如何简化响应式设计)

本文概述

  • Sass和Flexbox的简短介绍
  • 网格
  • 容器
  • 行数
  • 屏幕宽度相关列
  • 偏移量
  • 显示性
  • 总结
最近, 我面临着创建自己的网格系统的挑战, 并且由于重新发明方向盘对于学习体验总是非常有用的, 所以我选择了它。我知道这将是一个有趣的挑战, 但事实证明如此容易, 我感到惊讶!
Flexbox和Sass Grid教程(如何简化响应式设计)

文章图片
在本实验中, 我们将研究Flexbox布局以及它们如何允许布局的优美实现而无需进行任何疯狂的修改。另外, 如果你不熟悉Sass, 我们将了解它的工作原理并使用一些方便的Sass实用程序。你甚至可以学习有关CSS网格的新知识, 例如Bootstrap的一部分。
Sass和Flexbox的简短介绍 Sass基本上是一种可以避免CSS缺点的工具, 它是一种脚本语言, 可以解释为CSS。如果你已经在编写CSS样式, 但是该语法看起来非常熟悉, 但是其工具箱中包含变量, 可重用的mixins以及for和while指令等。关于Sass的最方便的事情之一是任何有效的CSS代码都是有效的Sass, 因此你可以逐步转换代码库。
【Flexbox和Sass Grid教程(如何简化响应式设计)】一个简单的for循环示例:
@for $i from 1 through 3 { .a-numbered-class-#{$i} { width: (20 * $i) * 1px; } }

这个简单的循环从1迭代到3并创建类。迭代的索引将方便地存储在$ i中。我们还可以进行数学运算, 并以不同的宽度每次打印.a-numbered-class-X三次。此代码输出:
.a-numbered-class-1 { width: 20px; }.a-numbered-class-2 { width: 40px; }.a-numbered-class-3 { width: 60px; }

正如我们所看到的, 我们可以抽象出你在CSS中要做的许多工作。在CSS中, 你必须手动复制, 粘贴和修改, 这显然更容易出错且不太美观。如果你还没有尝试过, 那就不要再浪费时间了!
Flexbox代表Flexible Box, Flexible Box是一个CSS3布局系统, 可以动态定位和分配元素。这是一个非常强大的工具, 可以轻松进行灵活的布局。有关如何学习Flexbox的更多详细信息, 请查看Chris Coyier的Flexbox完整指南。
网格 进入网格本身, 让我们从其基本元素开始。它们将受到Bootstrap的网格元素的启发:容器, 行和列, 每个元素都包含在其中。
我们将使用BEM命名约定来命名类的名称。 BEM约定非常易于使用, 并添加了许多有关元素及其上下文的信息。简而言之, 你有:
  • 块, “ 封装了对自己有意义的独立实体” :.block。
  • 元素是” 块的一部分, 没有独立的含义” , 由块名称, 两个下划线和元素表示:.block__elem
  • 修饰符, 如” 块或元素上的标志” , 用两个破折号表示:.block .block– mod。
Flexbox和Sass Grid教程(如何简化响应式设计)

文章图片
容器 这是网格的最外层元素, 它将包含我们的行元素。容器有两种类型:.container和.container– fluid。
.container的行为定义为某点以下宽度的100%, 其上方具有最大固定宽度, 并且左右边距相等:
$grid__bp-md: 768; .container { max-width: $grid__bp-md * 1px; margin: 0 auto; }

通过扩大和缩小” 输出” 窗口在此处玩
对于始终具有100%宽度的流体容器, 我们只需使用修饰符覆盖这些属性:
& --fluid { margin: 0; max-width: 100%; }

在这里玩。
那很简单!现在, 我们已经实现了两个容器。让我们继续下一个元素。
行数 行将是我们内容的水平组织者。
我们将使用Flexbox定位行的子元素, 使其包裹起来, 以免它们溢出, 并在行内提供100%的宽度(以便我们以后可以嵌套它们)。
& __row { display: flex; flex-wrap: wrap; width: 100%; }

如果子元素的宽度之和大于其自身的宽度, 则这将使子元素并排放置并换行。现在, 我们只需要添加一些div, 它将如下所示:
Flexbox和Sass Grid教程(如何简化响应式设计)

文章图片
通过扩展和收缩” 输出” 窗口在此处进行操作。
事情开始成形, 但这还不是CSS网格。它不见了…
列 列是网站内容所在的位置。它们定义了该行被分成多少部分以及它们占据了多少。我们将进行十二列的布局。这意味着我们可以将行分为一个或最多十二个部分。
首先, 一些基本数学。当我们要有一列时, 其宽度应为100%。如果我们要十二列。然后每个应该占宽度的8.333…%或100/12。
使用Flexbox, 要以这种方式分发内容, 我们可以使用flex-basis。
为了分成四列, 我们现在将添加以下内容:
flex-basis: (100 / 4 ) * 1%;

这样, 我们可以使每个元素占据宽度的25%或我们想要的任何百分比。
在这里玩。
让我们变得更有活力。由于我们希望这能反映我们可能的类, 因此我们将其命名为.col-1, 这是一个列div的类, 其宽度为8.333%, 因为其中的十二个必须在换行之前适合。百分比将一直递增, 直到.col-12, 它将占100%。
$grid__cols: 12; @for $i from 1 through $grid__cols { .col-#{$i} { flex-basis: (100 / ($grid__cols / $i) ) * 1%; } }

只是为了澄清情况, 假设我们要将宽度分为四个相等的部分。我们需要.col-3, 因为它适合12的4倍, 这意味着.col-3应该具有25%的flex-basis:
100 / ($grid__cols / $i) 100 /(12/ 3)=25

这已经开始看起来像网格!
Flexbox和Sass Grid教程(如何简化响应式设计)

文章图片
在这里玩。
屏幕宽度相关列 现在, 我们希望能够拥有一个元素, 该元素在移动设备上具有一定宽度, 而在平板电脑上具有不同的宽度, 依此类推。我们将使用取决于窗口宽度的某些断点。我们的UI将对这些断点做出反应, 并适应适合不同设备屏幕尺寸的理想布局。我们将按大小来命名断点:small(sm), medium(md)等, .col-sm-12将是一个元素, 至少在sm断点之前占据12列。
让我们重命名.col- *类.col-sm- *。由于我们的网格将首先移动, 因此我们将其属性应用于所有屏幕尺寸。对于我们需要在更大的屏幕上表现不同的那些, 我们将添加类:.col-md- *。
想象一个带有.col-sm-12和.col-md-4的元素。预期的行为将是, 在断点” md” (中)以下, 它将具有100%的宽度, 在断点” md” (中)之上, 将具有33.333%的宽度-这是非常常见的情况, 因为在移动设备上, 你可能需要将元素堆叠在顶部而不是在其旁边。当你的宽度受到更多限制时, 彼此可以互相配合。
Flexbox和Sass Grid教程(如何简化响应式设计)

文章图片
为此, 我们需要在断点处添加一个媒体查询(一个表达式, 该表达式只在特定宽度以上或以下执行, 或者在特定设备上执行), 并像以前对sm一样创建md列:
@media screen and (min-width: $grid__bp-md * 1px) { @for $i from 1 through $grid__cols { & __col-md-#{$i} { flex-basis: (100 / ($grid__cols / $i) ) * 1%; } } }

在这里玩。
这已经接近有用的东西了。相当多的WET(明白吗?不是DRY…), 所以让它变得更加抽象。
如我们所见, 我们将需要为每个断点提供媒体查询, 因此让我们创建一个混入, 它接收一个动态创建媒体查询的断点。它可能看起来像这样:
@mixin create-mq($breakpoint) { @if($breakpoint == 0) { @content; } @else { @media screen and (min-width: $breakpoint *1px) { @content; } } }

现在, 让我们将创建__col类的内容包装在一个称为create-col-classs的mixin中, 并使用create-mq mixin。
@mixin create-col-classes($modifier, $grid__cols, $breakpoint) { @include create-mq($breakpoint) { @for $i from 1 through $grid__cols { & __col#{$modifier}-#{$i} { flex-basis: (100 / ($grid__cols / $i) ) * 1%; } } } }

就是这样。要使用它, 我们现在在Sass映射中定义断点, 并对其进行迭代。
$map-grid-props: ('-sm': 0, '-md': $grid__bp-md, '-lg': $grid__bp-lg); @each $modifier , $breakpoint in $map-grid-props { @include create-col-classes($modifier, $grid__cols, $breakpoint); }

我们的网格系统已基本完成!我们定义了一个.container__col-sm- *类作为默认类, 我们可以使用container__col-md- *和container__col-lg- *在更大的屏幕上修改其行为。
我们甚至可以嵌套行!在这里玩。
这样做的好处是, 如果我们现在希望它具有与Bootstrap v4相同的所有断点, 则只需执行以下操作:
$grid__bp-sm: 576; $grid__bp-md: 768; $grid__bp-lg: 992; $grid__bp-xl: 1200; $map-grid-props: ( '': 0, '-sm': $grid__bp-sm, '-md': $grid__bp-md, '-lg': $grid__bp-lg, '-xl': $grid__bp-xl );

就是这样!在这里玩。
请注意, Bootstrap如何采用比我们最初讨论的更完整的” 移动优先” 方法。最小的窗口大小没有后缀, 例如sm或md, 原因是等效于.container__col-X的类不仅会在0到576px的窗口宽度中应用;如果我们不明确覆盖它, 则它将是每个窗口大小的列数。否则, 我们可以添加类.container__col-sm-Y, 使其在sm断点之间的宽度为Y列。
偏移量 偏移量将增加上一列的边距。 .container__col-offset-4将在所有屏幕尺寸上增加左边距:33.333%。 .container__col-md-offset-4将执行相同的操作, 但在md断点之上。
现在实现起来很简单。我们在创建类的同一循环上添加了-offset属性, 但是编写了margin-left属性而不是flex-bases。我们也必须为-offset-0做额外的操作, 因为我们可能想在更大的屏幕上清除边距:
@mixin create-col-classes($modifier, $grid-cols, $breakpoint) { @include create-mq($breakpoint) { & __col#{$modifier}-offset-0 { margin-left: 0; } @for $i from 1 through $grid-cols { & __col#{$modifier}-#{$i} { flex-basis: (100 / ($grid-cols / $i) ) * 1%; } & __col#{$modifier}-offset-#{$i} { margin-left: (100 / ($grid-cols / $i) ) * 1%; } } } }

现在, 我们有功能齐全的胶印!在这里玩。
显示性 有时我们希望显示/隐藏某个点之下或之上的元素。为此, 我们可以使类像Bootstrap v4一样可用。
例如, .hidden-md-up类将从md断点向上隐藏该类的任何元素;相反, .hidden-md-down会将其隐藏在断点下方。
这样的代码又很简单:我们只是迭代断点, 并为每个断点创建一个.hidden- *类。不过, 我们修改了create-mq类, 使其更加抽象:
@each $modifier , $breakpoint in $map-grid-props { @if($modifier == '') { $modifier: '-xs'; } @include create-mq($breakpoint - 1, 'max') { .hidden#{$modifier}-down { display: none !important; } } @include create-mq($breakpoint, 'min') { .hidden#{$modifier}-up { display: none !important; } } }

附带说明一下, 这不是!important的少数几个好用法之一吗?注意, 该元素在display:block规则中可能具有更高的特异性, 但我们仍希望将其隐藏在断点以下或上方。如果你不同意这种方法, 请在评论中告诉我!
就是这样:现在我们有了一个可显示系统。
在这里玩。
总结 尽管此” 框架” 尚未投入生产, 但它显示了Flexbox布局可以多么强大, Sass多么方便。仅用几行代码, 我们就实现了CSS框架/网格的核心功能。
也可以作为一个教训, 使几乎所有软件的基本版本都可以非常容易地实现。现实世界中的具体问题开始加重并使其变得困难。
我创建了一个GitHub存储库, 你可以在其中提交问题或请求。
你希望实现哪些功能?实施可以简化还是更优雅?
请随时让我知道你对以下评论的看法。

    推荐阅读