您好,登錄后才能下訂單哦!
本篇內容主要講解“純CSS布局排版技巧介紹”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“純CSS布局排版技巧介紹”吧!
開發每一張網頁都離不開布局排版
,基于良好布局排版
打下基礎,才能使后續的開發更順利。當然不能停留在IExplorer
時代那種局限思維上,沒辦法解決的布局排版
都用JS實現。今時不同往日,現代CSS屬性能更好地快速實現各種布局排版
,節約更多時間去摸魚。
不過按照筆者目前了解的情況來看,大部分同學即使在無需兼容IExplorer
的情況下還是遵循CSS+JS
的方式完成一些常見或特殊的布局排版
。從HTML/CSS/JS
前端三劍客的定位來看,HTML
映射網頁的結構,CSS
映射網頁的表現,JS
映射網頁的行為。
布局排版指將圖形、文本、圖像、媒體等可視化信息元素在頁面布局上調整位置
、尺寸
等屬性使頁面布局變得條理化的過程。大部分同學認為布局排版
就是幾個合理的CSS屬性隨便拼湊在一起,但多數情況即使實現也會存在瑕疵,此時就可能使用JS介入。
從布局排版
的特征可知它屬于表現
范疇,因此筆者認為大部分布局排版
都能使用純CSS
完成,無需JS介入。
本文秉承能使用CSS實現的效果都優先使用CSS的原則,為大家講解筆者如何巧妙運用各種純CSS開發技巧完成一些常見或特殊的布局排版
。
在進入主題前,筆者總結出布局排版
一些必備屬性,這些屬性能快速搭建整體效果,再通過一些常用選擇器加以修飾達到完美效果。看似簡單,但使用起來不一定完全駕馭。
必備屬性都是一些幾何屬性,主要用于聲明位置
和尺寸
。
浮動布局:float
定位布局:position/left/right/top/bottom/z-index
彈性布局:display:flex/inline-flex
、flex系列屬性
盒子模型:box-sizing/margin/padding/border/width/height
選擇器因CSS模塊
眾多而派生出的數量也眾多,若無特別方式記熟這些選擇器對應的功能,也很難將其發揮到最大作用。
筆者根據選擇器的功能劃分出八大類,每個類別的選擇器都能在一個應用場景里互相組合,記熟這些類別的選擇器,相信就能將選擇器發揮到最大作用,也能游刃有余將其應用到一些常見或特殊的布局排版
里。
布局排版
可能只應用到某些選擇器,但也不妨礙大家通過以下歸類方式記憶。選擇器作為CSS的重要組成部分,比起屬性組合會有更多的玩法。
基礎選擇器
選擇器 | 別名 | 說明 | 版本 | 常用 |
---|---|---|---|---|
tag | 標簽選擇器 | 指定類型的標簽 | 1 | √ |
#id | ID選擇器 | 指定身份的標簽 | 1 | √ |
.class | 類選擇器 | 指定類名的標簽 | 1 | √ |
* | 通配選擇器 | 所有類型的標簽 | 2 | √ |
層次選擇器
選擇器 | 別名 | 說明 | 版本 | 常用 |
---|---|---|---|---|
elemP elemC | 后代選擇器 | 元素的后代元素 | 1 | √ |
elemP>elemC | 子代選擇器 | 元素的子代元素 | 2 | √ |
elem1+elem2 | 相鄰同胞選擇器 | 元素相鄰的同胞元素 | 2 | √ |
elem1~elem2 | 通用同胞選擇器 | 元素后面的同胞元素 | 3 | √ |
集合選擇器
選擇器 | 別名 | 說明 | 版本 | 常用 |
---|---|---|---|---|
elem1,elem2 | 并集選擇器 | 多個指定的元素 | 1 | √ |
elem.class | 交集選擇器 | 指定類名的元素 | 1 | √ |
條件選擇器
選擇器 | 說明 | 版本 | 常用 |
---|---|---|---|
:lang | 指定標記語言的元素 | 2 | × |
:dir() | 指定編寫方向的元素 | 4 | × |
:has | 包含指定元素的元素 | 4 | × |
:is | 指定條件的元素 | 4 | × |
:not | 非指定條件的元素 | 4 | √ |
:where | 指定條件的元素 | 4 | × |
:scope | 指定元素 作為參考點 | 4 | × |
:any-link | 所有包含href 的鏈接元素 | 4 | × |
:local-link | 所有包含href 且屬于絕對地址的鏈接元素 | 4 | × |
狀態選擇器
選擇器 | 說明 | 版本 | 常用 |
---|---|---|---|
:active | 鼠標激活的元素 | 1 | × |
:hover | 鼠標懸浮的元素 | 1 | √ |
:link | 未訪問的鏈接元素 | 1 | × |
:visited | 已訪問的鏈接元素 | 1 | × |
:target | 當前錨點的元素 | 3 | × |
:focus | 輸入聚焦的表單元素 | 2 | √ |
:required | 輸入必填的表單元素 | 3 | √ |
:valid | 輸入合法的表單元素 | 3 | √ |
:invalid | 輸入非法的表單元素 | 3 | √ |
:in-range | 輸入范圍以內的表單元素 | 3 | × |
:out-of-range | 輸入范圍以外的表單元素 | 3 | × |
:checked | 選項選中的表單元素 | 3 | √ |
:optional | 選項可選的表單元素 | 3 | × |
:enabled | 事件啟用的表單元素 | 3 | × |
:disabled | 事件禁用的表單元素 | 3 | √ |
:read-only | 只讀的表單元素 | 3 | × |
:read-write | 可讀可寫的表單元素 | 3 | × |
:target-within | 內部錨點元素處于激活狀態的元素 | 4 | × |
:focus-within | 內部表單元素處于聚焦狀態的元素 | 4 | √ |
:focus-visible | 輸入聚焦的表單元素 | 4 | × |
:blank | 輸入為空的表單元素 | 4 | × |
:user-invalid | 輸入合法的表單元素 | 4 | × |
:indeterminate | 選項未定的表單元素 | 4 | × |
:placeholder-shown | 占位顯示的表單元素 | 4 | √ |
:current() | 瀏覽中的元素 | 4 | × |
:past() | 已瀏覽的元素 | 4 | × |
:future() | 未瀏覽的元素 | 4 | × |
:playing | 開始播放的媒體元素 | 4 | × |
:paused | 暫停播放的媒體元素 | 4 | × |
結構選擇器
選擇器 | 說明 | 版本 | 常用 |
---|---|---|---|
:root | 文檔的根元素 | 3 | × |
:empty | 無子元素的元素 | 3 | √ |
:nth-child(n) | 元素中指定順序索引的元素 | 3 | √ |
:nth-last-child(n) | 元素中指定逆序索引的元素 | 3 | × |
:first-child | 元素中為首的元素 | 2 | √ |
:last-child | 元素中為尾的元素 | 3 | √ |
:only-child | 父元素僅有該元素的元素 | 3 | √ |
:nth-of-type(n) | 標簽中指定順序索引的標簽 | 3 | √ |
:nth-last-of-type(n) | 標簽中指定逆序索引的標簽 | 3 | × |
:first-of-type | 標簽中為首的標簽 | 3 | √ |
:last-of-type | 標簽中為尾標簽 | 3 | √ |
:only-of-type | 父元素僅有該標簽的標簽 | 3 | √ |
屬性選擇器
選擇器 | 說明 | 版本 | 常用 |
---|---|---|---|
[attr] | 指定屬性的元素 | 2 | √ |
[attr=val] | 屬性等于指定值的元素 | 2 | √ |
[attr*=val] | 屬性包含指定值的元素 | 3 | √ |
[attr^=val] | 屬性以指定值開頭的元素 | 3 | √ |
[attr$=val] | 屬性以指定值結尾的元素 | 3 | √ |
[attr~=val] | 屬性包含指定值(完整單詞)的元素 (不推薦使用) | 2 | × |
[attr|=val] | 屬性以指定值(完整單詞)開頭的元素 (不推薦使用) | 2 | × |
偽元素
選擇器 | 說明 | 版本 | 常用 |
---|---|---|---|
::before | 在元素前插入的內容 | 2 | √ |
::after | 在元素后插入的內容 | 2 | √ |
::first-letter | 元素的首字母 | 1 | × |
::first-line | 元素的首行 | 1 | × |
::selection | 鼠標選中的元素 | 3 | × |
::backdrop | 全屏模式的元素 | 4 | × |
::placeholder | 表單元素的占位 | 4 | √ |
有了上述前置知識,接下來跟著筆者體驗一次如何巧妙運用各種純CSS開發技巧完成一些常見或特殊的布局排版
吧。為了方便瀏覽器自動計算某些樣式,需全局設置box-sizing:border-box
,編碼前請引入筆者整理的reset.css。
主體布局指在大部分情況下通用且具備統一特征的占位布局。掌握主體布局
是一個前端必不可少的技能,養成看設計圖就能大概規劃出整體布局的前提是必須熟悉這些主體布局
的特點與構造。
經典的全屏布局由頂部
、底部
和主體
三部分組成,其特點為三部分左右滿屏拉伸
、頂部底部高度固定
和主體高度自適應
。該布局很常見,也是大部分Web應用主體的主流布局。通常使用<header>
、<footer>
和<main>
三個標簽語義化排版,<main>
內還可插入<aside>
側欄或其他語義化標簽。
<div class="fullscreen-layout"> <header></header> <main></main> <footer></footer> </div>
position + left/right/top/bottom
三部分統一聲明left:0
和right:0
將其左右滿屏拉伸;頂部和底部分別聲明top:0
和bottom:0
將其吸頂和吸底,并聲明倆高度為固定值;將主體的top
和bottom
分別聲明為頂部高度和底部高度。通過絕對定位的方式將三部分固定在特定位置,使其互不影響。
.fullscreen-layout { position: relative; width: 400px; height: 400px; header, footer, main { position: absolute; left: 0; right: 0; } header { top: 0; height: 50px; background-color: #f66; } footer { bottom: 0; height: 50px; background-color: #66f; } main { top: 50px; bottom: 50px; background-color: #3c9; } }
flex
使用flex
實現會更簡潔。display:flex
默認會令子節點橫向排列,需聲明flex-direction:column
改變子節點排列方向為縱向排列;頂部和底部高度固定,所以主體需聲明flex:1
讓高度自適應。
.fullscreen-layout { display: flex; flex-direction: column; width: 400px; height: 400px; header { height: 50px; background-color: #f66; } footer { height: 50px; background-color: #66f; } main { flex: 1; background-color: #3c9; } }
若<main>
需表現成可滾動狀態,千萬不要聲明overflow:auto
讓容器自適應滾動,這樣做有可能因為其他格式化上下文的影響而導致自適應滾動失效或產生其他未知效果。需在<main>
內插入一個<div>
并聲明如下。
div { overflow: hidden; height: 100%; }
經典的兩列布局由左右兩列
組成,其特點為一列寬度固定
、另一列寬度自適應
和兩列高度固定且相等
。以下以左列寬度固定和右列寬度自適應為例,反之同理。
<div class="two-column-layout"> <div class="left"></div> <div class="right"></div> </div>
float + margin-left/right
左列聲明float:left
和固定寬度,由于float
使節點脫流,右列需聲明margin-left
為左列寬度,以保證兩列不會重疊。
.two-column-layout { width: 400px; height: 400px; .left { float: left; width: 100px; height: 100%; background-color: #f66; } .right { margin-left: 100px; height: 100%; background-color: #66f; } }
overflow + float
左列聲明同上,右列聲明overflow:hidden
使其形成BFC區域
與外界隔離。
.two-column-layout { width: 400px; height: 400px; .left { float: left; width: 100px; height: 100%; background-color: #f66; } .right { overflow: hidden; height: 100%; background-color: #66f; } }
flex
使用flex
實現會更簡潔。左列聲明固定寬度,右列聲明flex:1
自適應寬度。
.two-column-layout { width: 400px; height: 400px; .left { float: left; width: 100px; height: 100%; background-color: #f66; } .right { overflow: hidden; height: 100%; background-color: #66f; } }
經典的三列布局由左中右三列
組成,其特點為連續兩列寬度固定
、剩余一列寬度自適應
和三列高度固定且相等
。以下以左中列寬度固定和右列寬度自適應為例,反之同理。整體的實現原理與上述兩列布局一致。
<div class="three-column-layout"> <div class="left"></div> <div class="center"></div> <div class="right"></div> </div>
為了讓右列寬度自適應計算,就不使用float + margin-left
的方式了,若使用margin-left
還得結合左中列寬度計算。
overflow + float
.three-column-layout { width: 400px; height: 400px; .left { float: left; width: 50px; height: 100%; background-color: #f66; } .center { float: left; width: 100px; height: 100%; background-color: #66f; } .right { overflow: hidden; height: 100%; background-color: #3c9; } }
flex
.three-column-layout { display: flex; width: 400px; height: 400px; .left { width: 50px; background-color: #f66; } .center { width: 100px; background-color: #66f; } .right { flex: 1; background-color: #3c9; } }
經典的圣杯布局和雙飛翼布局都是由左中右三列
組成,其特點為左右兩列寬度固定
、中間一列寬度自適應
和三列高度固定且相等
。其實也是上述兩列布局和三列布局的變體,整體的實現原理與上述N列布局一致,可能就是一些細節需注意。
圣杯布局
和雙飛翼布局
在大體相同下也存在一點不同,區別在于雙飛翼布局
中間列需插入一個子節點。在常規實現方式里也是在這個中間列里做文章,如何使中間列內容不被左右列遮擋
。
相同
中間列放首位且聲明其寬高占滿父節點
被擠出的左右列使用float
和margin負值
將其拉回與中間列處在同一水平線上
不同
圣杯布局:父節點聲明padding
為左右列留出空位,將左右列固定在空位上
雙飛翼布局:中間列插入子節點并聲明margin
為左右列讓出空位,將左右列固定在空位上
圣杯布局float + margin-left/right + padding-left/right
由于浮動節點在位置上不能高于前面或平級的非浮動節點,否則會導致浮動節點下沉。因此在編寫HTML結構時,將中間列節點挪到右列節點后面。
<div class="grail-layout-x"> <div class="left"></div> <div class="right"></div> <div class="center"></div> </div>
.grail-layout-x { padding: 0 100px; width: 400px; height: 400px; .left { float: left; margin-left: -100px; width: 100px; height: 100%; background-color: #f66; } .right { float: right; margin-right: -100px; width: 100px; height: 100%; background-color: #66f; } .center { height: 100%; background-color: #3c9; } }
雙飛翼布局float + margin-left/right
HTML結構大體同上,只是在中間列里插入一個子節點<div>
。根據兩者區別,CSS聲明會與上述圣杯布局有一點點出入,可觀察對比找出不同地方。
<div class="grail-layout-y"> <div class="left"></div> <div class="right"></div> <div class="center"> <div></div> </div> </div>
.grail-layout-y { width: 400px; height: 400px; .left { float: left; width: 100px; height: 100%; background-color: #f66; } .right { float: right; width: 100px; height: 100%; background-color: #66f; } .center { margin: 0 100px; height: 100%; background-color: #3c9; } }
圣杯布局/雙飛翼布局flex
使用flex實現圣杯布局/雙飛翼布局
可忽略上述分析,左右兩列寬度固定,中間列寬度自適應。
<div class="grail-layout"> <div class="left"></div> <div class="center"></div> <div class="right"></div> </div>
.grail-layout { display: flex; width: 400px; height: 400px; .left { width: 100px; background-color: #f66; } .center { flex: 1; background-color: #3c9; } .right { width: 100px; background-color: #66f; } }
經典的均分布局由多列
組成,其特點為每列寬度相等
和每列高度固定且相等
。總體來說也是最簡單的經典布局,由于每列寬度相等,所以很易找到合適的方式處理。
<div class="average-layout"> <div class="one"></div> <div class="two"></div> <div class="three"></div> <div class="four"></div> </div>
.one { background-color: #f66; } .two { background-color: #66f; } .three { background-color: #f90; } .four { background-color: #09f; }
float + width
每列寬度聲明為相等的百分比,若有4列則聲明width:25%
。N列就用公式100 / n
求出最終百分比寬度,記得保留2位小數,懶人還可用width:calc(100% / n)
自動計算呢。
.average-layout { width: 400px; height: 400px; div { float: left; width: 25%; height: 100%; } }
flex
使用flex實現會更簡潔。節點聲明display:flex
后,生成的FFC容器
里所有子節點的高度都相等,因為容器的align-items
默認為stretch
,所有子節點將占滿整個容器的高度。每列聲明flex:1
自適應寬度。
.average-layout { display: flex; width: 400px; height: 400px; div { flex: 1; } }
居中布局由父容器
與若干個子容器
組成,子容器在父容器中橫向排列或豎向排列且呈水平居中或垂直居中。居中布局是一個很經典的問題,相信大家都會經常遇到。
在此直接上一個目前最簡單最高效的居中方式。display:flex
與margin:auto
的強行組合,同學們自行體會。
<div class="center-layout"> <div></div> </div>
.center-layout { display: flex; width: 400px; height: 400px; background-color: #f66; div { margin: auto; width: 100px; height: 100px; background-color: #66f; } }
自適布局指相對視窗任何尺寸都能占據特定百分比的占位布局。自適布局
的容器都是根據視窗尺寸計算,即使父節點
或祖先節點
的尺寸發生變化也不會影響自適布局
的容器尺寸。
搭建自適布局
就離不開視窗比例單位。在CSS3里增加了與viewport
相關的四個長度單位,隨著時間推移,目前大部分瀏覽器對這四個長度單位都有較好的兼容性,這也是未來最建議在伸縮方案里使用的長度單位。
1vw
表示1%
視窗寬度
1vh
表示1%
視窗高度
1vmin
表示1%
視窗寬度和1%
視窗高度里最小者
1vmax
表示1%
視窗寬度和1%
視窗高度里最大者
視窗寬高在JS里分別對應window.innerWdith
和window.innerHeight
。若不考慮低版本瀏覽器兼容性,完全可用一行CSS代碼秒殺所有移動端的伸縮方案。
/* 基于UI width=750px DPR=2的網頁 */ html { font-size: calc(100vw / 7.5); }
上述代碼使用calc()
實現font-size
的動態計算。calc()
是自適布局
里的核心存在,無它就不能愉快地實現自適布局
所有動態計算了。
calc()
用于動態計算單位,數值
、長度
、角度
、時間
和百分比
都能作為參數。由于執行數學表達式
后返回運算后的計算值,所以可減少大量人工計算甚至無需人工計算。
calc()
饑不擇食,所有計量單位都能作為參數參加整個動態計算。
數值:整數
、浮點數
長度:px
、em
、rem
、vw
、vh
等
角度:deg
、turn
時間:s
、ms
百分比:%
calc()
雖然好用,但新手難免會遇到一些坑,謹記以下特點,相信就能玩轉calc()
了。
四則運算:只能使用+
、-
、*
、/
作為運算符號
運算順序:遵循加減乘除運算順序,可用()
提升運算等級
符號連接:每個運算符號必須使用空格
間隔起來
混合計算:可混合不同計量單位動態計算
第三點尤為重要,若未能遵守,瀏覽器直接忽略該屬性。
上述font-size:calc(100vw / 7.5)
其實就是根據設計圖與瀏覽器視窗的比例動態計算<html>
的font-size
:100/750 = x/100vw
。
在SPA里有遇過因為有滾動條或無滾動條而導致頁面路由在跳轉過程里發生向左或向右的抖動嗎?這讓強迫癥患者很難受,此時可用calc()
巧妙解決該問題。
.elem { padding-right: calc(100vw - 100%); }
不直接聲明padding-right
為滾動條寬度是因為每個瀏覽器的默認滾動條寬度都可能不一致。100vw
是視窗寬度,100%
內容寬度,那么100vw - 100%
就是滾動條寬度,聲明padding-right
用于保留滾動條出現的位置,這樣滾動條出不出現都不會讓頁面抖動了。
有了calc()
做保障就可迅速實現一些與視窗尺寸相關的布局了。例如實現一個視窗寬度都為50%
的彈窗。
<div class="modal"> <div class="modal-wrapper"></div> </div>
.modal { display: flex; position: fixed; left: 0; right: 0; top: 0; bottom: 0; justify-content: center; align-items: center; background-color: rgba(0, 0, 0, .5); &-wrapper { width: 50vw; height: 200px; background-color: #f66; } }
當然使用calc()
也不一定結合視窗比例單位
計算。例如自適布局
已知部分節點高度,不想手動計算最后節點高度但又想其填充布局剩余空間。
<ul class="selfadaption-layout"> <div class="box-1"></div> <div class="box-2"></div> <div class="box-3"></div> </ul>
.selfadaption-layout { width: 200px; height: 567px; .box-1 { height: 123px; background-color: #f66; } .box-2 { height: 15%; background-color: #3c9; } .box-3 { height: calc(100% - 123px - 15%); background-color: #09f; } }
吸附布局指相對視窗任何滾動都能占據特定位置的占位布局。視窗滾動到特定位置,布局固定在該位置,后續不隨視窗滾動而滾動。該布局產生的效果俗稱吸附效果
,是一種常見網頁效果。譬如吸頂效果
和吸底效果
都是該范疇,經常在跟隨導航
、移動廣告
和懸浮提示
等應用場景里出現。
在jQuery時代
就有很多吸附效果插件,現在三大前端框架也有自身第三方的吸附效果組件。它們都有著共通的實現原理:監聽scroll
事件,判斷scrollTop
和目標節點
的位置范圍,符合條件則將目標節點
的position
聲明為fixed
使目標節點
相對于視窗定位,讓用戶看上去就像釘在視窗指定位置上。
JS實現吸附效果的代碼在網上一搜一大堆,更何況筆者喜歡耍CSS,在此就不貼相關的JS代碼了。在此推薦一個很少見很少用的CSS屬性position:sticky
。簡單的兩行核心CSS代碼就能完成十多行核心JS代碼的功能,何樂而不為呢。
簡單回顧position
屬性值,怎樣用就不說了,大家應該都熟悉。
取值 | 功能 | 版本 |
---|---|---|
inherit | 繼承 | 2 |
static | 標準流 | 2 |
relative | 相對定位 | 2 |
absolute | 絕對定位 | 2 |
fixed | 固定定位 | 2 |
sticky | 粘性定位 | 3 |
當值為sticky
時將節點變成粘性定位
。粘性定位是相對定位
和固定定位
的結合體,節點在特定閾值
跨越前為相對定位
,跨越后為固定定位
。
<div class="adsorption-position"> <ul> <li>Top 1</li> <li>Top 2</li> <li>Normal</li> <li>Bottom 1</li> <li>Bottom 2</li> </ul> </div>
.adsorption-position { overflow: auto; position: relative; width: 400px; height: 280px; outline: 1px solid #3c9; ul { padding: 200px 0; } li { position: sticky; height: 40px; line-height: 40px; text-align: center; color: #fff; &:nth-child(1) { top: 0; z-index: 9; background-color: #f66; } &:nth-child(2) { top: 40px; z-index: 9; background-color: #66f; } &:nth-child(3) { background-color: #f90; } &:nth-child(4) { bottom: 0; z-index: 9; background-color: #09f; } &:nth-child(5) { bottom: 40px; z-index: 9; background-color: #3c9; } } }
兩行核心CSS代碼分別是position:sticky
和top/bottom:npx
。上述5個節點都聲明position:sticky
,但由于top/bottom
賦值有所不同就產生不同吸附效果。
細心的同學可能發現這些節點在某些滾動時刻處于相對定位,在特定滾動時刻處于固定定位
。
第1個<li>
:top
為0px
,滾動到容器頂部
就固定
第2個<li>
:top
為40px
,滾動到距離容器頂部40px
就固定
第3個<li>
:未聲明top/bottom
,就一直保持相對定位
第4個<li>
:bottom
為40px
,滾動到距離容器底部40px
就固定
第5個<li>
:bottom
為0px
,滾動到容器底部
就固定
當然,換成left
或right
也一樣能實現橫向的吸附效果
。
值得注意,粘性定位
的參照物并不一定是position:fixed
。當目標節點
的任意祖先節點
都未聲明position:relative|absolute|fixed|sticky
,才與position:fixed
表現一致。當離目標節點
最近的祖先節點
聲明position:relative|absolute|fixed|sticky
,目標節點
就相對該祖先節點
產生粘性定位
。簡單來說確認參照物的方式與position:absolute
一致。
兼容性勉強還行,近2年發版的瀏覽器都能支持,Safari
和Firefox
的兼容性還是挺贊的。有吸附效果
需求的同學建議一試,要兼容IExplorer
就算了。期待該屬性有更好的發展,畢竟吸附布局
真的是一種常見布局。
橫向布局指容器內節點以水平方向排列且溢出部分被隱藏的占位布局。豎向布局
很常見,聲明overflow:hidden;width:xpx;height:ypx
就能實現,但橫向布局
卻不能使用類似方式實現。
為了方便使用多種方式實現橫向布局
,以下將通用代碼拆分出來。
<div class="horizontal-layout"> <ul> <li>Alibaba</li> <li>Tencent</li> <li>Baidu</li> <li>Jingdong</li> <li>Ant</li> <li>Netease</li> <li>Meituan</li> <li>ByteDance</li> <li>360</li> <li>Sina</li> </ul> </div>
.horizontal-layout { overflow: hidden; width: 300px; height: 100px; ul { overflow-x: auto; cursor: pointer; &::-webkit-scrollbar { height: 10px; } &::-webkit-scrollbar-track { background-color: #f0f0f0; } &::-webkit-scrollbar-thumb { border-radius: 5px; background-color: #f66; } } li { overflow: hidden; height: 90px; background-color: #66f; line-height: 90px; text-align: center; font-size: 16px; color: #fff; &:not(:first-child) { margin-left: 10px; } } }
有些同學可能會使用行內元素
實現橫向排版,但必須聲明overflow-y:hidden
使容器在Y軸
方向隱藏溢出部分。由于行內元素
在當前行排版產生溢出會自動將其余節點排版到下一行,因此還需聲明white-space:nowrap
使所有行內元素
在一行內排版完畢。若產生滾動條,還需對容器的height
做適當的微調。
.horizontal-layout.inline { height: 102px; ul { overflow-y: hidden; white-space: nowrap; } li { display: inline-block; width: 90px; } }
上述方式在筆者在開發認知里覺得太繁瑣,實質上將所有節點當成文本排列,也是醉了。筆者推薦使用flex布局
完成上述布局,flex布局
作為目前最常見的布局方式
,相信也不用筆者多說。以下實現方式不知大家是否見過呢?在移動端上體驗會更棒喔!
.horizontal-layout.flex { ul { display: flex; flex-wrap: nowrap; justify-content: space-between; } li { flex-shrink: 0; flex-basis: 90px; } }
凸顯布局指容器內節點以同一方向排列且存在一個節點在某個方向上較突出的占位布局。該布局描述起來可能比較拗口,直接看以下效果吧,這是一個橫向列表,節點從左往右排列,最右邊的節點特別突出。這就是凸顯布局
的特征,凸顯的節點可在凸顯布局
任意位置,上下左右
,左上左下右上右下
都行。
這里巧妙運用margin-*:auto
實現了凸顯布局
。相信大家實現水平居中固定寬度的塊元素
都會使用margin:0 auto
。
在此同樣原理,當節點聲明margin-*:auto
時,瀏覽器會自動計算剩余空間并將該值賦值給該節點。在使用該技巧時必須基于flex布局
。
<ul class="highlight-layout"> <li>Alibaba</li> <li>Tencent</li> <li>Baidu</li> <li>Jingdong</li> <li>Ant</li> <li>Netease</li> </ul>
.highlight-layout { display: flex; align-items: center; padding: 0 10px; width: 600px; height: 60px; background-color: #3c9; li { padding: 0 10px; height: 40px; background-color: #3c9; line-height: 40px; font-size: 16px; color: #fff; } &.left li { &:not(:first-child) { margin-left: 10px; } &:last-child { margin-left: auto; } } &.right li { &:not(:last-child) { margin-right: 10px; } &:first-child { margin-right: auto; } } &.top { flex-direction: column; width: 120px; height: 400px; li { &:not(:first-child) { margin-top: 10px; } &:last-child { margin-top: auto; } } } &.bottom { flex-direction: column; width: 120px; height: 400px; li { &:not(:last-child) { margin-bottom: 10px; } &:first-child { margin-bottom: auto; } } } }
在此還有一個小技巧,那就是:not()
與:first-child
和:last-child
的巧妙運用。這樣組合讓特殊位置的節點直接減少屬性覆蓋的問題,不僅易讀還能裝逼。
:not(:first-child):排除首節點,其他節點都使用某些樣式
:not(:last-child):排除尾節點,其他節點都使用某些樣式
間距布局指容器內節點從左往右從上往下排列且以特定間距間隔的占位布局。間距布局
常見于各大列表,是筆者認為最重要的布局之一。為何如此簡單的布局還是花費一些篇幅講解呢?最近筆者查看了Github
上很多與間隔布局
相關的CSS代碼,雖然整體效果看上去無大礙,但margin/padding
和結構選擇器
卻亂用,因此筆者想從零到一糾正間距布局
的正確編碼方式。
在進入編碼環節前,筆者想重點講解:nth-child()
的點睛之筆。大部分同學可能只認得:nth-child(n)
、:nth-child(2n-1)
、:nth-child(2n)
和:nth-child(xn)
的日常用法,但其實還有一些你可能未見過的用法。在此筆者借這次機會將:nth-child()
所有用法總結下,n/x/y
代表正整數,最小值為1
。
:nth-child(n):選擇第n
個元素
:nth-child(odd):選擇奇數位置
元素,相當于:nth-child(2n-1)
:nth-child(even):選擇偶數位置
元素,相當于:nth-child(2n)
:nth-child(xn):選擇第x*n
個元素
:nth-child(x-n):選擇前x
個元素
:nth-child(y-n):nth-child(n+x):選擇第x~y
個元素
分析間距布局
的一切特點,捕獲特征很有利于將特征轉換成CSS代碼。
A:確定容器間的間距,使用margin
聲明
B:確定容器內的間距,使用padding
聲明,后續方便聲明background-color
(該步驟很易與上一步驟混淆,請特別注意)
C:確定靠近容器邊界的節點與容器的間距,使用padding
聲明容器而不是使用margin
聲明節點(該步驟說明上一步驟的處理結果)
D:確認每行節點的左右間距,使用margin-left/margin-right
(二選一)聲明節點
E:確認最左列節點或最右列節點與容器的間距,使用margin-left:0
聲明最左列節點或使用margin-right:0
聲明最右列節點
F:除了首行節點,使用margin-top
聲明其余節點
G:若希望容器頂部底部留空,使用border-top/border-bottom
代替padding-top/padding-bottom
全部步驟串聯起來理解可能會產生混亂,但結合以下代碼理解相信就能很快熟悉。以一行排列3個節點總共8個節點為例,最終效果為三行三列。
<ul class="spacing-layout"> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> <li>6</li> <li>7</li> <li>8</li> </ul>
.spacing-layout { display: flex; overflow: auto; flex-wrap: wrap; margin-top: 20px; // 對應A padding: 20px; // 對應B和C // padding-top: 0; // 對應G // padding-bottom: 0; // 對應G // border-top: 20px solid #f66; // 對應G // border-bottom: 20px solid #f66; // 對應G width: 700px; // 稍微留空用于顯示滾動條 height: 400px; background-color: #f66; li { width: 200px; height: 200px; background-color: #66f; line-height: 200px; text-align: center; font-size: 20px; color: #fff; &:not(:nth-child(3n)) { margin-right: 20px; // 對應D和E } &:nth-child(n+4) { margin-top: 20px; // 對應F } } }
空載布局指容器內無任何節點時使用其他形式代替的占位布局。還有使用JS判斷列表集合為空時顯示占位符嗎?相信很多使用MVVM框架開發的同學都會使用條件判斷的方式渲染虛擬DOM,若列表長度不為0則渲染列表,否則渲染占位符。
<div> <ul v-if="list.length">...</ul> <div v-esle>Empty</div> </div>
然而CSS提供一個空判斷的選擇器:empty
,這應該很少同學會注意到吧。
:empty
作用于無子節點的節點,該子節點也包括行內匿名盒(單獨的文本內容
)。以下三種情況均視為非空狀態,若不出現這三種狀態則視為空狀態,此時:empty
才會觸發。
僅存在節點:<div><p>CSS</p></div>
僅存在文本:<div>CSS</div>
同時存在節點和文本:<div>Hello <p>CSS</p></div>
<ul class="empty-layout"> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> <li>6</li> <li>7</li> <li>8</li> <li>9</li> </ul> <ul class="empty-layout"></ul>
$empty: "https://yangzw.vip/img/empty.svg"; .empty-layout { overflow: auto; width: 200px; height: 150px; outline: 1px solid #3c9; &:empty { display: flex; justify-content: center; align-items: center; background: url($empty) no-repeat center/100px auto; &::after { margin-top: 90px; font-weight: bold; content: "沒錢就沒數據"; } } li { padding: 0 10px; height: 30px; background-color: #09f; line-height: 30px; color: #fff; &:nth-child(even) { background-color: #f90; } } }
另外還存在一種特殊的空載布局
,就是不做任何處理。這樣最終渲染的DOM只有容器,若已聲明margin/padding/border
但未聲明width/height
的情況下,就會出現以下占位效果。無任何子節點的容器還聲明著margin/padding/border
,看著都尷尬。
沒事,:empty
幫你搞掂!對于無任何子節點的容器直接聲明display:none
解決所有無效占位,當然也可作用于指定節點。一招制敵,勁!
// 作用于所有節點 :empty { display: none; } // 作用于指定節點 .empty-layout:empty { display: none; }
多格布局指容器內節點以動態數量的格子形式排列的占位布局。微信朋友圈的相冊就是最常見的多格布局
了,當單張照片排列、兩張照片排列、三張照片排列等等,每種情況下照片的尺寸都可能不一致。筆者制作了一個動態多格相冊懷念我家狗狗AB。大家感受下純CSS實現動態數量的多格布局
吧。
在此留個懸念,不講解如何實現,看看大家能不能根據筆者列出的提示嘗試將該效果復原。主要原理是根據結構選擇器限制節點范圍
實現,在本文也可找到原理的答案喔!記得實現完再看以下源碼哈!
<ul class="multigrid-layout"> <li class="item"><img src="https://static.yangzw.vip/codepen/ab-3.jpg"></li> <li class="item"><img src="https://static.yangzw.vip/codepen/ab-3.jpg"></li> <li class="item"><img src="https://static.yangzw.vip/codepen/ab-3.jpg"></li> <li class="item"><img src="https://static.yangzw.vip/codepen/ab-3.jpg"></li> <li class="item"><img src="https://static.yangzw.vip/codepen/ab-3.jpg"></li> <li class="item"><img src="https://static.yangzw.vip/codepen/ab-3.jpg"></li> <li class="item"><img src="https://static.yangzw.vip/codepen/ab-3.jpg"></li> <li class="item"><img src="https://static.yangzw.vip/codepen/ab-3.jpg"></li> <li class="item"><img src="https://static.yangzw.vip/codepen/ab-3.jpg"></li> </ul>
@mixin square($count: 2) { $length: calc((100% - #{$count} * 10px) / #{$count}); width: $length; height: $length; } .multigrid-layout { display: flex; flex-wrap: wrap; justify-content: flex-start; align-content: flex-start; padding: 5px; border: 1px solid #ccc; border-radius: 5px; width: 400px; height: 400px; li { display: flex; overflow: hidden; justify-content: center; margin: 5px; background-color: #f0f0f0; @include square(3); } img { width: 100%; height: 100%; object-fit: cover; } } // 一個元素 .item:only-child { border-radius: 10px; width: auto; max-width: 80%; height: auto; max-height: 80%; } // 兩個元素 .item:first-child:nth-last-child(2), .item:first-child:nth-last-child(2) ~ .item:nth-child(2) { @include square(2); } .item:first-child:nth-last-child(2) { border-radius: 10px 0 0 10px; } .item:first-child:nth-last-child(2) ~ .item:nth-child(2) { border-radius: 0 10px 10px 0; } // 三個元素 .item:first-child:nth-last-child(3), .item:first-child:nth-last-child(3) ~ .item:nth-child(2), .item:first-child:nth-last-child(3) ~ .item:nth-child(3) { @include square(2); } .item:first-child:nth-last-child(3) { border-top-left-radius: 10px; } .item:first-child:nth-last-child(3) ~ .item:nth-child(2) { border-top-right-radius: 10px; } .item:first-child:nth-last-child(3) ~ .item:nth-child(3) { border-bottom-left-radius: 10px; } // 四個元素 .item:first-child:nth-last-child(4), .item:first-child:nth-last-child(4) ~ .item:nth-child(2), .item:first-child:nth-last-child(4) ~ .item:nth-child(3), .item:first-child:nth-last-child(4) ~ .item:nth-child(4) { @include square(2); } .item:first-child:nth-last-child(4) { border-top-left-radius: 10px; } .item:first-child:nth-last-child(4) ~ .item:nth-child(2) { border-top-right-radius: 10px; } .item:first-child:nth-last-child(4) ~ .item:nth-child(3) { border-bottom-left-radius: 10px; } .item:first-child:nth-last-child(4) ~ .item:nth-child(4) { border-bottom-right-radius: 10px; } // 五個元素 .item:first-child:nth-last-child(5) { border-top-left-radius: 10px; } .item:first-child:nth-last-child(5) ~ .item:nth-child(3) { border-top-right-radius: 10px; } .item:first-child:nth-last-child(5) ~ .item:nth-child(4) { border-bottom-left-radius: 10px; } // 六個元素 .item:first-child:nth-last-child(6) { border-top-left-radius: 10px; } .item:first-child:nth-last-child(6) ~ .item:nth-child(3) { border-top-right-radius: 10px; } .item:first-child:nth-last-child(6) ~ .item:nth-child(4) { border-bottom-left-radius: 10px; } .item:first-child:nth-last-child(6) ~ .item:nth-child(6) { border-bottom-right-radius: 10px; } // 七個元素 .item:first-child:nth-last-child(7) { border-top-left-radius: 10px; } .item:first-child:nth-last-child(7) ~ .item:nth-child(3) { border-top-right-radius: 10px; } .item:first-child:nth-last-child(7) ~ .item:nth-child(7) { border-bottom-left-radius: 10px; } // 八個元素 .item:first-child:nth-last-child(8) { border-top-left-radius: 10px; } .item:first-child:nth-last-child(8) ~ .item:nth-child(3) { border-top-right-radius: 10px; } .item:first-child:nth-last-child(8) ~ .item:nth-child(7) { border-bottom-left-radius: 10px; } // 九個元素 .item:first-child:nth-last-child(9) { border-top-left-radius: 10px; } .item:first-child:nth-last-child(9) ~ .item:nth-child(3) { border-top-right-radius: 10px; } .item:first-child:nth-last-child(9) ~ .item:nth-child(7) { border-bottom-left-radius: 10px; } .item:first-child:nth-last-child(9) ~ .item:nth-child(9) { border-bottom-right-radius: 10px; }
很多同學可能覺得CSS很簡單,但真正玩起來也能與JS有得一比。筆者從事前端領域多年,一直致力于CSS技術的研究與應用,當然真的不是為了玩,而是在玩的過程里將實踐到的知識充分應用于工作上。
JS重要但CSS同樣重要,希望喜歡CSS的同學多多關注筆者,相信你一定會有更多CSS方面的收獲。
到此,相信大家對“純CSS布局排版技巧介紹”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。