單屏頁(yè)面響應(yīng)式適配玩法
首先瞅一下效果圖
接著就是思考怎么做,我的想法如下圖。
把公共的 頁(yè)頭 、頁(yè)腳、導(dǎo)航欄、邊框 放到最頂層,比方說(shuō)設(shè)置層級(jí)為 999,其他每個(gè)獨(dú)立頁(yè)則放在下面,然后切換頁(yè)面的時(shí)候更新獨(dú)立頁(yè)的層級(jí)以達(dá)到效果圖的效果(當(dāng)然不能超過(guò)最頂層)。
適配
上面的方式已經(jīng)把效果做出來(lái)了,接下來(lái)就是響應(yīng)式適配了。
1、Mac OS + Chrome
先考慮一下我自己的系統(tǒng)及顯示器,
MacBook Pro 1440 x 900 + 外設(shè) hp 1920 x 1080
也就是說(shuō) Chrome 的網(wǎng)頁(yè)可視區(qū)高度大概為: 900(或1080) - 180 = 720px
180 = 60 + 20 + 100
- 60: MAC 桌面程序塢動(dòng)態(tài)尺寸,60 可能是我常用的尺寸吧,那就先這個(gè)
- 20: MAC 桌面最頂部 icon 放置欄高度
- 100: Chrome 標(biāo)簽頁(yè)高度 + 地址欄高度 + 書簽欄高度
2、Windows + Chrome
然后我們?cè)倏纯?Windows + Chrome 的情況,以 1366 x 768 為例,
Chrome 的網(wǎng)頁(yè)可視區(qū)高度大概為 768 - 150 = 618px
150 = 40 + 110
- 40: Windows 桌面底部程序塢尺寸
- 110: Chrome 標(biāo)簽頁(yè)高度 + 地址欄高度 + 書簽欄高度
3、總結(jié)上面兩點(diǎn)
- 以上兩點(diǎn)的高度計(jì)算通過(guò)截圖獲得,可能會(huì)有些許誤差。
- 所以不管在哪種系統(tǒng)下,瀏覽器的寬度與分辨率是保持一致的(程序塢在底部的時(shí)候,程序塢在左右兩邊一般情況對(duì)寬度沒有影響),高度則根據(jù)系統(tǒng)及瀏覽器的不同各有不同,比方說(shuō) Safari 沒有書簽高度。
- 不同系統(tǒng)加瀏覽器占用的***高度約為 180,最小約為 0(全屏的時(shí)候)
4、主流系統(tǒng)分辨率尺寸
然后我們看下當(dāng)前主流系統(tǒng)及分辨率有哪些
PC & MAC & Chrome
常用
- 1280 x 800
- 1366 x 1024 (IPad Pro)
- 1440 x 900
- 1680 x 1050
- 1600 x 900
- 1920 x 1200
- 2560 x 1440
更高忽略
- 2880 x 1620
- 3200 x 1800
- 5120 x 2880
PC & Windows & Chrome (或 PC & MAC & Chrome & 外設(shè)顯示器)
- 1280 x 720/1024
- 1366 x 768
- 1440 × 900
- 1600 x 900
- 1920 x 1080
- 360 x 480
- 412 x 732
- 待補(bǔ)充
Mobile & IOS
- IPhone 6: 375 x 667
- IPhone 6 Plus: 414 x 736
- IPhone X: 375 x 812
不上不下的 IPad:
- 768 x 1024
5、分析
我們以寬度 1024 及以下算作移動(dòng)端,以上算作 PC 端,所以兩種選擇
- 移動(dòng)端適配一個(gè)移動(dòng)端頁(yè)面,PC 端適配一個(gè) PC 端頁(yè)面。
- 設(shè)計(jì)之初就想好一個(gè)頁(yè)面適配兩端,當(dāng)然這個(gè)設(shè)計(jì)稿需要比較符合適配兩端的條件。
6、別人適配是怎么做的?
貼個(gè)錄制的視頻~
所以,單屏頁(yè)面***頁(yè)面內(nèi)容言簡(jiǎn)意賅,設(shè)計(jì)層面傾向于水平垂直都居中的情況,是最適合做好這個(gè)頁(yè)面的,并且在各種尺寸變化的情況下能比較良好地展示UI,且開發(fā)成本也比較合理。
7、自身情況及實(shí)現(xiàn)
我們是分兩個(gè)頁(yè)面做的,先看一下 PC 端設(shè)計(jì)稿:
結(jié)合動(dòng)畫的展現(xiàn)形式,其實(shí)并不是很理想做響應(yīng)式,但還是要適配。
本來(lái)想用 rem 做適配的,但是 rem 需要些寫很多個(gè)匹配,即下面的代碼
- @media all and (max-width: 1024px) {
- html, body {
- font-size: 10px;
- }
- }
- @media all and (max-width: 1366px) {
- html, body {
- font-size: 12px;
- }
- }
- // 1680 1920 2560 等
然后有個(gè)問(wèn)題就是,@media 是根據(jù) width 的變化來(lái)匹配的,完全按照桌面分辨率來(lái)顯示是沒問(wèn)題的,不過(guò)高度隨便調(diào)節(jié)一下(變小),而寬度還是很寬,這時(shí)候頁(yè)面底部的部分文本就會(huì)溢出被隱藏掉。
我們不需要考慮更低端的瀏覽器,所以可以使用比較前沿的特性,如 pointer-events 等特性。
所以使用 vh 做適配方案,vh 是什么單位詳情可以自己查閱一下文檔,這里做個(gè)簡(jiǎn)單介紹。
- vw: 相對(duì)于瀏覽器可視區(qū)的寬度 1vw = 瀏覽器可視區(qū)寬度的 1%
- vh: 相對(duì)于瀏覽器可視區(qū)的高度 1vh = 瀏覽器可視區(qū)高度的 1%
也就是說(shuō) 100vh 實(shí)際上等于瀏覽器可視區(qū)的高度,所以 px 與 vh 的換算我們舉個(gè)例子說(shuō)明一下(一個(gè)很簡(jiǎn)單的數(shù)學(xué)換算)。假設(shè)瀏覽器可視區(qū)高度為 720px,某個(gè)元素的寬度為 300px,那應(yīng)該寫成多少 vh 才與 300px 相等呢,如下。
- 300 ÷ (720 ÷ 100) ≈ 41.666
比如設(shè)計(jì)稿為 1920x1080(單屏設(shè)計(jì)高度應(yīng)該更小一點(diǎn),如適配***節(jié)所說(shuō)),可以寫個(gè) CSS 預(yù)處理函數(shù),這樣方便直接使用設(shè)計(jì)稿的尺寸,以 Sass 為例如下。
- @function vh( $value ) {
- @return ( $value / 1080 / 100 ) + vh;
- }
- 或者
- @function vw( $value ) {
- @return ( $value / 1920 / 100 ) + vw;
- }
然后,300px 可以無(wú)縫寫成 vh(300) 或 vw(300)。
so… 對(duì)于我們的頁(yè)面選擇 vh 一舉兩得,不用寫很多 rem 匹配,也不會(huì)出現(xiàn)溢出的問(wèn)題。
因?yàn)楦叨茸儼瑑?nèi)容的尺寸會(huì)隨之變小,而頁(yè)面是 1190 寬,水平居中布局,所以當(dāng)只改變?yōu)g覽器寬度的情況下,不會(huì)出現(xiàn)寬度變化溢出問(wèn)題(除非分辨率超大,然后高度居很高,只把寬度縮很小的情況,這個(gè)下面會(huì)說(shuō)到)。寫完后在上面列舉的主流分辨率下一一測(cè)試通過(guò)。
看看效果(當(dāng)然這個(gè)是最終效果,只改變寬度的拉伸適配在***會(huì)說(shuō)):
8、特殊場(chǎng)景
這里就是剛剛說(shuō)到的 分辨率超大,然后高度居很高,只把寬度縮很小的情況,因?yàn)樵O(shè)計(jì)稿是長(zhǎng)寬比例為橫向矩形,所以明顯與用長(zhǎng)寬比為豎向的矩形來(lái)看頁(yè)面是背道而馳的。
委屈委屈,但還是要兼容下,至少看起來(lái)要顯示正常。
8.1、嘗試 rem + vh 方案
一開始想的是 rem + vh 結(jié)合使用,根元素 html 使用 vh,其他單位則使用 rem,然后找到有問(wèn)題的寬高比,通過(guò) @media 方式設(shè)置 html 為 vw 來(lái)達(dá)到適配。
事實(shí)是,rem 縮小到一定值就不會(huì)再縮小了,這個(gè)跟瀏覽器對(duì)字體大小限制為最小 12px 一樣,看個(gè)例子。
根字體小于 12px 以后,rem 對(duì)應(yīng)的值則都是設(shè)置的倍數(shù)乘以 12;設(shè)置根字體為 vh, vw 單位同理,rem 會(huì)在 vh, vw 換算達(dá)到 12 以后就不再改變。
PPPS: 是不是有點(diǎn)坑,應(yīng)該字體的屬性最小值為 12,而其他屬性的值沒有控制才對(duì)
所以,如果使用 rem + vh 方案,在界面縮小到一定尺寸后繼續(xù)縮小,有些值達(dá)到最小值固定不變,而有些值仍在變小,UI 的展示就變得混亂。
8.2、落地方案,vh + vw + JavaScript 計(jì)算
而直接在元素的屬性值上設(shè)置為 vh 或 vw,所有的值都會(huì)實(shí)時(shí)變動(dòng),沒有最小值(除了屬性為字體有最小值),這樣就***程度減少 UI 變亂的情況了,除非縮到很小很小,那就…(此處省略 1000 個(gè)字)。
于是乎,現(xiàn)在的想法是
- 在原來(lái)以 vh 為基礎(chǔ)的情況下,拷貝所有帶 vh 單位的代碼,把 vh 換成 vw,當(dāng)然這些改動(dòng)都在一個(gè)比如叫 .vw-mode 的類下面,基本上可以無(wú)縫遷移,只需替換 vh 函數(shù)名即可。
- 把 .vw-mode 下的內(nèi)容設(shè)置為上下居中。
- 通過(guò) JS 計(jì)算,當(dāng)可視區(qū)比例為豎向比例時(shí),則在頂層元素加上 .vw-mode 類名,當(dāng)比例為橫向比例時(shí),則去掉 .vw-mode 類名。
大致的代碼如下:
CSS
- .homepage.vw-mode {
- font-size: vw(14);
- .com-width {
- width: vw(1190);
- }
- .hp-header {
- padding-top: vw(30);
- // ...更多代碼
- }
- // ...更多代碼
- }
JS
- this.resizeHandler = () => {
- const clientWidth = document.documentElement.clientWidth
- const clientHeight = document.documentElement.clientHeight
- // 當(dāng)長(zhǎng)寬比為豎向比例時(shí)
- const isVerticalRatio = clientWidth / clientHeight < 1370 / 890
- $homepageElem.classList[isVerticalRatio ? 'add' : 'remove']('vw-mode')
- }
- this.resizeHandler()
- window.addEventListener('resize', this.resizeHandler)
***的結(jié)果就是上面那個(gè) GIF 效果圖了。
9、移動(dòng)端
移動(dòng)端用戶是沒法操作瀏覽器的,所以基本上都是標(biāo)準(zhǔn)的長(zhǎng)寬比,用 vh 最合適不過(guò)了,或 vw。
10、***
體驗(yàn)(官網(wǎng)):https://ling.jd.com
體驗(yàn)瀏覽器:Chrome、Safari 新版,其他瀏覽器暫不支持
【本文是51CTO專欄作者“凹凸實(shí)驗(yàn)室”的原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)通過(guò)51CTO聯(lián)系原作者獲取授權(quán)】