内容简介:阳光里她在院子中央晾晒着衣裳 / 在四季的风中她散着头发安慰着时光——赵雷《南方姑娘》响应式布局系统,在现在流行的 CSS 框架中已经非常常见了。它主要由容器类和约定一行列数的栅格系统组成,组成了一个框架的骨架。
阳光里她在院子中央晾晒着衣裳 / 在四季的风中她散着头发安慰着时光
——赵雷《南方姑娘》
响应式布局系统,在现在流行的 CSS 框架中已经非常常见了。它主要由容器类和约定一行列数的栅格系统组成,组成了一个框架的骨架。
在流行的前端框架 Bootstrap 和 Bulma CSS 中,就有体现。像 Bootstrap 的 .container
、 .row
、 .col
;还有 Bulma CSS 的 .container
、 columns
、 column
都是表示这类布局系统。虽然名称不一样,但原理都是相同的。
随着 Flex 布局的普及,几乎现代的栅格系统的实现都选择使用这一灵活的布局方式。
现在就来看一下,怎样实现一个最小的 CSS 响应式布局系统吧。
首先从容器说起。
为了保证实现代码的简洁,本文将使用 SCSS 来写。如果你对 SCSS 还不熟悉,没有关系,行文中会对使用到的知识点做介绍。
容器
容器主要用来包裹网页的主要内容,常见效果就是将内容居中地显示在屏幕中间。
我们使用 .container
来约定容器。
首先,容器是水平居中的,这一块样式较为容易:
.container { margin-left: auto; margin-right: auto; } 复制代码
所谓的响应式容器,就是根据不同的断点(breakpoints),也就是当前的视口宽度,来决定容器使用的 max-width
值。
这里我们借鉴了 Bootstrap 中对断点的定义,根据视口宽度,分为以下几类设备:
[0, 576px) [576px, 768px) [768px, 992px) [992px, 1200px) [1200px, +∞)
针对断点定义,声明一个变量 $breakpoints
:
$breakpoints: ( // Extra small screen / phone xs: 0, // Small screen / phone sm: 576px, // Medium screen / tablet md: 768px, // Large screen / desktop lg: 992px, // Extra large screen / wide desktop xl: 1200px ); 复制代码
$breakpoints
称为“列表”,是 SCSS 提供给我们的数据结构。由一个个 key: value
键值对组成。上例中的 key 表示的是设备有效范围的起始点。
不同的设备下,容器有不同的 max-width
值。所以,这里我们再声明一个表示容器宽度的变量 $container-max-widths
:
$container-max-widths: ( xs: none, sm: 540px, md: 720px, lg: 960px, xl: 1140px ); 复制代码
这里的 $container-max-widths
也是个列表,这里的 key 表示某个设备下容器的最大宽度。比如,在超大屏设备下,容器的最大宽度是 1140px
,而在平常手机下,不设置容器的最大宽度,为默认值 none
。
有了实现的思路,接下来就着手实现。
我们就可以借助媒体查询指令 @media
,依据视口宽度的范围,给予 .container
不同的 max-width
值。
@each $device, $breakpoint in $breakpoints { @media only screen and (min-width: $breakpoint) { .container { max-width: map-get($container-max-widths, $device); } } } 复制代码
7 行代码搞定!
下面解释下上面的代码。
我们对列表遍历,使用的是 @each...in
语法,每一次遍历取出对应的 key、value,得到当前的 $device
、 $breakpoint
。 map-get
是 SCSS 提供的用来操作列表的方法:根据 key 取出 value。比如,当 $device
值为 xs
的时候, map-get($container-max-widths, $device)
对应值为 none
;当 $device
值为 sm
的时候, map-get($container-max-widths, $device)
对应值为 540px
,以此类推。
@media only screen and (min-width: $breakpoint) { ... }
中包含的代码,表示从当前设备断点开始处,应用的 CSS 样式。 当我们同时按照从小到大的顺序设置两个断点的媒体查询时,后者会覆盖前者的样式
,这是实现不同视口下,具有不同宽度容器的核心原理。
接下来,将得到的宽度值赋给容器的 max-width
属性就可以了。
到现在为止,我们就写出了一个响应式容器了,我们总揽下代码:
$breakpoints: ( // Extra small screen / phone xs: 0, // Small screen / phone sm: 576px, // Medium screen / tablet md: 768px, // Large screen / desktop lg: 992px, // Extra large screen / wide desktop xl: 1200px ); $container-max-widths: ( xs: none, sm: 540px, md: 720px, lg: 960px, xl: 1140px ); .container { margin-left: auto; margin-right: auto; } @each $device, $breakpoint in $breakpoints { @media only screen and (min-width: $breakpoint) { .container { max-width: map-get($container-max-widths, $device); } } } 复制代码
点击这里,查看效果。
下面再来介绍 12 列栅格布局。
12 列栅格布局
先使用 Flex 布局,写一个最简的等宽布局。
.row { display: flex; .col { flex-grow: 1; flex-basis: 0; } } 复制代码
没错,这就是使用 Flex 布局实现一个等宽布局的所有代码了。如果不考虑中间的空白行,只需要 7 行代码。
这里的原理是,我们将所有 Flex 项目的 flex-basis
设置为 0
了,就是说这些 Flex 项目在 grow 或 shrink 之前都没有宽度,是一样长的。这样最终计算出来的主轴空间会平均地分配给了每个 Flex 项目,这样它们就等宽了。
到这里,我们所写的这个简易栅格布局有两个局限:
- 不能布局非等宽项目。
- 不支持换行。
换行的话很好弄,为 Flex 容器加个 flex-wrap: wrap
就可以了。那怎样处理“非等宽项目”排列布局呢。
为了能实现非等宽项目的布局,我们的思路是:
禁用 Flex 项目的伸缩特性,使用百分比 width
指定宽度
。
首先,禁用 Flex 项目的伸缩特性,使用到的属性如下:
flex-shrink: 0; flex-grow: 0; flex-basis: 0; 复制代码
这三个属性等价的快捷写法是:
flex: none; 复制代码
然后就是使用百分比 width
指定宽度了。
我们实现的是一行最多 12 列的栅格布局。也就是说把一行划分成 12 列,每一列的宽度大约占总宽度的 8.33%
。我们用 .is-列数
指定一个项目占据的列数:
.is-1 .is-2 .is-3 .is-4 .is-5 .is-6 .is-7 .is-8 .is-9 .is-10 .is-11 .is-12
根据这个规律,我们可以很容易地写出栅格布局代码:
$columns: 12; .row { display: flex; .col { flex-grow: 1; flex-basis: 0; @for $i from 1 through 12 { &.is-#{$i} { flex: none; width: percentage($i / 12); } } } } 复制代码
这里我们使用 @for
指令的 @for $var from <start> through <end>
语法,从 1 递增到 12,定义了 .is-*
这一系列类名,原理就是我们说过的禁用了 Flex 项目的伸缩特性,指定给它百分比宽度。怎么样,很简单吧。
接下来再加上折行( .row.is-multiline
)和 Flex 项目偏移( .is-offset-*
)的支持。
我们总揽下代码:
$columns: 12; .row { display: flex; &.is-multiline { flex-wrap: wrap; } .col { flex-grow: 1; flex-basis: 0; @for $i from 1 through 12 { &.is-#{$i} { flex: none; width: percentage($i / 12); } &.is-offset-#{$i} { margin-left: percentage($i / 12); } } } } 复制代码
.is-multiline
是跟随 .row
一起使用的,得到的就是 flex-wrap: wrap
的效果;项目偏移则借助 margin-left
属性实现。
到这里,我们的 12 列栅格布局就写完了 ヾ(◍°∇°◍)ノ゙
完整代码
我们把上面两部分的代码整合起来,就能得到一个最小的响应式布局系统了~ O(∩_∩)O
$breakpoints: ( // Extra small screen / phone xs: 0, // Small screen / phone sm: 576px, // Medium screen / tablet md: 768px, // Large screen / desktop lg: 992px, // Extra large screen / wide desktop xl: 1200px ); $container-max-widths: ( xs: none, sm: 540px, md: 720px, lg: 960px, xl: 1140px ); .container { margin-left: auto; margin-right: auto; } @each $device, $breakpoint in $breakpoints { @media only screen and (min-width: $breakpoint) { .container { max-width: map-get($container-max-widths, $device); } } } $columns: 12; .row { display: flex; &.is-multiline { flex-wrap: wrap; } .col { flex-grow: 1; flex-basis: 0; @for $i from 1 through 12 { &.is-#{$i} { flex: none; width: percentage($i / 12); } &.is-offset-#{$i} { margin-left: percentage($i / 12); } } } } 复制代码
可以 在此查看效果 。
当然,更多其他丰富的功能任君添加,这里只是提供了一个最简单的代码实现。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Numerical Recipes 3rd Edition
William H. Press、Saul A. Teukolsky、William T. Vetterling、Brian P. Flannery / Cambridge University Press / 2007-9-6 / GBP 64.99
Do you want easy access to the latest methods in scientific computing? This greatly expanded third edition of Numerical Recipes has it, with wider coverage than ever before, many new, expanded and upd......一起来看看 《Numerical Recipes 3rd Edition》 这本书的介绍吧!