web 頁面內容優化管理與效能技巧
回想一下,以前我們不得不花費大量時間去優化頁面內容(圖片、CSS等等),如今使用者有更快速的網際網路連結,我們似乎能夠使用更大的影象或更大的快閃記憶體檔案,裡面包含的有視訊或者圖片。然而,隨著移動開發的興起,我們又回到了過去的窘狀。網站優化是十分重要的,需要下載的內容少,反應速度快,就能使我們載入應用程式更快速。
圖片:控制在合適的尺寸大小
很多時候我們在不同的網站使用同樣的影象,例如一個網上商店,所有產品 都 有一個概覽圖片。打個比方,有三個頁面描述產品,第一個頁面顯示產品清單,第二個頁面顯示產品細節圖,第三個頁面顯示產品原始大小圖。因此,我們需要三種 不同大小的圖片。如果使用一個檔案放到不同的三個頁面上,那麼瀏覽器會自動載入完整大小的圖片,就連清單頁也是,實際上清單頁只需要200×200尺寸的 圖片。如果原始檔案大小在1MB左右,每頁上有十個產品介紹,那麼使用者就要下載10MB大小的資源。這樣做效果不好。如果可以的話,儘量為你的網站不同位 置分配不同的影象檔案,那麼就可以讓使用者少下載資源。把螢幕解析度因素也考慮進去也是很好的。如果有人用iPhone開啟你的網站頁面,手機上不需要顯示 電腦上那麼大尺寸的圖片,只需適應手機螢幕的大小就可以了。通過CSS Media Queries,你就能將影象壓縮到較小尺寸傳送出去了:
@media only screen and (min-device-width : 320px) and (max-device-width : 480px) { .header { background-image: url(../images/background_400x200.jpg); } }
壓縮
傳送影象的時候單單控制適當的尺寸往往是不夠的。不少檔案格式在不失真的前提下可以被壓縮很多。有一類應用程式可以達到這個效果。比如Photoshop有個很好的功能叫做Save for Web and Devices:
在此對話方塊中有多個選項,其中最重要的是質量,將其設計為80%左右,就能顯著減少檔案大小了。當然,你還可以使用程式碼來壓縮檔案,但我個人偏向於使用PS。下面是用PHP編寫的一個簡單的例子:
function compressImage($source, $destination, $quality) { $info = getimagesize($source); switch($info['mime']) { case "image/jpeg": $image = imagecreatefromjpeg($source); imagejpeg($image, $destination, $quality); break; case "image/gif": $image = imagecreatefromgif($source); imagegif($image, $destination, $quality); break; case "image/png": $image = imagecreatefrompng($source); imagepng($image, $destination, $quality); break; } } compressImage('source.png', 'destination.png', 85);
Sprite
增加應用程式效能的方法之一,是減少到伺服器的請求數。每一個新影象代表一個請求數。有一個辦法是將幾個圖片合併成一個,合併之後的影象叫做一個sprite,在CSS中改變背景層的位置,就能準確的把特定部分的影象顯示出來。比如Twitter Bootstrap利用sprites引導內部圖示:
在CSS中,你可以參照以下方式,顯示你喜歡的sprite部分:
.icon-edit { background-image: url("../img/glyphicons-halflings-white.png"); background-position: -96px -72px; }
超快取記憶體
瀏覽器超快取記憶體十分好用。儘管有時在開發過程中會導致一些非常有趣的情況,但它確實有助於提高你的網站的效能。所有瀏覽器的超快取記憶體下來的內容包括圖片、JavaScript或者CSS。有幾種方法可以控制快取,建議你閱讀相關文章。一般情況下,你可以通過設定標題,達到控制效果:
$expire = 60 * 60 * 24 * 1;// seconds, minutes, hours, days header('Cache-Control: maxage='.$expire); header('Expires: '.gmdate('D, d M Y H:i:s', time() + $expire).' GMT'); header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
預讀取
HTML 5每天都在進步,有一個很好的功能叫做預讀取,它讓瀏覽器提前下載你馬上需要用到的資源:
<link rel="prefetch" href="/images/background.jpg">
資料URI方案/內聯影象
幾年前我曾開發了一個簡單的網頁,只包含一個HTML資料夾,但當然裡面應該還包括一些我需要的影象。資料URI方案幫助我解決了問題。我們的想法是將影象轉換成一個base64編碼的字串,並將其放置在src屬性中的img標籤裡,例如:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot">
通過這種方法,你的影象實際上在HTML中並儲存了一個HTTP請求。你的影象越大的話,字串就越長。下面是一個簡單的PHP指令碼影象轉換為base64字串的例項:
$picture = fread($fp,filesize($file)); fclose($fp); // base64 encode the binary data, then break it // into chunks according to RFC 2045 semantics $base64 = base64_encode($picture); $tag = '<img src="data:image/jpg;base64,'.$base64.'" alt="" />'; $css = 'url(data:image/jpg;base64,'.str_replace("\n", "", $base64).'); ';
有些情況下這種方法挺好用的,但請注意,在IE瀏覽器中無法很好的相容。
CSS
我覺得編寫CSS就如同寫程式碼。你同樣需要組織模式,定義不同板塊和關係。所以我認為CSS管理非常重要。應用程式的每一部分應該有對應的模式,並很好的獨 立。不同的內容儲存在不同的資料夾可以有效的管理,但同樣也存在問題。使用@import狀態這種方法不好用,因為每用一個@import都意味著一個新 的請求傳送到伺服器。如果你有20個不同的.css檔案,就相當於瀏覽器要傳送20個請求。瀏覽器在渲染/下載所有內容之前不會顯示頁面。如果你 的.css檔案丟失了或者太大,瀏覽器載入頁面的時間就會大大延長。
使用CSS前處理器
CSS前處理器可以解決上述問題。你 同樣可以儲存不同的資料夾,前處理器可以將這些散資料夾最終生成一個.css檔案。實際上提供了一系列非常幫的功能比如變數、巢狀塊、混入和繼承。程式碼看 上去類似CSS,但實際上被很好的統一格式與結構了。有幾種好用的前處理器值得體驗——Sass、LESS、Stylus。下面是用LESS編寫的例子:
.position(@top: 0, @left: 0) { position: absolute; top: @top; left: @left; text-align: left; font-size: 24px; } .header { .position(20px, 30px); .tips { .position(10px, -20px); } .logo { .position(10px, 20px); } }
執行生成:
.header { position: absolute; top: 20px; left: 30px; text-align: left; font-size: 24px; } .header .tips { position: absolute; top: 10px; left: -20px; text-align: left; font-size: 24px; } .header .logo { position: absolute; top: 10px; left: 20px; text-align: left; font-size: 24px; }
又如你想再建立一個同樣樣式的按鈕,但是顏色不同,你可以這樣做:
.button { border: solid 1px #000; padding: 10px; background: #9f0; color: #0029FF; } .active-button { .button(); color: #FFF; }
高效的CSS
通常情況下,大多數開發人員沒有考慮過CSS效率問題。CSS的效率反映在頁面渲染上,如果模式低效,應用程式在瀏覽器上執行就會很慢。有趣的是瀏覽器解析CSS選擇器是從右到左的。所以以下程式碼更不一點效率都沒有:
body ul li a { color: #F000; text-decoration: none; }
這是因為該引擎首先識別所有的<a>標籤,評估每個母元素,最終收集到所需模式。你要知道,為了提高效率,選擇器有個 先後排序:ID、類、標籤及其一般。這意味著一個帶有id的元素集比只帶有標籤選擇器的元素更快的被渲染。當然,在所有DOM樹元素都加上id是沒有意義 的,但你應該特定檢查程式碼,把可能加id的地方都加上。比如你可以按照以下方式做:
ul #navigation li { background: #ff0232; }
.content元素是body tag的子集,實際上所有元素都是body tag的子集。關於這個話題有兩個有用的連結:developers.google.com和css-tricks.com。
檔案大小
正如我們上面提到的,程式碼越少越好,因為瀏覽器在載入CSS之前不渲染頁面。下面幾個技巧可供縮小檔案大小:
把類似的行
.header { font-size: 24px; } .content { font-size: 24px; }
轉換成
.header, .content { font-size: 24px; }
用速記,而不是以下
.header { background-color: #999999; background-image: url(../images/header.jpg); background-position: top right; }
用下面的風格編寫
.header { background: #999 url(../images/header.jpg) top right; }
縮減程式碼,也就是使用一個工具除去所有空間和線,可以使用CSSOptimiser或Minifycss。常見做法是在應用程式伺服器端使用這種工具。也就是在後端寫的語言。通常情況相愛這些元件可以縮減你的程式碼。
將你的CSS檔案放在<head>標籤下
將你的CSS檔案放在head標籤下是很好的方法,瀏覽器會首先下載它們。
JavaScript
減少HTTP請求數量
與CSS情況一樣,減少伺服器請求是有利的。大多數情況下,載入JavaScript檔案的同時不會停止渲染頁面,但會造成頁面某些部分失去作用。
縮減程式碼
有些小工具可以縮減JavaScript,使檔案大小減小了,但要記住在開發環境中,保持程式碼整潔是十分必要的。這些工具幾乎都會改變變數名稱,並轉換成一個單行的字串,這個過程不可能除錯。
JavaScript本身並沒有一個機制來管理模數,因此,這些工具是為了解決這個問題的。他們提供一個應用程式介面,你可以定義和使用模數。例如http://requirejs.org/:
<!DOCTYPE html> <html> <head> <title>My Sample Project</title> <!-- data-main attribute tells require.js to load scripts/main.js after require.js loads. --> <script data-main="scripts/main" src="scripts/require.js"></script> </head> <body> <h1>My Sample Project</h1> </body> </html>
執行指令碼,你可以用require()代替main.js
require(["helper/util"], function(util) { //This function is called when scripts/helper/util.js is loaded. //If util.js calls define(), then this function is not fired until //util's dependencies have loaded, and the util argument will hold //the module value for "helper/util". });
使用名字空間
提到程式碼組織,必然要提到名稱空間的部分。原本在JavaScript中是沒有這個功能的,但你可以通過幾行程式碼來實現這個功能。比如,你想達一個MVC框架,就可以用以下方式:
var model = function() { ... }; var view = function() { ... }; var controller = function() { ... };
光有以上程式碼是不夠的,很容易與其他行的程式碼發生衝突。所以需要按照以下方式將它們作為獨立的物件(名稱空間)分組,以保護整體框架:
var MyAwesomeFramework = { model: function() { ... }, view: function() { ... }, controller: function() { ... } }
遵循設計模式
JavasScript之所以很受歡迎是因為裡面包含了大量例子。可重複使用的設計模式是程式設計中常見問題的解決方案。遵循某些設計模式可以幫助你更好的設計應用程式。如果我全都寫下來,估計都可以出書了,所以這裡只寫出一些例子:
建構函式模式
用這個模式構建具體物件例項:
var Class = function(param1, param2) { this.var1 = param1; this.var2 = param2; } Class.prototype = { method:function() { alert(this.var1 + "/" + this.var2); } };
或者:
function Class(param1, param2) { this.var1 = param1; this.var2 = param2; this.method = function() { alert(param1 + "/" + param2); }; }; var instance = new Class("value1", "value2");
模組模式
模組模式可以讓我們建立私有和公共方法。比如下面的程式碼中,變數_index和方法privateMethod是私有的,increment和getIndex是公開的。
var Module = (function() { var _index = 0; var privateMethod = function() { return _index * 10; } return { increment: function() { _index += 1; }, getIndex: function() { return _index; } }; })();
觀察者模式
事件的訂閱和分派發生的時候就能看到這種模式。觀察者對特定物件相關的東西有興趣,一旦發生動作,就會通知觀察者。下面的例子顯示我們如何才能增加使用者物件的觀察者:
var Users = { list: [], listeners: {}, add: function(name) { this.list.push({name: name}); this.dispatch("user-added"); }, on: function(eventName, listener) { if(!this.listeners[eventName]) this.listeners[eventName] = []; this.listeners[eventName].push(listener); }, dispatch: function(eventName) { if(this.listeners[eventName]) { for(var i=0; i<this.listeners[eventName].length; i++) { this.listeners[eventName][i](this); } } }, numOfAddedUsers: function() { return this.list.length; } } Users.on("user-added", function() { alert(Users.numOfAddedUsers()); }); Users.add("Krasimir"); Users.add("Tsonev");
函式連結模式
這種模式可以很好的組織模組的公共介面。節省時間,提高可讀性:
var User = { profile: {}, name: function(value) { this.profile.name = value; return this; }, job: function(value) { this.profile.job = value; return this; }, getProfile: function() { return this.profile; } }; var profile = User.name("Krasimir Tsonev").job("web developer").getProfile(); console.log(profile);
我強烈推薦Addy Osmani出的書,它涵蓋了JavaScript中設計模式所有最棒的資源。
Assets-Pack
在本文結尾的時候,我想分享一些關於伺服器上CSS和JavaScript程式碼管理方面的想法。這是一個常用手段來新增合併、縮小、編譯成應用程式的邏輯。 時常有種快取機制,但在程式執行的時候所有事情都在同時發生。就是說你或許有程式碼的邏輯,同時處理.js或.css檔案請求,然後提供適當的內容。這個過 程的背後是彙編、壓縮,以及其他。在我最新一個專案中我用到一種叫做Assets-Pack的工具。它非常有用,我可以詳盡解釋它能做什麼,但更有趣的是 我是怎樣使用這個工具的。只能用在開發模式中,不是停留在基於程式碼形式的,也不是在伺服器上調配的。
我的想法是運用這個工具只當你在處理 CSS和JS的時候,它可以監視特定目錄中的變化,然後把程式碼編譯/打包成為一個單一的檔案。通過這個步驟,你不需要再去考慮壓縮或者彙編。所有你所要做 的僅僅是將編譯後的靜態檔案傳送給使用者。這增加了應用程式的效能,因為它只能提供靜態檔案,這當然讓事情變得更簡單。你不需要設定任何伺服器或實施不必要 的邏輯。
下面是你如何安裝和使用Assets-Pack:
npm install -g assetspack
用法
該模組可與JSON配置,當它通過命令列被呼叫的時候,你應該把設定放到.json檔案中。
通過命令列
建立assets.json資料夾,在同一個目錄下執行以下程式碼:
assetspack
如果你想使用另一種名稱或者換一個目錄:
assetspack --config [path to json file]
程式碼形式的
var AssetsPack = require("assetspack"); var config = [ { type: "css", watch: ["css/src"], output: "tests/packed/styles.css", minify: true, exclude: ["custom.css"] } ]; var pack = new AssetsPack(config, function() { console.log("AssetsPack is watching"); }); pack.onPack(function() { console.log("AssetsPack did the job"); });
配置
配置應該是一個有效的JSON檔案/物件,下面只是一個物件陣列:
[ (asset object), (asset object), (asset object), ... ]
Asset Object
Asset Object的基本結構如下:
{ type: (file type /string, could be css, js or less for example), watch: (directory or directories for watching /string or array of strings/), pack: (directory or directories for packing /string or array of strings/. ), output: (path to output file /string/), minify: /boolean/, exclude: (array of file names) }
pack屬性不是強制的,如果丟失了,它的值還是相等的,預設情況下的縮減是假屬性。
下面是一些例子:
Packing CSS
{ type: "css", watch: ["tests/data/css", "tests/data/css2"], pack: ["tests/data/css", "tests/data/css2"], output: "tests/packed/styles.css", minify: true, exclude: ["header.css"] }
Packing JavaScript
{ type: "js", watch: "tests/data/js", pack: ["tests/data/js"], output: "tests/packed/scripts.js", minify: true, exclude: ["A.js"] }
Packing .less Files
Packing .less Files有點不同,pack屬性是強制性的,基於你的切入點。你應當匯入所有其他的.less檔案。排除屬性在這裡無效。
{ type: "less", watch: ["tests/data/less"], pack: "tests/data/less/index.less", output: "tests/packed/styles-less.css", minify: true }
如果有其他問題,可以在原始碼(GitHub)庫中檢視tests/packing-less.spec.js
壓縮其他格式檔案
assets-pack適用於所有檔案格式。比如你可以結合HTML模板和一個簡單檔案,用以下方式:
{ type: "html", watch: ["tests/data/tpl"], output: "tests/packed/template.html", exclude: ["admin.html"] }
有一點需要注意的是這裡沒有縮小倍率。
結論
作為前端Web開發人員,我們應該儘量為的使用者提供最佳的效能。上面的提示不應該涵蓋所有資產的組織和效能方面的技巧,但它們是常用的幾種。
英文來源:web-assets-tips-for-better-organization-and-performance
相關文章
- Web 頁面優化專項 > Lighthouse > 效能分數優化Web優化
- iOS 頁面效能優化iOS優化
- web效能常見優化技巧Web優化
- 瀏覽器層合成與頁面效能優化瀏覽器優化
- Web效能優化系列(2):剖析頁面繪製時間Web優化
- 百度運維部一面之web頁面效能優化運維Web優化
- 效能優化的主要內容列表優化
- 瀏覽器的載入與頁面效能優化瀏覽器優化
- 前端優化:9 個技巧,提高 Web 效能前端優化Web
- 前端優化 9 個技巧,提高 Web 效能前端優化Web
- Web前端效能優化_CDN(內容釋出網路)、CDN工作原理Web前端優化
- 頁面載入效能之優化LCP優化
- 頁面效能優化辦法有哪些?優化
- iOS進階之頁面效能優化iOS優化
- Web效能優化系列:10個JavaScript效能提升的技巧Web優化JavaScript
- web頁面效能測試Web
- iOS效能優化之頁面載入速率iOS優化
- 頁面間跳轉的效能優化(一)優化
- QQ音樂Android客戶端Web頁面通用效能優化實踐Android客戶端Web優化
- 【JS實用技巧】利用冒泡機制,減少事件繫結,優化頁面效能JS事件優化
- 【效能優化實踐】優化打包策略提升頁面載入速度優化
- js效能優化相關內容筆記整理JS優化筆記
- web效能優化Web優化
- 高頻 dom 操作和頁面效能優化探索優化
- SQL效能優化技巧SQL優化
- MySQL 效能優化技巧MySql優化
- jQuery 效能優化技巧jQuery優化
- PHP效能優化技巧PHP優化
- 微信php分享頁面自定義標題與內容PHP
- 42個移動端啟動頁面優化技巧優化
- Web效能優化系列(1):Web效能優化分析Web優化
- Web開發者必知的25個Apache效能優化技巧WebApache優化
- 無線效能優化:頁面可見時間與非同步載入優化非同步
- web簡單頁面佈局fixed 頭部固定 內容滾動Web
- 有關web頁面內容檔案強制下載程式碼Web
- 開發者分享優化技巧,將PC VR內容移植到Quest優化VR
- Web效能優化:圖片優化Web優化
- 使用 Chrome Timeline 來優化頁面效能Chrome優化