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