單屏頁面響應式適配玩法
首先瞅一下效果圖
接著就是思考怎麼做,我的想法如下圖。
把公共的 頁頭
、頁尾
、導航欄
、邊框
放到最頂層,比方說設定層級為 999
,其他每個獨立頁則放在下面,然後切換頁面的時候更新獨立頁的層級以達到效果圖的效果(當然不能超過最頂層)。
適配
上面的方式已經把效果做出來了,接下來就是響應式適配了。
1、Mac OS + Chrome
先考慮一下我自己的系統及顯示器,
MacBook Pro 1440 x 900
+ 外設 hp 1920 x 1080
也就是說 Chrome
的網頁可視區高度大概為: 900(或1080) - 180 = 720px
180 = 60 + 20 + 100
123 | 60:MAC桌面程式塢動態尺寸,60可能是我常用的尺寸吧,那就先這個20:MAC桌面最頂部icon放置欄高度100:Chrome標籤頁高度+位址列高度+書籤欄高度 |
2、Windows + Chrome
然後我們再看看 Windows + Chrome
的情況,以 1366 x 768
為例,
Chrome
的網頁可視區高度大概為 768 - 150 = 618px
150 = 40 + 110
JavaScript12 | 40:Windows桌面底部程式塢尺寸110:Chrome標籤頁高度+位址列高度+書籤欄高度 |
3、總結上面兩點
- 以上兩點的高度計算通過截圖獲得,可能會有些許誤差。
- 所以不管在哪種系統下,瀏覽器的寬度與解析度是保持一致的(程式塢在底部的時候,程式塢在左右兩邊一般情況對寬度沒有影響),高度則根據系統及瀏覽器的不同各有不同,比方說
Safari
沒有書籤高度。 - 不同系統加瀏覽器佔用的最高高度約為 180,最小約為 0(全屏的時候)
4、主流系統解析度尺寸
然後我們看下當前主流系統及解析度有哪些
PC & MAC & Chrome
JavaScript123456789101112 | 常用1280x8001366x1024(IPad Pro)1440x9001680x10501600x9001920x12002560x1440更高忽略2880x16203200x18005120x2880 |
PC & Windows & Chrome (或 PC & MAC & Chrome & 外設顯示器)
JavaScript12345 | 1280x720/10241366x7681440×9001600x9001920x1080 |
Mobile & Android
JavaScript123 | 360x480412x732待補充 |
Mobile & IOS
JavaScript123 | IPhone6:375x667IPhone6 Plus:414x736IPhone X:375x812 |
不上不下的 IPad:
JavaScript1 | 768x1024 |
5、分析
我們以寬度 1024
及以下算作移動端,以上算作 PC 端,所以兩種選擇
- 移動端適配一個移動端頁面,PC 端適配一個 PC 端頁面。
- 設計之初就想好一個頁面適配兩端,當然這個設計稿需要比較符合適配兩端的條件。
6、別人適配是怎麼做的?
貼幾個錄製的視訊~
所以,單屏頁面最好頁面內容言簡意賅,設計層面傾向於水平垂直都居中的情況,是最適合做好這個頁面的,並且在各種尺寸變化的情況下能比較良好地展示UI,且開發成本也比較合理。
7、自身情況及實現
我們是分兩個頁面做的,先看一下 PC 端設計稿
結合動畫的展現形式,其實並不是很理想做響應式,但還是要適配。
本來想用 rem
做適配的,但是 rem
需要些寫很多個匹配,即下面的程式碼
1234567891011 | @media all and (max-width: 1024px) { html, body { font-size: 10px;}}@media all and (max-width: 1366px) { html, body { font-size: 12px;}}//168019202560等 |
然後有個問題就是,@media
是根據 width
的變化來匹配的,完全按照桌面解析度來顯示是沒問題的,不過高度隨便調節一下(變小),而寬度還是很寬,這時候頁面底部的部分文字就會溢位被隱藏掉。
我們不需要考慮更低端的瀏覽器,所以可以使用比較前沿的特性,如 pointer-events
等特性。
所以使用 vh
做適配方案,vh
是什麼單位詳情可以看下這篇文章,這裡做個簡單介紹。
12 | vw:相對於瀏覽器可視區的寬度1vw=瀏覽器可視區寬度的1%vh:相對於瀏覽器可視區的高度1vh=瀏覽器可視區高度的1% |
也就是說 100vh
實際上等於瀏覽器可視區的高度,所以 px
與 vh
的換算我們舉個例子說明一下(一個很簡單的數學換算)。假設瀏覽器可視區高度為 720px
,某個元素的寬度為 300px
,那應該寫成多少 vh
才與 300px
相等呢,如下。
1 | 300÷(720÷100)≈41.666 |
比如設計稿為 1920x1080
(單屏設計高度應該更小一點,如適配第一節所說),可以寫個 CSS
預處理函式,這樣方便直接使用設計稿的尺寸,以 Sass
為例如下。
1234567 | <a href="http://www.jobbole.com/members/wx2980501052">@function</a> vh( $value ) {<a href="http://www.jobbole.com/members/wx1409399284">@return</a> ( $value / 1080 / 100 ) + vh;}或者<a href="http://www.jobbole.com/members/wx2980501052">@function</a> vw( $value ) {<a href="http://www.jobbole.com/members/wx1409399284">@return</a> ( $value / 1920 / 100 ) + vw;} |
然後,300px
可以無縫寫成 vh(300)
或 vw(300)
。
so… 對於我們的頁面選擇 vh
一舉兩得,不用寫很多 rem
匹配,也不會出現溢位的問題。
因為高度變矮,內容的尺寸會隨之變小,而頁面是 1190
寬,水平居中佈局,所以當只改變瀏覽器寬度的情況下,不會出現寬度變化溢位問題(除非解析度超大,然後高度居很高,只把寬度縮很小的情況,這個下面會說到)。寫完後在上面列舉的主流解析度下一一測試通過。
看看效果(當然這個是最終效果,只改變寬度的拉伸適配在最後會說):
8、特殊場景
這裡就是剛剛說到的 解析度超大,然後高度居很高,只把寬度縮很小的情況
,因為設計稿是長寬比例為橫向矩形,所以明顯與用長寬比為豎向的矩形來看頁面是背道而馳的。
委屈委屈,但還是要相容下,至少看起來要顯示正常。
8.1、嘗試 rem + vh
方案
一開始想的是 rem + vh
結合使用,根元素 html
使用 vh
,其他單位則使用 rem
,然後找到有問題的寬高比,通過 @media
方式設定 html
為 vw
來達到適配。
事實是,rem
縮小到一定值就不會再縮小了,這個跟瀏覽器對字型大小限制為最小 12px
一樣,看個例子。
根字型小於 12px
以後,rem
對應的值則都是設定的倍數乘以 12
;設定根字型為 vh, vw
單位同理,rem
會在 vh, vw
換算達到 12
以後就不再改變。
PPPS: 是不是有點坑,應該字型的屬性最小值為 12,而其他屬性的值沒有控制才對
所以,如果使用 rem + vh
方案,在介面縮小到一定尺寸後繼續縮小,有些值達到最小值固定不變,而有些值仍在變小,UI 的展示就變得混亂。
8.2、落地方案,vh + vw + JavaScript 計算
而直接在元素的屬性值上設定為 vh 或 vw
,所有的值都會實時變動,沒有最小值(除了屬性為字型有最小值),這樣就最大程度減少 UI 變亂的情況了,除非縮到很小很小,那就…(此處省略 1000 個字)。
於是乎,現在的想法是
- 在原來以
vh
為基礎的情況下,拷貝所有帶vh
單位的程式碼,把vh
換成vw
,當然這些改動都在一個比如叫.vw-mode
的類下面,基本上可以無縫遷移,只需替換vh
函式名即可。 - 把
.vw-mode
下的內容設定為上下居中。 - 通過
JS
計算,當可視區比例為豎向比例時,則在頂層元素加上.vw-mode
類名,當比例為橫向比例時,則去掉.vw-mode
類名。
大致的程式碼如下
CSS
CSS1234567891011 | .homepage.vw-mode {font-size:vw(14);.com-width {width:vw(1190);}.hp-header {padding-top:vw(30);//...更多程式碼}//...更多程式碼} |
JS
JavaScript123456789 | this.resizeHandler=()=>{constclientWidth=document.documentElement.clientWidthconstclientHeight=document.documentElement.clientHeight// 當長寬比為豎向比例時constisVerticalRatio=clientWidth/clientHeight<1370/890$homepageElem.classList[isVerticalRatio?'add':'remove']('vw-mode')}this.resizeHandler()window.addEventListener('resize',this.resizeHandler) |
最後的結果就是上面那個 GIF
效果圖了。
9、移動端
移動端使用者是沒法操作瀏覽器的,所以基本上都是標準的長寬比,用 vh
最合適不過了,或 vw
。
10、最後
體驗瀏覽器:Chrome、Safari 新版,其他瀏覽器暫不支援