相信不少人都在項目中用過這麼一個玩意 —— NProgress.js庫,或者是其它相似的庫,它們的做用很實用:頁面加載進度提示。
顧名思義,就是在剛進入頁面或刷新或請求數據時在頁面頂部有一個進度條給用戶以反饋,使頁面加載顯得不那麼「尷尬」。javascript
但只有不多人見過 「在頁面頂部實時反饋當前閱讀進度」 的效果 —— 爲何?由於有滾動條。
但不得不提的是:這真的頗有用!不論是「在有些要求高的頁面對自帶滾動條很厭惡」仍是「即便有滾動條也能夠給用戶更好看的提示效果」。固然,目前第一種場景比較多。css
用JS達到實時進度提示效果
這得益於JS的一些「別緻」的API ——html
- 滾動距離:
document.documentElement.scrollTop || document.body.scrollTop;
- 獲取文檔真實高度:
document.documentElement.scrollHeight;
- 獲取瀏覽器窗口可視高度:
document.documentElement.clientHeight;
這裏須要注意的是:scrollTop指的是啥?頁面滾動條縱座標位置。也就是頁面相對於窗口顯示區左上角的Y座標。因此有的地方也用下面的API代替:
window.pageYOffset
java
回到咱們這個想法中:其實咱們要展現出來的,不就是「當前向上滑動了多少」與「文檔區域總高度」的比例嗎?
那若是實時監聽變化並展現到頁面上,不就成了?git
let scrollHeight=document.documentElement.scrollHeight; let clientHeight=document.documentElement.clientHeight; document.addEventListener('scroll',function(e){ let scrollTop=document.documentElement.scrollTop || document.body.scrollTop; const sizeHeight=+(scrollTop/(scrollHeight-clientHeight)).toFixed(2)*100; console.log(sizeHeight) })
而後將其展現到頁面上 —— 採用css控制父元素位置、js控制子元素width的方式渲染:web
<div class="pro_bar"> <div class="bar_cess"></div> </div>
.pro_bar{ position: fixed; top: 0; left: 0; width: 100%; height: 3px; background-color: #DDD; overflow: hidden; } .pro_bar .bar_cess{ position: absolute; left: 0; height: 100%; background-color: #0089f2; }
let scrollHeight=document.documentElement.scrollHeight; let clientHeight=document.documentElement.clientHeight; let bar=document.querySelector('.bar_cess'); document.addEventListener('scroll',function(e){ let scrollTop=document.documentElement.scrollTop || document.body.scrollTop; const sizeHeight=+(scrollTop/(scrollHeight-clientHeight)).toFixed(2)*100; bar.style.width=sizeHeight+"%"; })
但js實現不免會遇到好比「迴流和重繪」一類的性能問題。一般一看到監聽resize之流就會下意識的「防抖」、「節流」、「脫離文檔流渲染」…如臨大敵。
其實dark沒必要:api
用CSS實現進度提示
這個的實現原理也很簡單,是筆者以前提過的 —— linear-gradient
,嘿嘿,沒想到吧?讓我來帶各位逐步分析:
首先,是linear-gradient的第一個參數。它是規定方向的 —— 這裏須要注意的是:它實際至關於「劃」了一條線,按你規定的方向從你規定的比例中將頁面給分割開(這一點具體的參見我這篇文章),好比 linear-gradient(to right top, #0089f2 50%, #DDD 50%)
,效果以下:
瀏覽器
有了這麼一個「藍色三角形」,你有沒有想到什麼?svg
若是控制寬高把這部分大小設置爲「滾動條拉到最底部時藍色區域的最底部也恰好到頁面頂部」,就像這樣:
那豈不就接近咱們想要的效果了?
這有兩種實現方式!wordpress
- 第一種方式:
body{ background: linear-gradient(to right top, #0089f2 50%, #DDD 50%); background-size: 100% calc(100% - 122vh + 129px); background-repeat: no-repeat; }
經過 background-size
設置了漸變的大小:
進一步說,咱們須要的是一個頂部的滾動條,而不是全屏的三角塊 —— 大方向已經肯定了,這時候就能夠經過僞元素去覆蓋三角形背景區域,使之只在頂部一小塊區域內展現出來!
爲何要用僞元素呢?其實更確切地說仍是
::before/::after
,由於僞元素不在文檔流以內,方便渲染和控制,並且,這裏設置linear-gradient的是background,咱們若是想要實現「覆蓋」,也就只能用一個「屬於相同元素自身」的屬性去實現。綜合來講,在相似場景下,僞元素是最好的選擇了。
實現代碼:
<main> <h2>I was interested to see if I could make a scroll indicator with just CSS.</h2> <p>You can! But maybe you shouldn't. This is an interesting consequence of a bunch of hacks held together with duct tape. It uses z-index hacks, gradient hacks and tricks with calc and viewport units.</p> <p>Having said that, hacks are not always bad. I love hacks and many of us have made quite a good living selling floats and clearfixes.</p> <p>The techniques used here are well supported, if not conventional. If you can read the CSS, understand how it works, and how to change it, and you think this works better for you than JavaScript, feel free to implement it. Just be aware of the z-index behaviour and possible conflict with other CSS using negative z-index.</p> <hr> <h3>Tristique Aenean Etiam Cras</h3> <p>Donec id elit non mi porta gravida at eget metus. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Donec sed odio dui. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.</p> <p>Cras mattis consectetur purus sit amet fermentum. Donec id elit non mi porta gravida at eget metus. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Etiam porta sem malesuada magna mollis euismod. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec ullamcorper nulla non metus auctor fringilla.</p> <p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Donec ullamcorper nulla non metus auctor fringilla. Sed posuere consectetur est at lobortis. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Aenean lacinia bibendum nulla sed consectetur. Nulla vitae elit libero, a pharetra augue.</p> <p>Donec sed odio dui. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Cras mattis consectetur purus sit amet fermentum. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> <ul> <li>Ullamcorper Aenean Ornare</li> <li>Ridiculus Lorem Malesuada Consectetur</li> <li>Aenean Tristique Sit Lorem Purus</li> <li>Vehicula Egestas Mollis Cursus Nibh</li> </ul> <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Sed posuere consectetur est at lobortis. Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Nullam id dolor id nibh ultricies vehicula ut id elit. Aenean lacinia bibendum nulla sed consectetur. Nullam quis risus eget urna mollis ornare vel eu leo.</p> <h3>Bibendum Aenean Dapibus Tristique</h3> <p>Cras mattis consectetur purus sit amet fermentum. Donec id elit non mi porta gravida at eget metus. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Etiam porta sem malesuada magna mollis euismod. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec ullamcorper nulla non metus auctor fringilla.</p> <p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Donec ullamcorper nulla non metus auctor fringilla. Sed posuere consectetur est at lobortis. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Aenean lacinia bibendum nulla sed consectetur. Nulla vitae elit libero, a pharetra augue.</p> <p>Donec sed odio dui. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Cras mattis consectetur purus sit amet fermentum. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> <ul> <li>Ullamcorper Aenean Ornare</li> <li>Ridiculus Lorem Malesuada Consectetur</li> <li>Aenean Tristique Sit Lorem Purus</li> <li>Vehicula Egestas Mollis Cursus Nibh</li> </ul> <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Sed posuere consectetur est at lobortis. Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Nullam id dolor id nibh ultricies vehicula ut id elit. Aenean lacinia bibendum nulla sed consectetur. Nullam quis risus eget urna mollis ornare vel eu leo.</p> <h2>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.</h2> <p>Cras mattis consectetur purus sit amet fermentum. Donec id elit non mi porta gravida at eget metus. Donec id elit non mi porta gravida at eget metus. Aenean lacinia bibendum nulla sed consectetur.</p> </main>
html,body { margin:0;padding: 0;} @supports (height: 100vh) { body{ background: linear-gradient(to right top, #0089f2 50%, #DDD 50%); background-size: 100% calc(100% - 122vh + 129px); /** 這裏「%」換成「vw」也可 */ background-repeat: no-repeat; } body::before{ content:''; position: fixed; top: 2px; bottom: 0; width: 100%; z-index: -1; background: #fff; /** 這個纔是真正頁面的背景!不論是顏色仍是圖片都在這裏替換! */ } }
這種方法固然也有一絲缺點:它須要「只能偏大不能偏小」的控制background-size
的寬度,可是這顯然不適應精確在不一樣分辨率大小且須要響應式的屏幕中展現!
- 第二種方法:
通過上面的折騰,我想咱們已經掌握了「密碼」:定位+覆蓋。
若是你不想直接在body中操做,你徹底能夠再定義一個元素,讓它跟隨body定位不就能夠了?由於body是不會動的,相對body定位就能夠達到fixed效果!
<!-- 在body下添加一個空標籤 --> <div class="scroll_fixed"></div>
body { position: relative; } .scroll_fixed { position: absolute; top: 0; right: 0; left: 0; bottom: 0; background: linear-gradient(to right top, #0089f2 50%, transparent 50%) no-repeat; background-size: calc(100% + 5px) calc(100% - 100vh + 17px); z-index: 1; pointer-events: none; mix-blend-mode: darken; } .scroll_fixed::after { content: ''; position: fixed; top: 2px; bottom: 0; right: 0; left: 0; background: #fff; z-index: 1; }
這種方式對於第一種方式的缺點很是完美的解決了,可是這種方式對於頁面總體背景沒有強制要求顏色或圖片的還能夠,但在我爲「不當心」爲body加了背景圖後,它就不行了、沒有效果了。(由於上面說了,這種方式實現的特色是同級z-index覆蓋僞元素的「僞頁面」)
這裏面有個mix-blend-mode: darken;
,這是個很是好用的屬性 —— 規定被規定的元素和它下面的背景相比誰的顏色深就用誰的顏色!(就是這個玩意引發的問題)
這個小知識是筆者跟張鑫旭老師的 這篇文章 學到的,嘿嘿,還挺好用
本文同步分享在 博客「行舟客」(CSDN)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。