新聞中心
本文轉(zhuǎn)載自微信公眾號(hào)「神光的編程秘籍」,作者神說(shuō)要有光zxg。轉(zhuǎn)載本文請(qǐng)聯(lián)系神光的編程秘籍公眾號(hào)。

創(chuàng)新互聯(lián)公司是一家集網(wǎng)站建設(shè),龍馬潭企業(yè)網(wǎng)站建設(shè),龍馬潭品牌網(wǎng)站建設(shè),網(wǎng)站定制,龍馬潭網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營(yíng)銷,網(wǎng)絡(luò)優(yōu)化,龍馬潭網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
UI 發(fā)展史
自從圖形界面操作系統(tǒng)問(wèn)世以來(lái),之上的應(yīng)用軟件基本都會(huì)繪制界面,這也是用戶使用軟件的接口,叫做 UI (user interface)。涉及到用戶體驗(yàn)、設(shè)計(jì)、具體界面的開(kāi)發(fā),是軟件中和用戶最近的一部分,也是多個(gè)職能的崗位交集最多的部分。
根據(jù)操作系統(tǒng)不同,會(huì)有不同的界面的開(kāi)發(fā)方式。安卓、ios、windows 等都有各自的創(chuàng)建 ui 的庫(kù),但是更底層的繪圖庫(kù)卻是有標(biāo)準(zhǔn)的:跨平臺(tái)的繪圖 api 接口標(biāo)準(zhǔn) OpenGL 以及 windows 下的 DirectX。
因?yàn)楦鱾€(gè)操作系統(tǒng)繪制 ui 的方式不同,所以跨平臺(tái)的繪制方案逐漸流行開(kāi)來(lái),也就是瀏覽器?;跒g覽器服務(wù)器的軟件架構(gòu)叫做 B/S 架構(gòu),而基于客戶端的叫做 C/S 架構(gòu)。
在一段時(shí)間內(nèi),B/S 架構(gòu)的應(yīng)用越來(lái)越多,C/S 架構(gòu)的應(yīng)用也更多的混合 B/S 的方案來(lái)實(shí)現(xiàn)。
在移動(dòng)互聯(lián)網(wǎng)時(shí)代來(lái)臨之后,大家發(fā)現(xiàn)網(wǎng)頁(yè)的體驗(yàn)比不上原生,雖然后面發(fā)展出了 PWA (漸進(jìn)式WebApp)等技術(shù),但離原生的體驗(yàn)還是有差距的,所以原生開(kāi)發(fā)應(yīng)用的方案又占了上風(fēng)。
但是安卓、ios 繪制界面、書(shū)寫(xiě)邏輯的方式都不同,雙端要分別實(shí)現(xiàn),開(kāi)發(fā)、測(cè)試的人力都是雙份的,這樣的成本是比較高的。為了節(jié)省成本,大家又摸索出了跨端引擎的方案,也就是說(shuō)還是通過(guò)網(wǎng)頁(yè)來(lái)寫(xiě)渲染和交互的邏輯,但是渲染用的 api 是由安卓、ios 分別實(shí)現(xiàn),這樣就實(shí)現(xiàn)了跨端的渲染,邏輯部分也是由 JS 來(lái)寫(xiě),一些需要的設(shè)備能力 api 分別由安卓、ios 實(shí)現(xiàn)然后注入到 JS 引擎里。
和安卓、ios 的跨端方案逐漸流行一樣,桌面端也出現(xiàn)了 electron 的方案,通過(guò)網(wǎng)頁(yè)來(lái)渲染界面和寫(xiě)邏輯,需要用的 api 注入到 JS 引擎中,而且 electron 是直接把 Node.js 的 api 注入到了 JS 引擎中,在網(wǎng)頁(yè)里實(shí)現(xiàn)一些原生功能的時(shí)候可以直接使用 Node.js 的 api,此外還有一些 api 是 elctron 額外注入的,比如剪貼板、電源監(jiān)視器等。
發(fā)展到現(xiàn)在,UI 的繪制方案逐步向網(wǎng)頁(yè)靠攏,基于 html、css、js 的 web 技術(shù)成為了創(chuàng)建 UI 界面的主流方案。
網(wǎng)頁(yè)的物理層和邏輯層
大家用過(guò) canvas 的 api 應(yīng)該知道,如果直接繪制的話需要指定什么內(nèi)容繪制到什么地方,每一部分都要計(jì)算,而這是比較繁瑣的,所以瀏覽器提供了一些布局用的樣式,并且提供了 css 來(lái)描述,而內(nèi)容部分則是通過(guò) html 描述。
開(kāi)發(fā)者只需要使用 html 描述內(nèi)容的結(jié)構(gòu),然后用 css 來(lái)描述布局和如何渲染,就可以完成界面的繪制。網(wǎng)頁(yè)會(huì)把 html 解析成 dom 樹(shù),把 css 解析成 cssom 樹(shù),之后把兩者合并成 render 樹(shù),自動(dòng)計(jì)算出什么內(nèi)容繪制到什么位置,實(shí)現(xiàn)最終的渲染。
dom 是有 id、class、tagName 等標(biāo)識(shí)的,邏輯的部分就通過(guò)這些標(biāo)識(shí)給具體 dom 綁定一些事件處理函數(shù),然后在函數(shù)里面操作 dom 來(lái)實(shí)現(xiàn)的界面的交互。
dom api 是最終瀏覽器提供給開(kāi)發(fā)者的構(gòu)建 web 應(yīng)用的接口,算是 web 應(yīng)用的物理層。
當(dāng)然,現(xiàn)在開(kāi)發(fā) web 應(yīng)用并不會(huì)直接基于 dom api,而是會(huì)選擇某一個(gè)前端框架,比如 vue、react、angular 等。
這些框架實(shí)現(xiàn)了組件的功能,也就是對(duì)頁(yè)面做的邏輯的拆分,把相同功能的 html、css、js 聚合在一起,使之可以復(fù)用。并且提供了 mvvm 的功能,自動(dòng)做數(shù)據(jù)到具體 dom 的映射,而不再需要開(kāi)發(fā)者手動(dòng)操作 dom。
前端框架做的事情相當(dāng)于是 web 應(yīng)用的邏輯層,最終的渲染和交互還是通過(guò) dom api,但是用戶不需要直接操作,而是在邏輯層描述組件和數(shù)據(jù),由前端框架完成數(shù)據(jù)到 dom 的自動(dòng)映射。
現(xiàn)在的跨端方案基本都是對(duì)物理層的 dom api 做了替換,然后上層對(duì)接一個(gè)邏輯層的前端框架來(lái)支持跨端的應(yīng)用開(kāi)發(fā)。
css 的兩部分
css 是瀏覽器提供給開(kāi)發(fā)者的描述界面的方式,而描述界面分為兩部分:
- 內(nèi)容繪制在什么地方
- 內(nèi)容怎么繪制
內(nèi)容繪制在什么地方就是布局的部分,主要是 display 和 position 的樣式。而內(nèi)容怎么繪制則跟具體內(nèi)容相關(guān),font、text、image 等內(nèi)容都有各自的一些樣式。
本文我們主要來(lái)探究 css 做布局的部分。
盒模型
首先,所有的內(nèi)容都會(huì)有一些空白和與其他元素的間距,所以 css 抽象出了盒模型的概念,也就是任何一個(gè)塊都是由 content、padding(空白)、border、margin(間距)這幾部分構(gòu)成。
display
但是盒與盒之間也是有區(qū)別的,有的盒可以在同一行顯示,有的則是獨(dú)占一行,而且對(duì)內(nèi)容的位置的計(jì)算方式也不一樣。于是提供了 display 樣式來(lái)設(shè)置盒類型,比如 block、inline、inline-block、flex、table-cell、grid 等,分別設(shè)置成不同的盒類型,就會(huì)使用不同的計(jì)算規(guī)則。
- block 的元素會(huì)獨(dú)占一行、可以設(shè)置內(nèi)容的寬高,具體計(jì)算規(guī)則叫做 BFC。
- inline 的元素寬高由內(nèi)容撐開(kāi)不可設(shè)置,不會(huì)獨(dú)占一行,具體計(jì)算規(guī)則叫做 IFC。
- flex 的子元素可以自動(dòng)計(jì)算空白部分,由 flex 樣式指定分配比例,具體計(jì)算規(guī)則叫做 FFC。
- grid 的子元素則是可以拆分成多個(gè)行列來(lái)計(jì)算位置,具體計(jì)算規(guī)則叫 GFC。
這些都是不同盒類型的布局計(jì)算規(guī)則。
position
根據(jù)不同盒類型的布局計(jì)算規(guī)則往往不夠用,很多場(chǎng)景下需要一些用戶自定義的布局規(guī)則,所以 css 提供了 position 樣式,包括 static、relative、absolute、fixed、sticky。
static
默認(rèn)盒的定位方式就是 static,也就是流式的,上個(gè)盒子顯示到什么地方了,下個(gè)盒子就在下面繼續(xù)計(jì)算位置,顯示在什么位置是由內(nèi)容多少來(lái)決定的。
最開(kāi)始的時(shí)候網(wǎng)頁(yè)主要是用來(lái)顯示一些文本,所以流式的位置計(jì)算規(guī)則就很方便。
relative
流式的規(guī)則是根據(jù)上個(gè)盒子的位置自動(dòng)計(jì)算出下個(gè)盒子的位置,但有的時(shí)候想做一些偏移,這種就可以通過(guò) relative 來(lái)指定,設(shè)置 position 為 relative,然后通過(guò) top、bottom、left、right 來(lái)指定如何偏移。
相對(duì)布局給流式布局增加一些靈活性,可以在流式計(jì)算規(guī)則的基礎(chǔ)上做一些偏移。
absolute
流式的計(jì)算規(guī)則具體什么內(nèi)容顯示在什么位置是不固定的,只適合文字、圖片等內(nèi)容的布局。但是比如一些面板需要固定下來(lái),就在某個(gè)位置不要?jiǎng)?,就可以通過(guò) position 設(shè)置為 absolute,就可以脫離文檔流了。這時(shí)候就可以根據(jù)上個(gè)非流式的 position 來(lái)計(jì)算現(xiàn)在的 position。
fixed
absolute 是根據(jù)上一個(gè)脫離了文檔流的 position 來(lái)計(jì)算位置的,最外層的 absolute 的元素是根據(jù)窗口定位。如果想直接根據(jù)窗口來(lái)定位可以指定 position 為 fixed。這個(gè)時(shí)候的 top、bottom、left、right 就是相對(duì)于窗口的。
sticky
sticky 的效果在滾動(dòng)的時(shí)候如果超過(guò)了一定的高度就 fixed 在一個(gè)位置,否則的話就 static。相當(dāng)于基于 static 和 fixed 做的一層封裝,實(shí)現(xiàn)導(dǎo)航條吸頂效果的時(shí)候可以直接用。
或許就是因?yàn)樘S茫欧庋b出了這樣一個(gè) position 的屬性值吧,之前都是通過(guò) js 監(jiān)聽(tīng)滾動(dòng)條位置來(lái)分別設(shè)置 static 和 fixed 的。
小結(jié)
所謂的布局就是確定元素的位置,設(shè)置了盒的類型(display)之后對(duì)于內(nèi)容如何渲染會(huì)有不同的規(guī)則,比如 BFC、IFC、FFC、GFC 等。
盒與盒之間默認(rèn)是流式的,也就是 position 為 static,但有的時(shí)候想在流中做下偏移,用 relative。當(dāng)不想跟隨文檔流了,可以設(shè)置 absolute 來(lái)相對(duì)于上個(gè)非 static 位置來(lái)計(jì)算一個(gè)固定的位置,如果想直接相對(duì)于窗口,就用 fixed。
當(dāng)需要做吸頂效果的時(shí)候,要根據(jù)滾動(dòng)位置切換 static 和 fixed,這時(shí)候 css 還有一個(gè) sticky 的定位方式可以直接用。
也就是說(shuō),盒內(nèi)部的布局計(jì)算規(guī)則根據(jù) display 來(lái)確定,還可以用 position 做一些調(diào)整。
vscode 是如何布局的
講了 css 的布局方式(也就是 display 配合 position)之后,我們來(lái)看一個(gè)具體的案例:vscode 是如何布局的。
vscode 是我們經(jīng)常用的 ide,它基于 electron,也就是通過(guò)網(wǎng)頁(yè)來(lái)繪制界面,那么它是怎么做布局的呢?
vscode 分為了標(biāo)題欄、狀態(tài)欄、內(nèi)容區(qū),是上中下結(jié)構(gòu),而內(nèi)容區(qū)又分為了活動(dòng)欄、側(cè)邊欄、編輯區(qū),是左中右結(jié)構(gòu)。窗口可以調(diào)整大小,而這個(gè)上中下嵌套左中右的結(jié)構(gòu)是不變的。
這種布局如何實(shí)現(xiàn)呢?
css 的布局就是 display 配合 position 來(lái)確定每一塊內(nèi)容的位置。我們的需求是窗口放縮但每一塊的相對(duì)位置不變,這種用 absolute 的布局就可以實(shí)現(xiàn)。
首先,最外層是上中下的結(jié)構(gòu),可以把每一塊設(shè)置為 absolute,然后分別設(shè)置 top 值,然后中間部分由分為了左中右,可以再分別設(shè)置左中右部分的 left 值,這樣就完成了每一塊的布局。
這是整體的布局,每一塊內(nèi)部則根據(jù)不同的布局需求分別使用流式、彈性等不同的盒,配合絕對(duì)、相對(duì)等定位方式來(lái)布局。
但是,絕對(duì)定位是要指定具體的 top、bottom、left、right 值,是靜態(tài)的,而窗口大小改變的時(shí)候需要?jiǎng)討B(tài)的設(shè)置具體的值。這時(shí)候就需要監(jiān)聽(tīng)窗口的 resize 事件來(lái)重新布局,分別計(jì)算不同塊的位置。
而且 vscode 每一塊的大小是也是可以拖動(dòng)改變大小的,也要在拖動(dòng)的時(shí)候重新計(jì)算 left、top 的值。
總結(jié)
現(xiàn)代軟件基本都是有用戶界面的,而不同操作系統(tǒng)下構(gòu)建 UI 的方式不同,所以跨平臺(tái)渲染的瀏覽器的方案逐漸流行開(kāi)來(lái)。移動(dòng)互聯(lián)網(wǎng)時(shí)代之后,為了綜合原生的體驗(yàn)和網(wǎng)頁(yè)的跨平臺(tái),出現(xiàn)了跨端引擎的方案,也就是基于安卓、ios 分別實(shí)現(xiàn) dom api 并注入一些設(shè)備能力的 api 給 JS 引擎,業(yè)務(wù)代碼通過(guò) dom api 來(lái)描述 UI。
dom api 是瀏覽器提供給開(kāi)發(fā)者的描述 UI 的方式,是物理層?,F(xiàn)在的前端框架可以完成組件的封裝和數(shù)據(jù)到 dom 的映射,不再需要直接操作 dom,算是邏輯層。
因?yàn)榭缍艘鎸?shí)現(xiàn)了 dom api,所以上層可以對(duì)接前端框架。
UI 是通過(guò) css 來(lái)描述的,而 css 可以分為兩部分:布局和具體元素的渲染。
具體 font、text、image 等分別有不同的樣式來(lái)描述如何渲染,而布局是確定每個(gè)元素的位置,由 display 配合 position 來(lái)確定。
網(wǎng)頁(yè)的每一個(gè)內(nèi)容都是一個(gè)盒,由 content、padding、border、margin 構(gòu)成,而 display 是設(shè)置盒的類型,不同的盒有不同的布局規(guī)則,比如 BFC、IFC、FFC、GFC 等。
當(dāng)有一些需要定制的布局規(guī)則,可以使用 position。默認(rèn)的 position 是 static,也就是流式的,根據(jù)上個(gè)盒來(lái)確定下個(gè)盒的位置,可以使用 relative 做一些偏移,如果想相對(duì)于某個(gè)位置固定,可以使用 absolute,當(dāng)直接相對(duì)窗口的時(shí)候使用 fixed。此外,在做吸頂效果的時(shí)候,可以使用 sticky,它是基于 static 和 fixed 的封裝。
知道了 display 和 position 都怎么做布局,也就是計(jì)算盒的位置以后,我們看了下 vscode 是怎么布局的。
vscode 是上中下嵌套左中右的結(jié)構(gòu),窗口改變或者拖動(dòng)都可以調(diào)整每塊大小,所以使用嵌套的 absolute 的方式來(lái)做整體的布局。每一塊的內(nèi)部則綜合使用流式、彈性等方式配合 position 分別做更細(xì)節(jié)的布局。
網(wǎng)頁(yè)的 css 布局方案已經(jīng)應(yīng)用在越來(lái)越多的領(lǐng)域,比如跨端引擎通過(guò)安卓、ios 實(shí)現(xiàn) css,kraken 基于 flutter 實(shí)現(xiàn) css,所以 css 的布局方式是我們必須掌握的技能。希望這篇文章能幫大家梳理清楚 css 布局的思路,對(duì)各種布局都能夠分析清楚特性,然后用合適的方案來(lái)實(shí)現(xiàn)。
本文名稱:CSS布局的本質(zhì)是什么
網(wǎng)頁(yè)路徑:http://www.dlmjj.cn/article/djisspi.html


咨詢
建站咨詢
