最近在作一個項目時,遇到了這樣一個問題:網頁大標題要用設計師指定的中文字體,該字體文件比較大,瀏覽器加載字體文件的過程當中是不會顯示使用該字體的文本的,因而出現了初次打開網頁時有一段時間「No title」的BUG。css
針對該問題,筆者能想到如下幾種解決方案(歡迎補充):html
結合項目特色,最終選擇方案5。程序員
整個過程邏輯很是簡單:首先標題所用的class在CSS中被定義了一個最接近目標字體的安全字體,而後等待字體文件加載,加載完成後將標題的class換成自定義字體的class。npm
首先設好兩個CSS屬性,一個是用最接近目標字體的安全字體,用於默認字體,第二個是自定義字體:後端
/* 定義字體 */ @font-face{ font-family: Lanting_light; src: url("../res/font/goDieDesigner.woff"); } /* 安全字體,用於默認 */ .lanting_l{ font-family: Arial, Helvetica, sans-serif; } /* 自定義字體 */ .lanting_light{ font-family: "Lanting_light",Arial, Helvetica, sans-serif; }
元素設置成默認字體:瀏覽器
<p class="Lanting_l"> 我是一段可愛的文字,啾咪~ </p>
寫一個函數,用於替換元素的class,在字體文件加載完成後執行它:安全
function onLoadedFont() { ele = document.getElementsByClassName("Lanting_l"); for (let i = 0; i < ele.length; i++){ ele[i].classList.add("Lanting_light"); ele[i].classList.remove("Lanting_l"); } }
接下來是整個問題的核心:如何判斷字體文件已被加載?
服務器
一個html元素,能夠用監聽load事件來判斷加載,但字體不是html元素,沒法監聽。
再來看一下需求,字體文件是從用戶打開頁面時就要開始加載了,因此只要讓字體一開始就加載,而後監聽window.load事件就行了:異步
window.addEventListener("load",onLoadedFont);
PS:這裏不太嚴謹,可能會有其餘大致積資源加載拖慢load事件,因此大文件最好用lazyload。MDN提供了一個屬性能夠判斷字體加載,可是目前兼容性還有一些問題,這裏就先不用了,感興趣的能夠看一下這裏。小弟才疏學淺,若有大神知道其餘監聽字體文件加載的方法,還請留言告知,謝謝~
函數
而後就是要作些什麼讓字體文件一開始就去加載了,要知道不一樣瀏覽器何時會去加載一個字體,能夠參考這篇文章。
在HTML中建立一個文本標籤,讓它去用這個須要被加載的字體,而且讓這個文本不要出如今視窗中:
<h1 class="Lanting_light" style="position: fixed;left:calc(-1000% - 5000px)">字體</h1>
最後擦個屁股,load完成後把上述已經被榨乾剩餘價值的節點刪掉:
window.addEventListener("load",function(){ let dev = document.getElementsByClassName("Lanting_light"); for (let i = 0; i < dev.length; i++){ dev[i].parentElement.removeChild(dev[i]); } //必須先刪除舊節點後再修改須要改的節點,不然文本節點會被刪掉 onLoadedFont(); });
到這裏,整個功能就完成了。
總結一下,這個方案可讓字體文件沒有加載完的時候,先用一個接近的安全字體讓文本先顯示出來,待字體加載完後再換字體,核心的點是監聽字體文件的加載,由於MDN上提供的document.font是一個實驗性功能,兼容性不是很好,因此這裏用了投機取巧的辦法去監聽window.load,可能會被其餘大文件阻塞,也會拖慢監聽window.load的其餘函數,因此在項目中仍是要取捨,沒有完美的方案,只有最合適的方案。