陽光裏她在院子中央晾曬着衣裳 / 在四季的風中她散着頭髮安慰着時光css
——趙雷《南方姑娘》前端
響應式佈局系統,在如今流行的 CSS 框架中已經很是常見了。它主要由容器類和約定一行列數的柵格系統組成,組成了一個框架的骨架。bootstrap
在流行的前端框架 Bootstrap 和 Bulma CSS 中,就有體現。像 Bootstrap 的 .container
、.row
、.col
;還有 Bulma CSS 的 .container
、columns
、column
都是表示這類佈局系統。雖然名稱不同,但原理都是相同的。前端框架
隨着 Flex 佈局的普及,幾乎現代的柵格系統的實現都選擇使用這一靈活的佈局方式。數據結構
如今就來看一下,怎樣實現一個最小的 CSS 響應式佈局系統吧。框架
首先從容器提及。ide
爲了保證明現代碼的簡潔,本文將使用 SCSS 來寫。若是你對 SCSS 還不熟悉,沒有關係,行文中會對使用到的知識點作介紹。佈局
容器主要用來包裹網頁的主要內容,常見效果就是將內容居中地顯示在屏幕中間。flex
咱們使用 .container
來約定容器。spa
首先,容器是水平居中的,這一塊樣式較爲容易:
.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 列柵格佈局。
先使用 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
:佔據 1 列,也就是 1/12 寬.is-2
:佔據 2 列,也就是 1/6 寬.is-3
:佔據 3 列,也就是 1/4 寬.is-4
:佔據 4 列,也就是 1/3 寬.is-5
:佔據 5 列,也就是 5/12 寬.is-6
:佔據 6 列,也就是 1/2 寬.is-7
:佔據 7 列,也就是 7/12 寬.is-8
:佔據 8 列,也就是 2/3 寬.is-9
:佔據 9 列,也就是 3/4 寬.is-10
:佔據 10 列,也就是 5/6 寬.is-11
:佔據 11 列,也就是 11/12 寬.is-12
:佔據 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);
}
}
}
}
複製代碼
能夠在此查看效果。
固然,更多其餘豐富的功能任君添加,這裏只是提供了一個最簡單的代碼實現。
Grid system, by getbootstrap.com
感謝你花費寶貴的時間⏲️閱讀這篇文章。
若是你以爲這篇文章讓你的生活美好了一點點,歡迎鼓(diǎn)勵(zàn)😀。若是能在文章下面留下你寶貴的評論或意見是再合適不過的了,由於研究證實,參與討論比單純閱讀更能讓人對知識印象深入😉。
(完)