---恢復內容開始---javascript
這篇文章很長,但的確是一篇很是乾的乾貨,講訴了 HTML、JavaScript、CSS、jQuery使用的一些規範與建議,前端的同窗能夠認真閱讀此文,並比較本身平時的一些習慣,看是否有改進的地方……css
不定義DOCTYPE是一種能夠被判死刑的罪行。 之前你可能用的是下面的DOCTYPE,不過你要知道如今已經有更簡潔清晰的代碼取而代之了。html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
理想的情況是用HTML5 DOCTYPE,全部現代的瀏覽器都支持它,即便是不支持HTML5的瀏覽器,例如IE6,IE7,也會由此轉入標準模式。 參見來源。前端
<!DOCTYPE html>
用整潔、語義清晰的HTML編寫網站代碼是咱們一直孜孜以求的。有時咱們會發現前人配置頁面的方式限制了咱們,或者有時咱們編寫的是HTML格式的email模板。但永遠不要偏離HTML的規範,即便是爲了解決特定瀏覽器兼容性的bug。全部的標題應該從<h2>
開始分層級建立,文字段落應該老是放在<p>
標籤裏,諸如此類。若是你編寫的HTML的語義清晰,產生的頁面會更整潔、簡練,並且易於被搜索引擎爬蟲解析。這是你能作到的最簡單的SEO修補方式。來看看下面的段落,你以爲哪一個更整潔?是這個?html5
<span class="sectionHeading">A Heading</span> <br /> <br /> Lorem ipsum dolor sit amet. ... <br /> <br />
仍是這個?java
<h2>A Heading</h2> <p> Lorem ipsum dolor sit amet. ... </p>
現代web應用最使人鬱悶的可用性缺陷之一是超連接功能的變種。 一些看起來像是超連接的元素多是經過Javascript映射的單擊功能,這就破壞了鼠標中鍵點擊(在新的tab中打開連接頁面)的功能。即便它們能在新的標籤頁打開,它們只帶有一個 # 的href又會把你帶回到一樣的頁面。深入詮釋了該問題的一個現代熱門網站的例子就是Twitter。在它的整個應用裏,鼠標中鍵點擊用戶名或頭像會獲得徹底不一樣的結果。jquery
<!-- 舊的方式,破壞網頁語義 --> <a href="#"></a> <!-- 若是鼠標點擊不能產生一個頁面,那就不是超連接 --> <span class="link" role="link"></span>
另外一個替代方案是使用 # 引導的路徑,它會把普通的url映射爲 # 引導的連接,而後經過AJAX來獲取頁面片斷。提供此功能的庫應該可以在鼠標中鍵點擊的時候正常顯示頁面,或者在左鍵點擊時把該頁面內容加載到指定的區域。不過這樣也要慎重行事,有不少人都認爲 連接正在破壞web應用css3
Microformat是一種便於機器讀取聯繫人信息的方式。hCard類(不是vCard)用來定義元素裏包含的內容類型。這些內容會被瀏覽器提取並突出顯示。git
<span class="tel"> <span class="type">home</span>: <span class="value">+1.415.555.1212</span> </span>
若是你曾經瀏覽採用此格式的網頁,你會注意到相似skype的程序能夠輕鬆檢測到網頁上的哪些數字是電話號碼。在iOS設備上的Safari瀏覽器也能夠作到相似的事情。程序員
有關Microformat的更多信息請參閱http://microformats.org/wiki/hcard
<img>
標籤須要 alt 文本,以便檢查並知足可讀性的要求。 在 alt 屬性中的文本必須可以說明圖片顯示的內容或要達到的效果,除非該圖片不重要。
若是圖片只是一個列表中的着重號或者其餘可有可無的圖標,最好是給 alt 屬性一個空字符串,但仍是留着它。這樣屏幕閱讀器會忽略它,而不是把"着重號"連讀20次。
<img src="dog.gif" alt="Fido and I at the park!" /> <!-- 很好,描述清晰 --> <img src="bullet.gif" alt="bullet" /> <!-- 很差,顯得多餘 --> <img src="bullet.gif" alt="" /> <!-- 好 -->
table標籤永遠只應該用在表格數據的展現上。惟一的例外是當編寫HTML格式的郵件時,這種狀況下可能table是某些坑爹的郵件客戶端惟一支持的樣式了。
爲了可讀性,表格頭永遠要使用 <th>
元素。同時切記要設置cellpadding, cellspacing 和 border 的值爲 0 , 由於這些樣式由CSS來控制更容易確保一致性。
<table cellpadding="0" cellspacing="0" border="0"> <thead> <tr> <th> Cell Header </th> </tr> </thead> <tbody> <tr> <td> Cell Item </td> </tr> </tbody> </table>
jQuery 和 jQuery UI 被作成儘量在不一樣瀏覽器上表現出幾乎相同的外觀和功能。 jQuery UI 被設計爲符合 WAI WCAG 2.0 及 WAI ARIA, 所以採用該框架能夠避免在你的站點上運行的插件或腳本的全部不肯定性。
任何關於代碼格式、留空和大括號位置的討論都會引發激烈辯論。對此,我想最簡單的規則就是,除非你願意把整個代碼文件從新格式化,否則仍是尊重並保持已有代碼文件的格式。這意味着若是你看到一個JS文件裏的大括號沒有換行寫,那你的代碼也要繼續保持大括號不換行。若是你的代碼沒有和代碼文件裏的其餘部分保持一致,那麼你的代碼就不該該經過代碼審查流程。
一致的代碼格式讓代碼更加易讀,同時也意味着代碼容易用查找/替換命令進行修改。謝天謝地,咱們本身造成的編程習慣和jQuery正式推薦的方式很是類似。細微的差別也是有的,不過,那些是我的問題或者咱們以爲無法維護的一些東西。 參閱jQuery核心樣式指南
字符間距
// 很差 if(blah==="foo"){ foo("bar"); } // 好 :) if (blah === "foo") { foo("bar"); }
大括號不換行
// 很差 if (foo) { bar(); } // 好 :) if (foo) { bar(); }
老是用大括號
// 很差 if (foo) bar(); // 好 :) if (foo) { bar(); }
字符串處理
引用字符串永遠要用雙引號。 有些人很是喜歡用C語言風格的字符串(單引號),但這種習慣會致使腳本內部的風格衝突。C語言風格的字符串處理要求空字符串和單字符包在單引號裏,而短語和單詞必須包在雙引號內。
往代碼裏玩命加註釋的需求是由各類經理、主管及其餘不多接觸代碼的人們引領的。這種需求無非是僱員們考覈指標中的一個勾選欄,花在這上面的時間基本沒有帶來什麼回報。 若是那些從善如流的開發者能遵循本文檔中提出的建議,他們的代碼會變得至關易於閱讀,一目瞭然,以致於再用註釋描述這些代碼會多餘得使人尷尬。來看下面的例子。在這裏,布爾變量被做爲問題提出,而函數也有直觀的命名。
if (user.hasPermission) { editPage(); }
至少在這個場景中,註釋是徹底沒有必要的。
一個項目裏,永遠會有某些部分難以查閱和理解。好比一個複雜的正則表達式,或者一個對角度進行計算或在度和弧度單位之間切換的數學函數。沒有上面的註釋,初級或中級的讀者將對腳本的含義毫無頭緒。
// 校驗美國電話號碼的正則表達式,號碼格式是 (XXX) XXX-XXXX (減號、空格和括號都是可選的,能夠有也能夠沒有) var phoneRegEx = /^\(?(\d{3})\)?[- ]?(\d{3})[- ]?(\d{4})$/;
使用 == 比較符可讓使人鬱悶的bug消失於無形。它容許在 JavaScript花園 中有清楚解釋的弱類型。使用嚴格的 === 比較符不會執行類型強制轉換,從而可以嚴格地評估兩個對象之間的差異。再說一遍,更多詳細信息請參見 JavaScript花園。
var zeroAsAString = "0"; if (zeroAsAString == 0) { // 這樣也能判斷爲true,呵呵... } if (zeroAsAString === 0) { // 判斷爲false }
例外
在和null進行比較的時候,容許使用 == 比較符,由於它會檢測null和undefined兩個屬性。若是你不徹底理解這個原理,那我仍是建議你用 === 比較符爲好。
var foo = null; // foo 是 null, 但 bar 是 undefined ,由於它還沒有被聲明 if (foo == null && bar == null) { // 上面的判斷仍是成立的 }
把字符串解析爲整數的時候,有個好習慣是指定第二個基數參數 -- 它會肯定該字符串被轉換成幾進制。當字符串以 0 開頭的時候,缺省狀況下會觸發 16 進製做爲基數。大部分初級和中級用戶只會用到 10 這個基數。 感謝 João Moreno 記錄的這個 勘誤。
alert( parseInt("08") ); // alerts: 2 alert( parseInt("08", 10) ); // alerts: 8
直接比較 true 和 false 的值是沒有必要的。有時候也許明確一下有好處,但它仍是額外的代碼。
if (foo === true) { // 用了 === 卻是不錯,可這是多餘的 } if (foo) { // 贊! } if (!bar) { // 反過來也贊 }
過度依賴全局變量是咱們組全部人 -- 特別是我本身 -- 特別有負罪感的一件事。關於爲啥全局變量很差的討論是至關直接的:這增長了腳本和變量衝突的機率,並且源文件和命名空間自己都會充斥着數不清的命名模糊的變量。
Douglas Crockford 堅信一個Javascript應用的代碼質量能夠用其中使用的全局變量數來評價,越少越好。因爲並非什麼均可以定義成local的(不過要誠實,其實你如今考慮的那個是能夠的,別偷懶),你須要想辦法整理你的變量以免衝突,並把命名空間的膨脹減到最小。最簡單的方法就是採用單變量或者把用到這些全局變量的模塊儘量減小。 Crockford提到YUI只用了一個全局變量,YAHOO。他在他的博文 "全局統治" 中討論了更多的細節問題。
考慮這種狀況:對於小型web應用,全局變量一般用於保存應用級的設置,能夠用你的項目名或者settings做爲命名去定義一個對象,這樣總的來講會更好。
// 被污染的全局命名空間 var settingA = true; var settingB = false; var settingC = "test"; // 用 settings 做爲對象命名 var settings = { settingA: true, settingB: false, settingC: "test" }
不過,若是咱們能夠經過避免使用全局變量來減小衝突機率,可是把命名空間標準化成同樣的,豈不是會增長各個應用之間產生衝突的機率麼?呃,這個擔心確實有道理。因此,建議你用本身特定的應用名做爲全局變量的命名空間,或者用和jQuery採起的 $.noConflict() 模式相同的方法從新分配你的命名空間.
JavaScript變量的駝峯法命名在大部分編程環境中都是做爲標準的。有讀者在評論中提出了惟一的例外,就是要用大寫字母加下劃線來指代常量。
var X_Position = obj.scrollLeft; var xPosition = obj.scrollLeft; // 更好,更簡潔 SCENE_GRAVITY = 1; // 常量
循環估計是Javascript性能調優最重要的部分了。在一個循環內部節省個一兩毫秒的,說不定整體就省出好幾秒來了。這裏有一招就是把數組的長度緩存,這樣在循環裏就無需每次迭代的時候都計算一遍了。
var toLoop = new Array(1000); for (var i = 0; i < toLoop.length; i++) { // 敗家玩意 - 長度會反覆算 1000 次你知道不? } for (var i = 0, len = toLoop.length; i < len; i++) { // 會過日子 - 長度只計算一次,而後緩存了 }
例外
若是你對一個數組作循環來查找並刪除某個元素,這就會改變數組長度。任什麼時候候你只要會在循環內部增長或刪除元素來改變數組的長度,你就給本身帶來了麻煩。這種狀況下,你要麼每次改變後從新設置數組長度,要麼就別緩存它了。
跳過和跳出循環的能力對於避免開銷很大的循環週期是很是有用的。
若是你是在循環內部查找,查找成功之後你會作什麼?好比1000個元素的循環執行到一半,你就找到了你要的東西。你無論三七二十一,即便知道後面的if語句不會再有符合的機會,仍是讓循環繼續把剩下的500個元素迭代完麼?不!你應該跳出循環,必須的!
var bigArray = new Array(1000); for (var i = 0, len = bigArray.length; i < len; i++) { if (i === 500) { break; } console.log(i); // 這樣只會輸出 0 - 499 }
另外一個問題是跳過某個特定的迭代,而後繼續循環。雖說相似於奇偶數這樣的條件能夠經過把 i++ 替換成 i + 2 的辦法來管理,有些條件仍是須要具體檢測,而後觸發跳過操做。任何可以避免執行完整的迭代過程的東西都是頗有用的。
var bigArray = new Array(1000); for (var i = 0, len = bigArray.length; i < len; i++) { if (condition) { continue; } doCostlyStuff(); }
對於可讀性而不是其餘因素來講,下面這種方式真是糟透了:
function greet(name, language, age, gender, hairColour, eyeColour) { alert(name); }
面的例子預先構建了一個對象做爲參數,或者把內聯對象傳遞過去,這樣就好多了。
function greet(user) { alert(user.name); } greet({ name: "Bob", gender: "male" });
在編寫面向對象(OO)Javascript代碼的時候, 必須瞭解 this 的做用範圍. 無論你用來構建僞類的設計模式是什麼,對 this 的引用是指向一個實例的最簡單辦法。當你開始把jQuery的helper方法和你的僞類集成的時候,你就會注意到 this 的做用範圍變化。
Bob.findFriend("Barry"); Person.prototype.findFriend = function(toFind) { // this = Bob $(this.friends).each(function() { // this = Bob.friends[i] if (this.name === toFind) { // this = Barry return this; } }); }
在上面的例子裏, this 經歷了從對 Bob 的引用,變成對他的朋友 Barry 的引用的過程。 瞭解 this 的取值在一段時間發生的變化是很重要的。在原型函數內部, this 指向所在僞類的當前實例(這裏是 Bob )。而一旦咱們進入 $.each() 循環, this 就會從新映射爲被解析數組的第 i 個元素。
解決辦法是把 this 的值從新映射爲 self 或者 _self。雖然 self (不帶下劃線)並非 保留字, 但它 確實是 window 對象的一個屬性。雖然我上面用到 self 的例子是從jQuery源代碼中挑的,但他們也認識到了這個錯誤,正打算 修正目前的情況 ,也就是改用 **_self。我我的仍是喜歡用 self** ,不爲別的,就由於它的簡潔 -- 不過它可能會冒出一些很是使人困惑的bug。總之,用 self 有風險,使用需謹慎。
在下面的例子中,我會更好地利用在 $.each() helper 中提供的參數,同時從新映射 this 的值。
Bob.findFriend("Barry"); Person.prototype.findFriend = function(toFind) { // 就這一次用到了 "this" var _self = this; $(_self.friends).each(function(i,item) { if (item.name === toFind) { return item; } }); }
布爾變量必須可以很容易經過命名來識別。能夠用相似於 is, can 或者 has 的前綴來造成一個問句。
isEditing = true; obj.canEdit = true; user.hasPermission = true;
從新繪製和從新佈局與從新渲染DOM的過程關聯,這個過程會在特定屬性或元素被改變時發生。從新繪製是在某個元素的外觀被改變但沒有對佈局進行調整的狀況下觸發的。 Nicole Sullivan 在一篇全面的 博文 中把這些改變描述爲諸如是否可見或背景色變化之類的樣式改變。從新佈局則是開銷更大的操做,由調整頁面佈局的一些改變引起。例如增長或刪除元素,改變某個元素的寬度或高度,甚至是改變瀏覽器窗口的大小。最糟糕的狀況是從新佈局致使先輩、兄弟和孩子節點元素也須要從新佈局的多米諾骨牌效應。
毫無疑問,從新繪製和從新佈局應該儘可能避免,可是如何作到呢?
其實也不是說下面的代碼就很糟糕啦。不過咱們先假定數組 arr 有10個元素
var myList = document.getElementById("myList"); for (var i = 0, len = arr.length; i < len; i++) { myList.innerHTML += "<li>" + arr[i].title + "</li>"; //從新佈局 -- 增長到元素 }
在上面的 for 循環裏,每次迭代會觸發一次從新佈局。10次迭代就是10次從新佈局。
如今考慮下面的代碼:
var constructedHTML = ""; for (var i = 0, len = arr.length; i < len; i++) { constructedHTML += "<li>" + arr[i].title + "</li>"; //沒有從新佈局 - 增長到字符串 } document.getElementById("myList").innerHTML = constructedHTML; //在這裏從新佈局
在這個場景裏,須要增長的元素是在一個字符串裏構建的。循環裏邊沒有產生任何從新佈局,由於DOM並無變化。只有當數組被徹底循環完畢,構建的字符串被應用到某個對象的 innerHTML ,這才產生函數裏惟一的一次從新佈局。
有無數種從新佈局和從新繪製是能夠避免的,但願你幸運地瞭解了那些訣竅。這方面的閱讀材料汗牛充棟,不過大部分的材料都會引用到 Nicole Sullivan的這篇 博文 ,這是一個完美的起點。除了這裏的經驗,在涉及到"web 3.0"和HTML5時代的多種技術術語的時候,還有其餘重要的經驗教訓值得汲取。上面的分析直接適用於寫jQuery代碼。在搗騰 canvas 的時候這些原則也很重要,另外儘可能保持幀頻在30-60的範圍內。
自打web開發早期開始,就流行一種產生惟一ID的方法。具體作法是把從1970年1月1日開始計算的微秒數加到你的靜態ID後面,以下所示:
var myID = "static" + new Date().getTime();
這原本是至關萬無一失的方法,由於即使兩段這樣的代碼連續執行,在它們執行的間隙也會有幾毫秒。但是如今新的瀏覽器帶着新的Javascript引擎,伴隨着一直在提高的主頻。到如今,上面的代碼產生相同的毫秒數的可能性會比產生間隙的可能性更大。
這會致使傳統方法難以debug的bug。由於你的DOM是在運行中建立的,對頁面源代碼進行傳統的測試沒法肯定多個重複ID的錯誤。Javascript和jQuery的錯誤處理機制會把第一個匹配的做爲ID並忽略其餘的重複ID。因此它甚至都不會拋出JS錯誤!
這樣不行,惟一真正的方法是逐行設斷點和log,可是若是斷點的位置不對,你的毫秒數又不會衝突了!
好消息是有不少產生惟一ID的替代方法。學究氣一點的說法是,計算機的隨機數函數其實並非真正隨機的,由於它仍是來源於系統時間,雖然這一點值得注意,可是隨機數衝突的可能性是微乎其微的。
var myID = "static" + Math.round(Math.random() * 10000);
我我的更偏心人工產生GUID方法。從技術角度說,GUID是根據你的硬件建立的,不過下面的Javascript函數作得至關棒。這是我從 stack overflow 的一個帖子 裏偷來的,至關順手的一個函數。
function S4() { return (((1+Math.random())*0x10000)|0).toString(16).substring(1); } function guid() { return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4()); }
var myID = "static" + guid();
用戶的瀏覽器是否支持地理信息?用戶的瀏覽器是否支持web works?HTML5 視頻?HTML5 音頻?答案曾經是這樣的:
if ($.browser.msie) { // 哦,是IE啊,那確定不支持 }
可是世界在快速變化。最新版的IE幾乎能算是現代瀏覽器了,但它依舊給前端開發帶來痛苦。更早版本的IE基本上和它以前的版本同樣爛,這就讓偷懶的Javascript程序員習慣於檢測 if (ie) 而後執行一些微軟專用的破語法。如今IE9已經廢棄了這些專用函數,那些原來的 if (ie) 老古董就反而會壞事了。
那麼,若是能檢測每一個特性而不用檢測(既不可靠又能假裝的)user-agent,你以爲咋樣?
若是你的回答是 "那至關靠譜", 那你就說對了。
用 Modernizr 吧,這是行業夢幻級大師Paul Irish參與開發的一個Javascript庫。該庫集普遍應用、輕量級和海量文檔三大優點於一身,實施無需動腦,實爲居家旅行、殺人滅口必備。它會產生一個 Modernizr 對象,其中包含了它全部檢測測試的結果,這樣檢測某個特性的支持與否就和下面的例子同樣簡單:
// 檢測瀏覽器是否支持canvas的老辦法 if (!!document.createElement('canvas').getContext) { ... } // 用 Modernizr 檢測 if (Modernizr.canvas) { ... }
毫秒數的一種方便的寫法是寫成可讀的。對於初學者這很棒,可是大部分狀況下其實只是一個噱頭。
// 這是3秒,30秒仍是300秒啊? var timeout = 30000; // 增長了額外的計算開銷,可是讀和修改會更容易 var timeout = 30 * 1000;
jQuery最好的特性之一就是它的函數串接。你可能已經用過一點,也許把一些簡單的調用一個接一個串起來...可是你是否曾經像頭瘋狗同樣在DOM裏上躥下跳地遍歷呢?仍是花點時間來熟悉一下 .end() 函數。等你從起始選擇器開始在DOM裏上躥下跳的時候,這個函數會很關鍵。
$(".quote") .hide() .find("a").text("Click here").bind("click",doStuff).end() .parent().removeClass().addClass("testimonial").draggable().end() .fadeIn("slow");
上例中,每次咱們完成對某個DOM對象的操做,要反向遍歷DOM返回咱們引用的原始對象的時候,就須要使用 .end() 函數。而後咱們就順藤摸瓜扎回原來DOM裏的位置了。
大家當中那些已經寫了很長時間Javascript(原生的,不是jQuery)代碼的同窗,極可能都熟悉各類屬性吧。大家想辦法設置它們,獲取它們,或者濫用 rel 和 title ...
別說HTML5 或者 jQuery 沒幫上忙哦。新的描述中容許在HTML元素中使用 data- 前綴來指明包含數據的屬性,jQuery會把指定的字符串轉換成正確的Javascript數據類型,這活幹的很是漂亮。咱們來建立一個帶有某些數據屬性的 DIV 。
<div id="test" data-is-bool="true" data-some-number="123"></div>
如今,即便咱們的值被包裝在引號裏面,它們也不會被當作字符串處理:
typeof $("#test").data("isBool"); // boolean typeof $("#test").data("someNumber"); // number
要注意,要讓這些代碼片斷正常工做,(HTML裏的屬性定義)必須使用小寫字母,這很重要。不過若是你是一位很強的前端開發者,你仍是會想用駝峯法來命名你的數據變量。正如在Javascript裏不少地方出現的,前置的鏈接符意味着下一個字母會適用於駝峯法大寫。不過,下面的例子裏在HTML屬性定義中使用駝峯法是 不行的 ,會讓上面的Javascript代碼返回 undefined。
很差使 :(
<div id="test" data-isBool="true" data-someNumber="123"></div>
好使 :)
<div id="test" data-is-bool="true" data-some-number="123"></div>
把jQuery動畫效果和鼠標事件綁定是基於web的現代用戶交互方式中的關鍵部分,但是這方面即使某些最有名的網站也作得很蹩腳。這篇文章 提供了一個實現動畫的直接例子而且演示了這些動畫放在一塊兒在視覺上會產生多麼不和諧的效果。 好在這個問題能夠利用一個函數前綴或在 $.animate 調用中加入一個參數來輕鬆解決。
在使用 $.animate 的時候, 能夠在參數中加入 queue: false 來避免串接。諸如 $.fadeIn 或 $.slideDown 這樣的動畫快捷方式不接受 queue 設置,你必須用 $.stop 這個方法預先中止這些動畫.。 在特定的場景下,須要某個動畫直接停下,或跳轉到變換的最終狀態。推薦你先熟悉有關 clearQueue 和 jumpToEnd 這兩個參數的相關 文檔 ,由於老天在上,我沒有其餘辦法幫你。
$("selector").stop(true,true).fadeOut(); $("selector").animate({ property: value }, { duration: 1000, queue: false }
jQuery 很高冷。它幾乎無所不能,不過它目前還無法給你衝咖啡,我據說在2.0版的路線圖裏有才這個特性。你須要小心的一件事是別濫用它的 sizzleJS 選擇器引擎的能力。想避免這種問題能夠有兩個策略:緩存選擇器結果 以及 使用高效率的選擇器。
是每次你要修改一點東西的時候都先進行開銷巨大的DOM查詢,仍是保存一份元素的索引?選擇一目瞭然。
// before $(".quote a").bind("click", doStuff); // DOM查詢 // now $(".quote a").addClass("quoteLink"); // DOM查詢!! // later $(".quote a").fadeIn("slow"); // 又一次DOM查詢!!!
忽略串接,這樣作更好:
// before var $quoteLinks = $(".quote a"); // 只需一次DOM查詢 $quoteLinks.bind("click", doStuff); // now $quoteLinks.addClass("quoteLink"); // later $quoteLinks.fadeIn("slow");
好了,jQuery/sizzleJS 能夠輕鬆使用CSS3選擇器,可是真正的開銷是什麼? 在這種場景下瀏覽器有可能會使用 document.querySelector(), 可是它也有可能分拆你的選擇器字符串,而後手工去查詢DOM。
// ID搜索是最快的查詢方式,而後它獲取孩子節點的列表,匹配其中class爲'quotes'的元素 $("#quoteList").children(".quotes"); // 只在預先肯定的bar元素下查找'foo'class $(".foo",bar);
無論將來幾年在瀏覽器開發領域會發生什麼,本地的 for循環永遠會比jQuery的 $.each() 循環快。 當你思考jQuery究竟是什麼(把本地JS函數包裝起來的一個庫)這種高大上問題的時候,你就會開始認識到本地原生Javascript代碼永遠會更快。用庫仍是用原生,這是一個運行速度和編程速度之間的權衡。
很重要的一點是,對那些可能每秒調用數百次的性能關鍵的函數,老是要使用 for 循環。例如:
# CSS
## 理解盒子模型是關鍵
"盒子模型"對於理解瀏覽器如何渲染頁面是關鍵性決定性的因素。對其複雜性的全面理解有助於奇蹟般地簡化你的工做。盒子模型描述了對HTML元素的物理維度進行計算的方式。若是一個塊元素具備固定寬度,好比說100px,那麼應該如何肯定它的 padding, border 和 margin 呢?
不少網站都有深刻的描述,但我們簡單點說:在遵循標準的瀏覽器中,border和padding是被放在指定寬度以外的。最好是用圖形來解釋。好比下列代碼:
.foo { width: 150px; height: 150px; padding: 25px; border: 25px solid; margin: 20px; }
你可能估計的狀況(Quirks 模式)
padding 和 border 都是往裏算的,結果保持高度和寬度都是150px。
你看到的狀況(遵循標準模式)
但是,實際上出來的寬度和高度都是250px。 也就是150px + (2 * 25) + (2 * 25)。
若是你以爲這個結果很奇怪,那你不是一我的(呃,你是人,只是說還有其餘人也會這麼想)。 如今手頭有個修復辦法,須要引入一個CSS屬性叫 box-sizing,這個屬性對於 IE8 及以上版本 都適用。它容許你選擇計算元素維度的確切方式,這樣就能救你於危難之中。具體支持的參數因瀏覽器而異,另外須要用到瀏覽器廠商的前綴,具體細節請參閱 caniuse.com 。
/* 舊方法 (178 + 20 + 2 = 200) */ .foo { width: 178px; padding: 10px; border: 1px; } /* 更好的方法 */ .foo { width: 200px; padding: 10px; border: 1px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; }
雖說你也老是能夠對寬度進行心算,在各個像素數中減來減去(就像第一個方法作的那樣),但在涉及到不一樣的寬度單位時(好比百分比或者EM),就沒人能搞清楚到底該怎麼作了。目前,除了把元素包在父元素中,以確保寬度和 padding/margin/borders 能夠所有分開以外,也沒有別的解決辦法。
用table進行佈局的時代過去了。如今要認可咱們能夠集中精力去理解float和position的工做原理。這裏須要掌握一套特別的思惟模型,我相信這件事最好是經過動手練習來進行。
用float從DOM中提取元素並強制它們靠到左邊或右邊,那是至關靠譜。它們已成爲前端開發的後table佈局時代的萬金油,這多是由於之前瀏覽器對於 display: inline 和 inline-block 的支持不力,還有對position的支持中冒出的 z-index bug。可如今就真的沒有藉口了。 inline-block 已經支持得很好了,簡單的一點修正就能讓它在 IE7 裏應用。
謝天謝地,之前那些阻撓用CSS對元素進行絕對定位的爭論都消亡了。理論上,定位屬性可讓你在頁面上以X和Y座標放置元素,這種方式簡單直接,Flash開發者們都應該很熟悉。
理解 Position
用CSS定位元素的時候,理解一個事實很是重要:定位的位置老是相對於離它最近的有定位屬性的父元素而言的。人們剛開始用CSS的時候會有一個常見的誤解,認爲 position: absolute; 是相對頁面的root元素定位的。 我以爲這種誤解來源於某些狀況下,元素沒有任何父元素具有position樣式 -- 在這種狀況下,他們的結論是對的。這樣向上遍歷DOM樹沒有找到任何有定位樣式的元素,就會定位到頁面的根元素上。
那麼,若是 position: absolute; 是把元素從他們所在的流中抽取出來,那你如何相對一個元素的父元素對它進行定位呢? 方法很直接。父元素須要定義 position: relative; 樣式,而後全部的孩子元素就會按上、右、下、左的順序依次擺放。利用這個知識,你會如何實現下面很直觀的佈局呢?
使用 float,你會須要把這些元素包在一個父元素中, 而後把.one float靠左,而後改動 .two 和 .three 的 float 和 margin 。最後你應該寫出相似下面的東西:
.parent { /* ghetto clearfix */ width: 310px; overflow: auto; } .one { width: 200px; height: 210px; float: left; } .two { width: 100px; height: 100px; float: right; margin-bottom: 10px; } .three { width: 100px; height: 100px; float: right; }
正如咱們前面所說,使用 position 讓咱們能夠用很明確的方式,按照 X 和 Y 座標把元素顯示在屏幕上。 上面用float的方式會把頁面上的長文字隔開,下面的方法則能夠確保全部元素處於正常位置,不管頁面上有什麼內容。
.parent { position: relative; width: 310px; height: 210px; } .one, .two, .three { position: absolute; } .one { top: 0; left: 0; width: 200px; height: 210px; } .two { top: 0; right: 0; width: 100px; height: 100px; } .three { bottom: 0; right: 0; width: 100px; height: 100px; }
如前文所述,有些 z-index 的問題須要考慮。雖然上面的例子可能顯得有點過度,不過一旦你開始思考定位,它會打開一個各類可能性的新世界.
若是咱們在單行和多行CSS參數的格式之間變來變去,CSS裏的留空也會不同。我不打算對這個說太細。
合適的空白
/* 很差 */ .selector {display:none;background:#ff0000;color:#000000;} /* 好 -- 單行 */ .selector { display: none; background: #ff0000; color: #000000; } /* 好 -- 多行 */ .selector { display: none; background: #ff0000; color: #000000; }
大括號不換行
.selector { display: none; background: #ff0000; color: #000000; }
子元素縮進
這個用不用就見仁見智了,我我的只會在單行定義的CSS文檔中用這種格式。
.selector { display: none; background: #ff0000; color: #000000; } .selector a { text-decoration: none; } .selector span { font-weight: bold; }
組合並縮進瀏覽器廠商前綴屬性
.selector { background: #FFF; border: 1px solid #000; color: #EAEAEA; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; }
屬性分組
把屬性分組到一塊兒是大大減小CSS文件大小的最有效方法。這裏很重要的一點是要理解屬性是如何排序的(順時針 -- 上,右,下,左),以及如何進一步縮短它們(上和下,左和右)。
/* 逐個定義,太長了 */ padding-top: 1px; padding-right: 2px; padding-bottom: 1px; padding-left: 2px; /* 上,右,下,左,好不少 */ padding: 1px 2px 1px 2px; /* 上和下,左和右,最優 */ padding: 1px 2px;
從 0px 到英雄
給值爲 0 的屬性分配一個單位類型是多餘的。一個元素是距離左邊 0px 仍是 0 elephants 根本不重要,只要知道它是貼着左邊就好了。
/* 很差 */ padding: 0px 10px;
/* 好 */ padding: 0 10px;
對於在一個樣式表裏維護多個樣式區域的任務,給大段CSS加上註釋是很好的辦法。顯然這和單行CSS風格配合使用效果更佳,不過這個效果在多行CSS風格里也不是徹底沒用。註釋裏用破折號、等號仍是下劃線起強調做用就見仁見智了,不過下面是我喜歡的方式:
/* === HORIZONTAL NAV === */ #horizNav { width: 100%; display: block; } #horizNav li { display: block; float: left; position: relative; } #horizNav li a { display: block; height: 30px; text-decoration: none; } #horizNav li ul { display: none; position: absolute; top: 30; left: 0; } /* === HOME PAGE - CAROUSEL === */ #carousel { width: 960px; height: 150px; position: relative; } #carousel img { display: none; } #carousel .buttons { position: absolute; right: 10px; bottom: 10px; }
清除一個 <div>
過去意味着額外的DOM,由於這會涉及到增長一個額外的清除元素。更好的辦法是給父元素設置明確的寬度('auto'並非在全部瀏覽器和場景中有效)以及把overflow屬性設爲'auto'或者'hidden'。'hidden'顯然兼容性更好,但在某些兼容IE的版本里'auto'的效果好一些。
HTML:
<div class="parentElement"> <div class="childElement"> I'm floated left! </div> I'm normal text that wraps around the float </div>
CSS:
.parentElement { width: 100%; overflow: hidden; } .childElement { float: left; }
有本項目的貢獻者提醒我注意最新的clearfix。 micro clear-fix 被認爲至關穩定且跨瀏覽器兼容,足以列入最新的HTML5 boilerplate發佈了。 我 強烈 建議你去看看。雖然我不是瀏覽器特定CSS和 :after 這種僞元素的狂熱粉絲,不過這個micro clearfix的確更健壯。它還能避免頂層margin縮回的問題。
水平居中元素實際上不是什麼高精尖的科技,我敢確定大家大部分人都熟悉下面的代碼片斷:
.class { width: 960px; margin: 0 auto; }
前端開發者們使用這種代碼很長時間了,也沒搞明白爲何這種方式對垂直居中不起做用。從個人理解說,很重要的一點是記住父元素通常會有個 height: auto; 樣式, 也沒有垂直居中元素所需的100%高度。而應用 position: absolute; 能有效地把元素轉移到定位模式,而後被設爲auto的margin會自動幫助它調整位置,達到居中效果。
.exactMiddle { width: 100px; height: 100px; position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: auto; }
這種方法的不足之處包括在 IE6 和 IE7 中缺少支持,以及當瀏覽器被縮小到比居中對象還小時不出現滾動條。 在 這個網頁 裏列出了更多的方法(如今這個是第4個),不過如今這個目前是最優方法。
在一個元素裏垂直居中文字也是很直接的。若是文字是單行的,例如一個水平導航元素,你能夠設置 line-height 爲該元素的物理高度。
#horizNav li { height: 32px; line-height: 32px; }
在前面關於Javascript特性檢測的討論中,檢測到瀏覽器是 任何版本 的 IE 而後就運用某些屬性的作法愈來愈成問題了。鐵人 Paul Irish 引領了使用 IE 版本檢測 方法來解決這些問題的大潮,可是 Modernizr 從那時起拯救了咱們。 Modernizr 在 root 元素裏放入一些class,描述某些特性是否獲得支持. 而後前沿的樣式就能夠很容易從這些class級聯出來或者刪除掉。
.my_elem { -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.25); -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.25); box-shadow: 0 1px 2px rgba(0,0,0,0.25); } /* 若是 box shadow 不支持, 就應用 borders 屬性 */ .no-boxshadow .my_elem { border: 1px solid #666; border-bottom-width: 2px; }
依賴於 !important 標籤是個危險的現象。非用它不可的狀況屈指可數,並且是特殊狀況。這些狀況大抵是須要覆蓋另一套樣式表,而你無法或者沒權限編輯它。另外一個場景是對元素的樣式硬編碼以防止Javascript在線產生的樣式有更大優先級。而實際狀況是 !important 每每被用作偷懶的快捷方式,讓某個樣式優先於其餘的樣式,這樣作未來會產生不少問題。
對 !important 標籤的大部分使用是能夠避免的,只要更好地理解CSS選擇器優先級以及如何更準確地定位元素。選擇器越具體,被接受爲適用樣式的可能性就越大。下面來自 vanseodesign 的例子展現了具體化起做用的狀況。
p { font-size: 12px; } p.bio { font-size: 14px; }
關於樣式優先級, 他們的文章 在解釋繼承性方面比我能寫出來的文章都好,因此請給它點個贊吧。
值得注意的是,這段是個人我的觀點,只適用於特定狀況。在依賴老版本瀏覽器的大型商業項目或企業級解決方案中,進取性向下兼容的立場將不容易被接受。
進取性向下兼容的意思是若是某個特定的(老版本)瀏覽器沒法渲染某個特定效果,則應直接忽略它。CSS3 按鈕就是一個好例子。諸如 border-radius, box-shadow, text-shadow 和 gradients 這些效果會在先進的瀏覽器裏顯示出來。對於版本稍微老一點的瀏覽器,能夠用一個 .PNG 圖片做爲無傷大雅的補救辦法,而全部解決辦法中最優雅的應該是針對IE6提供一個PNG-Fix,或者用filter 參數來代替 gradients 和 shadows等屬性。 不過,在這種狀況下,進取性向下兼容方式會讓你忽略老版本瀏覽器,而在其中展現一個平面的還過得去的對象。
簡單地說,進取性向下兼容說白了就是:若是你的瀏覽器渲染不了漸變色或盒子陰影,那是你運氣很差。
雖然這不是對全部狀況都理想,這種方法能確保項目按時交付,且核心產品是可用的,而不需依賴於對瀏覽器的破解辦法。
這個話題我想我已經說的夠多了。用 Modernizr 來檢測特定的 HTML5 和 CSS3 特性是否可用。
在你考慮嵌入一套定製的字體以前,很重要的一點是你要查看 EULA 並檢查是否容許web嵌入。 字體庫廠商天然是不肯意讓設計師和開發者有能力把字體庫文件直接存放在服務器上,而後被熟練的終端用戶拷貝走。某些廠商也禁止嵌入特定的文件類型,例如 .TTF 和 .OTF。
若是,通過慎重考慮,你相信想要的字體是可嵌入的,那就去看一下Font Squirrel的 @font-face 生成器。 它利用了 Fontspring的 防彈 @font-face 結構 並能自動生成全部須要的文件格式。
謝天謝地,瀏覽器對於它不支持的HTML5 和 CSS3 特性的處理已經達到了優雅的本色。加到 <input />
標籤的新類型例如 "email", "search" 等等在瀏覽器本地不支持的狀況下通常會向下兼容爲正常的 <input type="text" />
。 相似的,不支持的CSS3 特性就不會出現,由高度和寬度媒體查詢控制的響應式佈局也不會被應用。
精巧的CSS3效果應該被應用爲對使用現代瀏覽器的用戶的一種獎勵。
在下面的"資源"小節裏包括了一些有助於讓HTML5和CSS3功能在一批老版本瀏覽器中保持正常的庫。
下列的資源對於代碼標準化和現代web頁面的互動是很重要的。它們確保了CSS3 和 HTML5 特性在之前缺少支持能力的一批瀏覽器中可以使用。
---恢復內容結束---
>這篇文章很長,但的確是一篇很是乾的乾貨,講訴了 HTML、JavaScript、CSS、jQuery使用的一些規範與建議,前端的同窗能夠認真閱讀此文,並比較本身平時的一些習慣,看是否有改進的地方……不定義DOCTYPE是一種能夠被判死刑的罪行。 之前你可能用的是下面的DOCTYPE,不過你要知道如今已經有更簡潔清晰的代碼取而代之了。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
理想的情況是用HTML5 DOCTYPE,全部現代的瀏覽器都支持它,即便是不支持HTML5的瀏覽器,例如IE6,IE7,也會由此轉入標準模式。 參見來源。
<!DOCTYPE html>
用整潔、語義清晰的HTML編寫網站代碼是咱們一直孜孜以求的。有時咱們會發現前人配置頁面的方式限制了咱們,或者有時咱們編寫的是HTML格式的email模板。但永遠不要偏離HTML的規範,即便是爲了解決特定瀏覽器兼容性的bug。全部的標題應該從<h2>
開始分層級建立,文字段落應該老是放在<p>
標籤裏,諸如此類。若是你編寫的HTML的語義清晰,產生的頁面會更整潔、簡練,並且易於被搜索引擎爬蟲解析。這是你能作到的最簡單的SEO修補方式。來看看下面的段落,你以爲哪一個更整潔?是這個?
<span class="sectionHeading">A Heading</span> <br /> <br /> Lorem ipsum dolor sit amet. ... <br /> <br />
仍是這個?
<h2>A Heading</h2> <p> Lorem ipsum dolor sit amet. ... </p>
現代web應用最使人鬱悶的可用性缺陷之一是超連接功能的變種。 一些看起來像是超連接的元素多是經過Javascript映射的單擊功能,這就破壞了鼠標中鍵點擊(在新的tab中打開連接頁面)的功能。即便它們能在新的標籤頁打開,它們只帶有一個 # 的href又會把你帶回到一樣的頁面。深入詮釋了該問題的一個現代熱門網站的例子就是Twitter。在它的整個應用裏,鼠標中鍵點擊用戶名或頭像會獲得徹底不一樣的結果。
<!-- 舊的方式,破壞網頁語義 --> <a href="#"></a> <!-- 若是鼠標點擊不能產生一個頁面,那就不是超連接 --> <span class="link" role="link"></span>
另外一個替代方案是使用 # 引導的路徑,它會把普通的url映射爲 # 引導的連接,而後經過AJAX來獲取頁面片斷。提供此功能的庫應該可以在鼠標中鍵點擊的時候正常顯示頁面,或者在左鍵點擊時把該頁面內容加載到指定的區域。不過這樣也要慎重行事,有不少人都認爲 連接正在破壞web應用
Microformat是一種便於機器讀取聯繫人信息的方式。hCard類(不是vCard)用來定義元素裏包含的內容類型。這些內容會被瀏覽器提取並突出顯示。
<span class="tel"> <span class="type">home</span>: <span class="value">+1.415.555.1212</span> </span>
若是你曾經瀏覽採用此格式的網頁,你會注意到相似skype的程序能夠輕鬆檢測到網頁上的哪些數字是電話號碼。在iOS設備上的Safari瀏覽器也能夠作到相似的事情。
有關Microformat的更多信息請參閱http://microformats.org/wiki/hcard
<img>
標籤須要 alt 文本,以便檢查並知足可讀性的要求。 在 alt 屬性中的文本必須可以說明圖片顯示的內容或要達到的效果,除非該圖片不重要。
若是圖片只是一個列表中的着重號或者其餘可有可無的圖標,最好是給 alt 屬性一個空字符串,但仍是留着它。這樣屏幕閱讀器會忽略它,而不是把"着重號"連讀20次。
<img src="dog.gif" alt="Fido and I at the park!" /> <!-- 很好,描述清晰 --> <img src="bullet.gif" alt="bullet" /> <!-- 很差,顯得多餘 --> <img src="bullet.gif" alt="" /> <!-- 好 -->
table標籤永遠只應該用在表格數據的展現上。惟一的例外是當編寫HTML格式的郵件時,這種狀況下可能table是某些坑爹的郵件客戶端惟一支持的樣式了。
爲了可讀性,表格頭永遠要使用 <th>
元素。同時切記要設置cellpadding, cellspacing 和 border 的值爲 0 , 由於這些樣式由CSS來控制更容易確保一致性。
<table cellpadding="0" cellspacing="0" border="0"> <thead> <tr> <th> Cell Header </th> </tr> </thead> <tbody> <tr> <td> Cell Item </td> </tr> </tbody> </table>
jQuery 和 jQuery UI 被作成儘量在不一樣瀏覽器上表現出幾乎相同的外觀和功能。 jQuery UI 被設計爲符合 WAI WCAG 2.0 及 WAI ARIA, 所以採用該框架能夠避免在你的站點上運行的插件或腳本的全部不肯定性。
任何關於代碼格式、留空和大括號位置的討論都會引發激烈辯論。對此,我想最簡單的規則就是,除非你願意把整個代碼文件從新格式化,否則仍是尊重並保持已有代碼文件的格式。這意味着若是你看到一個JS文件裏的大括號沒有換行寫,那你的代碼也要繼續保持大括號不換行。若是你的代碼沒有和代碼文件裏的其餘部分保持一致,那麼你的代碼就不該該經過代碼審查流程。
一致的代碼格式讓代碼更加易讀,同時也意味着代碼容易用查找/替換命令進行修改。謝天謝地,咱們本身造成的編程習慣和jQuery正式推薦的方式很是類似。細微的差別也是有的,不過,那些是我的問題或者咱們以爲無法維護的一些東西。 參閱jQuery核心樣式指南
字符間距
// 很差 if(blah==="foo"){ foo("bar"); } // 好 :) if (blah === "foo") { foo("bar"); }
大括號不換行
// 很差 if (foo) { bar(); } // 好 :) if (foo) { bar(); }
老是用大括號
// 很差 if (foo) bar(); // 好 :) if (foo) { bar(); }
字符串處理
引用字符串永遠要用雙引號。 有些人很是喜歡用C語言風格的字符串(單引號),但這種習慣會致使腳本內部的風格衝突。C語言風格的字符串處理要求空字符串和單字符包在單引號裏,而短語和單詞必須包在雙引號內。
往代碼裏玩命加註釋的需求是由各類經理、主管及其餘不多接觸代碼的人們引領的。這種需求無非是僱員們考覈指標中的一個勾選欄,花在這上面的時間基本沒有帶來什麼回報。 若是那些從善如流的開發者能遵循本文檔中提出的建議,他們的代碼會變得至關易於閱讀,一目瞭然,以致於再用註釋描述這些代碼會多餘得使人尷尬。來看下面的例子。在這裏,布爾變量被做爲問題提出,而函數也有直觀的命名。
if (user.hasPermission) { editPage(); }
至少在這個場景中,註釋是徹底沒有必要的。
一個項目裏,永遠會有某些部分難以查閱和理解。好比一個複雜的正則表達式,或者一個對角度進行計算或在度和弧度單位之間切換的數學函數。沒有上面的註釋,初級或中級的讀者將對腳本的含義毫無頭緒。
// 校驗美國電話號碼的正則表達式,號碼格式是 (XXX) XXX-XXXX (減號、空格和括號都是可選的,能夠有也能夠沒有) var phoneRegEx = /^\(?(\d{3})\)?[- ]?(\d{3})[- ]?(\d{4})$/;
使用 == 比較符可讓使人鬱悶的bug消失於無形。它容許在 JavaScript花園 中有清楚解釋的弱類型。使用嚴格的 === 比較符不會執行類型強制轉換,從而可以嚴格地評估兩個對象之間的差異。再說一遍,更多詳細信息請參見 JavaScript花園。
var zeroAsAString = "0"; if (zeroAsAString == 0) { // 這樣也能判斷爲true,呵呵... } if (zeroAsAString === 0) { // 判斷爲false }
例外
在和null進行比較的時候,容許使用 == 比較符,由於它會檢測null和undefined兩個屬性。若是你不徹底理解這個原理,那我仍是建議你用 === 比較符爲好。
var foo = null; // foo 是 null, 但 bar 是 undefined ,由於它還沒有被聲明 if (foo == null && bar == null) { // 上面的判斷仍是成立的 }
把字符串解析爲整數的時候,有個好習慣是指定第二個基數參數 -- 它會肯定該字符串被轉換成幾進制。當字符串以 0 開頭的時候,缺省狀況下會觸發 16 進製做爲基數。大部分初級和中級用戶只會用到 10 這個基數。 感謝 João Moreno 記錄的這個 勘誤。
alert( parseInt("08") ); // alerts: 2 alert( parseInt("08", 10) ); // alerts: 8
直接比較 true 和 false 的值是沒有必要的。有時候也許明確一下有好處,但它仍是額外的代碼。
if (foo === true) { // 用了 === 卻是不錯,可這是多餘的 } if (foo) { // 贊! } if (!bar) { // 反過來也贊 }
過度依賴全局變量是咱們組全部人 -- 特別是我本身 -- 特別有負罪感的一件事。關於爲啥全局變量很差的討論是至關直接的:這增長了腳本和變量衝突的機率,並且源文件和命名空間自己都會充斥着數不清的命名模糊的變量。
Douglas Crockford 堅信一個Javascript應用的代碼質量能夠用其中使用的全局變量數來評價,越少越好。因爲並非什麼均可以定義成local的(不過要誠實,其實你如今考慮的那個是能夠的,別偷懶),你須要想辦法整理你的變量以免衝突,並把命名空間的膨脹減到最小。最簡單的方法就是採用單變量或者把用到這些全局變量的模塊儘量減小。 Crockford提到YUI只用了一個全局變量,YAHOO。他在他的博文 "全局統治" 中討論了更多的細節問題。
考慮這種狀況:對於小型web應用,全局變量一般用於保存應用級的設置,能夠用你的項目名或者settings做爲命名去定義一個對象,這樣總的來講會更好。
// 被污染的全局命名空間 var settingA = true; var settingB = false; var settingC = "test"; // 用 settings 做爲對象命名 var settings = { settingA: true, settingB: false, settingC: "test" }
不過,若是咱們能夠經過避免使用全局變量來減小衝突機率,可是把命名空間標準化成同樣的,豈不是會增長各個應用之間產生衝突的機率麼?呃,這個擔心確實有道理。因此,建議你用本身特定的應用名做爲全局變量的命名空間,或者用和jQuery採起的 $.noConflict() 模式相同的方法從新分配你的命名空間.
JavaScript變量的駝峯法命名在大部分編程環境中都是做爲標準的。有讀者在評論中提出了惟一的例外,就是要用大寫字母加下劃線來指代常量。
var X_Position = obj.scrollLeft; var xPosition = obj.scrollLeft; // 更好,更簡潔 SCENE_GRAVITY = 1; // 常量
循環估計是Javascript性能調優最重要的部分了。在一個循環內部節省個一兩毫秒的,說不定整體就省出好幾秒來了。這裏有一招就是把數組的長度緩存,這樣在循環裏就無需每次迭代的時候都計算一遍了。
var toLoop = new Array(1000); for (var i = 0; i < toLoop.length; i++) { // 敗家玩意 - 長度會反覆算 1000 次你知道不? } for (var i = 0, len = toLoop.length; i < len; i++) { // 會過日子 - 長度只計算一次,而後緩存了 }
例外
若是你對一個數組作循環來查找並刪除某個元素,這就會改變數組長度。任什麼時候候你只要會在循環內部增長或刪除元素來改變數組的長度,你就給本身帶來了麻煩。這種狀況下,你要麼每次改變後從新設置數組長度,要麼就別緩存它了。
跳過和跳出循環的能力對於避免開銷很大的循環週期是很是有用的。
若是你是在循環內部查找,查找成功之後你會作什麼?好比1000個元素的循環執行到一半,你就找到了你要的東西。你無論三七二十一,即便知道後面的if語句不會再有符合的機會,仍是讓循環繼續把剩下的500個元素迭代完麼?不!你應該跳出循環,必須的!
var bigArray = new Array(1000); for (var i = 0, len = bigArray.length; i < len; i++) { if (i === 500) { break; } console.log(i); // 這樣只會輸出 0 - 499 }
另外一個問題是跳過某個特定的迭代,而後繼續循環。雖說相似於奇偶數這樣的條件能夠經過把 i++ 替換成 i + 2 的辦法來管理,有些條件仍是須要具體檢測,而後觸發跳過操做。任何可以避免執行完整的迭代過程的東西都是頗有用的。
var bigArray = new Array(1000); for (var i = 0, len = bigArray.length; i < len; i++) { if (condition) { continue; } doCostlyStuff(); }
對於可讀性而不是其餘因素來講,下面這種方式真是糟透了:
function greet(name, language, age, gender, hairColour, eyeColour) { alert(name); }
面的例子預先構建了一個對象做爲參數,或者把內聯對象傳遞過去,這樣就好多了。
function greet(user) { alert(user.name); } greet({ name: "Bob", gender: "male" });
在編寫面向對象(OO)Javascript代碼的時候, 必須瞭解 this 的做用範圍. 無論你用來構建僞類的設計模式是什麼,對 this 的引用是指向一個實例的最簡單辦法。當你開始把jQuery的helper方法和你的僞類集成的時候,你就會注意到 this 的做用範圍變化。
Bob.findFriend("Barry"); Person.prototype.findFriend = function(toFind) { // this = Bob $(this.friends).each(function() { // this = Bob.friends[i] if (this.name === toFind) { // this = Barry return this; } }); }
在上面的例子裏, this 經歷了從對 Bob 的引用,變成對他的朋友 Barry 的引用的過程。 瞭解 this 的取值在一段時間發生的變化是很重要的。在原型函數內部, this 指向所在僞類的當前實例(這裏是 Bob )。而一旦咱們進入 $.each() 循環, this 就會從新映射爲被解析數組的第 i 個元素。
解決辦法是把 this 的值從新映射爲 self 或者 _self。雖然 self (不帶下劃線)並非 保留字, 但它 確實是 window 對象的一個屬性。雖然我上面用到 self 的例子是從jQuery源代碼中挑的,但他們也認識到了這個錯誤,正打算 修正目前的情況 ,也就是改用 **_self。我我的仍是喜歡用 self** ,不爲別的,就由於它的簡潔 -- 不過它可能會冒出一些很是使人困惑的bug。總之,用 self 有風險,使用需謹慎。
在下面的例子中,我會更好地利用在 $.each() helper 中提供的參數,同時從新映射 this 的值。
Bob.findFriend("Barry"); Person.prototype.findFriend = function(toFind) { // 就這一次用到了 "this" var _self = this; $(_self.friends).each(function(i,item) { if (item.name === toFind) { return item; } }); }
布爾變量必須可以很容易經過命名來識別。能夠用相似於 is, can 或者 has 的前綴來造成一個問句。
isEditing = true; obj.canEdit = true; user.hasPermission = true;
從新繪製和從新佈局與從新渲染DOM的過程關聯,這個過程會在特定屬性或元素被改變時發生。從新繪製是在某個元素的外觀被改變但沒有對佈局進行調整的狀況下觸發的。 Nicole Sullivan 在一篇全面的 博文 中把這些改變描述爲諸如是否可見或背景色變化之類的樣式改變。從新佈局則是開銷更大的操做,由調整頁面佈局的一些改變引起。例如增長或刪除元素,改變某個元素的寬度或高度,甚至是改變瀏覽器窗口的大小。最糟糕的狀況是從新佈局致使先輩、兄弟和孩子節點元素也須要從新佈局的多米諾骨牌效應。
毫無疑問,從新繪製和從新佈局應該儘可能避免,可是如何作到呢?
其實也不是說下面的代碼就很糟糕啦。不過咱們先假定數組 arr 有10個元素
var myList = document.getElementById("myList"); for (var i = 0, len = arr.length; i < len; i++) { myList.innerHTML += "<li>" + arr[i].title + "</li>"; //從新佈局 -- 增長到元素 }
在上面的 for 循環裏,每次迭代會觸發一次從新佈局。10次迭代就是10次從新佈局。
如今考慮下面的代碼:
var constructedHTML = ""; for (var i = 0, len = arr.length; i < len; i++) { constructedHTML += "<li>" + arr[i].title + "</li>"; //沒有從新佈局 - 增長到字符串 } document.getElementById("myList").innerHTML = constructedHTML; //在這裏從新佈局
在這個場景裏,須要增長的元素是在一個字符串裏構建的。循環裏邊沒有產生任何從新佈局,由於DOM並無變化。只有當數組被徹底循環完畢,構建的字符串被應用到某個對象的 innerHTML ,這才產生函數裏惟一的一次從新佈局。
有無數種從新佈局和從新繪製是能夠避免的,但願你幸運地瞭解了那些訣竅。這方面的閱讀材料汗牛充棟,不過大部分的材料都會引用到 Nicole Sullivan的這篇 博文 ,這是一個完美的起點。除了這裏的經驗,在涉及到"web 3.0"和HTML5時代的多種技術術語的時候,還有其餘重要的經驗教訓值得汲取。上面的分析直接適用於寫jQuery代碼。在搗騰 canvas 的時候這些原則也很重要,另外儘可能保持幀頻在30-60的範圍內。
自打web開發早期開始,就流行一種產生惟一ID的方法。具體作法是把從1970年1月1日開始計算的微秒數加到你的靜態ID後面,以下所示:
var myID = "static" + new Date().getTime();
這原本是至關萬無一失的方法,由於即使兩段這樣的代碼連續執行,在它們執行的間隙也會有幾毫秒。但是如今新的瀏覽器帶着新的Javascript引擎,伴隨着一直在提高的主頻。到如今,上面的代碼產生相同的毫秒數的可能性會比產生間隙的可能性更大。
這會致使傳統方法難以debug的bug。由於你的DOM是在運行中建立的,對頁面源代碼進行傳統的測試沒法肯定多個重複ID的錯誤。Javascript和jQuery的錯誤處理機制會把第一個匹配的做爲ID並忽略其餘的重複ID。因此它甚至都不會拋出JS錯誤!
這樣不行,惟一真正的方法是逐行設斷點和log,可是若是斷點的位置不對,你的毫秒數又不會衝突了!
好消息是有不少產生惟一ID的替代方法。學究氣一點的說法是,計算機的隨機數函數其實並非真正隨機的,由於它仍是來源於系統時間,雖然這一點值得注意,可是隨機數衝突的可能性是微乎其微的。
var myID = "static" + Math.round(Math.random() * 10000);
我我的更偏心人工產生GUID方法。從技術角度說,GUID是根據你的硬件建立的,不過下面的Javascript函數作得至關棒。這是我從 stack overflow 的一個帖子 裏偷來的,至關順手的一個函數。
function S4() { return (((1+Math.random())*0x10000)|0).toString(16).substring(1); } function guid() { return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4()); }
var myID = "static" + guid();
用戶的瀏覽器是否支持地理信息?用戶的瀏覽器是否支持web works?HTML5 視頻?HTML5 音頻?答案曾經是這樣的:
if ($.browser.msie) { // 哦,是IE啊,那確定不支持 }
可是世界在快速變化。最新版的IE幾乎能算是現代瀏覽器了,但它依舊給前端開發帶來痛苦。更早版本的IE基本上和它以前的版本同樣爛,這就讓偷懶的Javascript程序員習慣於檢測 if (ie) 而後執行一些微軟專用的破語法。如今IE9已經廢棄了這些專用函數,那些原來的 if (ie) 老古董就反而會壞事了。
那麼,若是能檢測每一個特性而不用檢測(既不可靠又能假裝的)user-agent,你以爲咋樣?
若是你的回答是 "那至關靠譜", 那你就說對了。
用 Modernizr 吧,這是行業夢幻級大師Paul Irish參與開發的一個Javascript庫。該庫集普遍應用、輕量級和海量文檔三大優點於一身,實施無需動腦,實爲居家旅行、殺人滅口必備。它會產生一個 Modernizr 對象,其中包含了它全部檢測測試的結果,這樣檢測某個特性的支持與否就和下面的例子同樣簡單:
// 檢測瀏覽器是否支持canvas的老辦法 if (!!document.createElement('canvas').getContext) { ... } // 用 Modernizr 檢測 if (Modernizr.canvas) { ... }
毫秒數的一種方便的寫法是寫成可讀的。對於初學者這很棒,可是大部分狀況下其實只是一個噱頭。
// 這是3秒,30秒仍是300秒啊? var timeout = 30000; // 增長了額外的計算開銷,可是讀和修改會更容易 var timeout = 30 * 1000;
jQuery最好的特性之一就是它的函數串接。你可能已經用過一點,也許把一些簡單的調用一個接一個串起來...可是你是否曾經像頭瘋狗同樣在DOM裏上躥下跳地遍歷呢?仍是花點時間來熟悉一下 .end() 函數。等你從起始選擇器開始在DOM裏上躥下跳的時候,這個函數會很關鍵。
$(".quote") .hide() .find("a").text("Click here").bind("click",doStuff).end() .parent().removeClass().addClass("testimonial").draggable().end() .fadeIn("slow");
上例中,每次咱們完成對某個DOM對象的操做,要反向遍歷DOM返回咱們引用的原始對象的時候,就須要使用 .end() 函數。而後咱們就順藤摸瓜扎回原來DOM裏的位置了。
大家當中那些已經寫了很長時間Javascript(原生的,不是jQuery)代碼的同窗,極可能都熟悉各類屬性吧。大家想辦法設置它們,獲取它們,或者濫用 rel 和 title ...
別說HTML5 或者 jQuery 沒幫上忙哦。新的描述中容許在HTML元素中使用 data- 前綴來指明包含數據的屬性,jQuery會把指定的字符串轉換成正確的Javascript數據類型,這活幹的很是漂亮。咱們來建立一個帶有某些數據屬性的 DIV 。
<div id="test" data-is-bool="true" data-some-number="123"></div>
如今,即便咱們的值被包裝在引號裏面,它們也不會被當作字符串處理:
typeof $("#test").data("isBool"); // boolean typeof $("#test").data("someNumber"); // number
要注意,要讓這些代碼片斷正常工做,(HTML裏的屬性定義)必須使用小寫字母,這很重要。不過若是你是一位很強的前端開發者,你仍是會想用駝峯法來命名你的數據變量。正如在Javascript裏不少地方出現的,前置的鏈接符意味着下一個字母會適用於駝峯法大寫。不過,下面的例子裏在HTML屬性定義中使用駝峯法是 不行的 ,會讓上面的Javascript代碼返回 undefined。
很差使 :(
<div id="test" data-isBool="true" data-someNumber="123"></div>
好使 :)
<div id="test" data-is-bool="true" data-some-number="123"></div>
把jQuery動畫效果和鼠標事件綁定是基於web的現代用戶交互方式中的關鍵部分,但是這方面即使某些最有名的網站也作得很蹩腳。這篇文章 提供了一個實現動畫的直接例子而且演示了這些動畫放在一塊兒在視覺上會產生多麼不和諧的效果。 好在這個問題能夠利用一個函數前綴或在 $.animate 調用中加入一個參數來輕鬆解決。
在使用 $.animate 的時候, 能夠在參數中加入 queue: false 來避免串接。諸如 $.fadeIn 或 $.slideDown 這樣的動畫快捷方式不接受 queue 設置,你必須用 $.stop 這個方法預先中止這些動畫.。 在特定的場景下,須要某個動畫直接停下,或跳轉到變換的最終狀態。推薦你先熟悉有關 clearQueue 和 jumpToEnd 這兩個參數的相關 文檔 ,由於老天在上,我沒有其餘辦法幫你。
$("selector").stop(true,true).fadeOut(); $("selector").animate({ property: value }, { duration: 1000, queue: false }
jQuery 很高冷。它幾乎無所不能,不過它目前還無法給你衝咖啡,我據說在2.0版的路線圖裏有才這個特性。你須要小心的一件事是別濫用它的 sizzleJS 選擇器引擎的能力。想避免這種問題能夠有兩個策略:緩存選擇器結果 以及 使用高效率的選擇器。
是每次你要修改一點東西的時候都先進行開銷巨大的DOM查詢,仍是保存一份元素的索引?選擇一目瞭然。
// before $(".quote a").bind("click", doStuff); // DOM查詢 // now $(".quote a").addClass("quoteLink"); // DOM查詢!! // later $(".quote a").fadeIn("slow"); // 又一次DOM查詢!!!
忽略串接,這樣作更好:
// before var $quoteLinks = $(".quote a"); // 只需一次DOM查詢 $quoteLinks.bind("click", doStuff); // now $quoteLinks.addClass("quoteLink"); // later $quoteLinks.fadeIn("slow");
好了,jQuery/sizzleJS 能夠輕鬆使用CSS3選擇器,可是真正的開銷是什麼? 在這種場景下瀏覽器有可能會使用 document.querySelector(), 可是它也有可能分拆你的選擇器字符串,而後手工去查詢DOM。
// ID搜索是最快的查詢方式,而後它獲取孩子節點的列表,匹配其中class爲'quotes'的元素 $("#quoteList").children(".quotes"); // 只在預先肯定的bar元素下查找'foo'class $(".foo",bar);
無論將來幾年在瀏覽器開發領域會發生什麼,本地的 for循環永遠會比jQuery的 $.each() 循環快。 當你思考jQuery究竟是什麼(把本地JS函數包裝起來的一個庫)這種高大上問題的時候,你就會開始認識到本地原生Javascript代碼永遠會更快。用庫仍是用原生,這是一個運行速度和編程速度之間的權衡。
很重要的一點是,對那些可能每秒調用數百次的性能關鍵的函數,老是要使用 for 循環。例如:
# CSS
## 理解盒子模型是關鍵
"盒子模型"對於理解瀏覽器如何渲染頁面是關鍵性決定性的因素。對其複雜性的全面理解有助於奇蹟般地簡化你的工做。盒子模型描述了對HTML元素的物理維度進行計算的方式。若是一個塊元素具備固定寬度,好比說100px,那麼應該如何肯定它的 padding, border 和 margin 呢?
不少網站都有深刻的描述,但我們簡單點說:在遵循標準的瀏覽器中,border和padding是被放在指定寬度以外的。最好是用圖形來解釋。好比下列代碼:
.foo { width: 150px; height: 150px; padding: 25px; border: 25px solid; margin: 20px; }
你可能估計的狀況(Quirks 模式)
padding 和 border 都是往裏算的,結果保持高度和寬度都是150px。
你看到的狀況(遵循標準模式)
但是,實際上出來的寬度和高度都是250px。 也就是150px + (2 * 25) + (2 * 25)。
若是你以爲這個結果很奇怪,那你不是一我的(呃,你是人,只是說還有其餘人也會這麼想)。 如今手頭有個修復辦法,須要引入一個CSS屬性叫 box-sizing,這個屬性對於 IE8 及以上版本 都適用。它容許你選擇計算元素維度的確切方式,這樣就能救你於危難之中。具體支持的參數因瀏覽器而異,另外須要用到瀏覽器廠商的前綴,具體細節請參閱 caniuse.com 。
/* 舊方法 (178 + 20 + 2 = 200) */ .foo { width: 178px; padding: 10px; border: 1px; } /* 更好的方法 */ .foo { width: 200px; padding: 10px; border: 1px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; }
雖說你也老是能夠對寬度進行心算,在各個像素數中減來減去(就像第一個方法作的那樣),但在涉及到不一樣的寬度單位時(好比百分比或者EM),就沒人能搞清楚到底該怎麼作了。目前,除了把元素包在父元素中,以確保寬度和 padding/margin/borders 能夠所有分開以外,也沒有別的解決辦法。
用table進行佈局的時代過去了。如今要認可咱們能夠集中精力去理解float和position的工做原理。這裏須要掌握一套特別的思惟模型,我相信這件事最好是經過動手練習來進行。
用float從DOM中提取元素並強制它們靠到左邊或右邊,那是至關靠譜。它們已成爲前端開發的後table佈局時代的萬金油,這多是由於之前瀏覽器對於 display: inline 和 inline-block 的支持不力,還有對position的支持中冒出的 z-index bug。可如今就真的沒有藉口了。 inline-block 已經支持得很好了,簡單的一點修正就能讓它在 IE7 裏應用。
謝天謝地,之前那些阻撓用CSS對元素進行絕對定位的爭論都消亡了。理論上,定位屬性可讓你在頁面上以X和Y座標放置元素,這種方式簡單直接,Flash開發者們都應該很熟悉。
理解 Position
用CSS定位元素的時候,理解一個事實很是重要:定位的位置老是相對於離它最近的有定位屬性的父元素而言的。人們剛開始用CSS的時候會有一個常見的誤解,認爲 position: absolute; 是相對頁面的root元素定位的。 我以爲這種誤解來源於某些狀況下,元素沒有任何父元素具有position樣式 -- 在這種狀況下,他們的結論是對的。這樣向上遍歷DOM樹沒有找到任何有定位樣式的元素,就會定位到頁面的根元素上。
那麼,若是 position: absolute; 是把元素從他們所在的流中抽取出來,那你如何相對一個元素的父元素對它進行定位呢? 方法很直接。父元素須要定義 position: relative; 樣式,而後全部的孩子元素就會按上、右、下、左的順序依次擺放。利用這個知識,你會如何實現下面很直觀的佈局呢?
使用 float,你會須要把這些元素包在一個父元素中, 而後把.one float靠左,而後改動 .two 和 .three 的 float 和 margin 。最後你應該寫出相似下面的東西:
.parent { /* ghetto clearfix */ width: 310px; overflow: auto; } .one { width: 200px; height: 210px; float: left; } .two { width: 100px; height: 100px; float: right; margin-bottom: 10px; } .three { width: 100px; height: 100px; float: right; }
正如咱們前面所說,使用 position 讓咱們能夠用很明確的方式,按照 X 和 Y 座標把元素顯示在屏幕上。 上面用float的方式會把頁面上的長文字隔開,下面的方法則能夠確保全部元素處於正常位置,不管頁面上有什麼內容。
.parent { position: relative; width: 310px; height: 210px; } .one, .two, .three { position: absolute; } .one { top: 0; left: 0; width: 200px; height: 210px; } .two { top: 0; right: 0; width: 100px; height: 100px; } .three { bottom: 0; right: 0; width: 100px; height: 100px; }
如前文所述,有些 z-index 的問題須要考慮。雖然上面的例子可能顯得有點過度,不過一旦你開始思考定位,它會打開一個各類可能性的新世界.
若是咱們在單行和多行CSS參數的格式之間變來變去,CSS裏的留空也會不同。我不打算對這個說太細。
合適的空白
/* 很差 */ .selector {display:none;background:#ff0000;color:#000000;} /* 好 -- 單行 */ .selector { display: none; background: #ff0000; color: #000000; } /* 好 -- 多行 */ .selector { display: none; background: #ff0000; color: #000000; }
大括號不換行
.selector { display: none; background: #ff0000; color: #000000; }
子元素縮進
這個用不用就見仁見智了,我我的只會在單行定義的CSS文檔中用這種格式。
.selector { display: none; background: #ff0000; color: #000000; } .selector a { text-decoration: none; } .selector span { font-weight: bold; }
組合並縮進瀏覽器廠商前綴屬性
.selector { background: #FFF; border: 1px solid #000; color: #EAEAEA; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; }
屬性分組
把屬性分組到一塊兒是大大減小CSS文件大小的最有效方法。這裏很重要的一點是要理解屬性是如何排序的(順時針 -- 上,右,下,左),以及如何進一步縮短它們(上和下,左和右)。
/* 逐個定義,太長了 */ padding-top: 1px; padding-right: 2px; padding-bottom: 1px; padding-left: 2px; /* 上,右,下,左,好不少 */ padding: 1px 2px 1px 2px; /* 上和下,左和右,最優 */ padding: 1px 2px;
從 0px 到英雄
給值爲 0 的屬性分配一個單位類型是多餘的。一個元素是距離左邊 0px 仍是 0 elephants 根本不重要,只要知道它是貼着左邊就好了。
/* 很差 */ padding: 0px 10px;
/* 好 */ padding: 0 10px;
對於在一個樣式表裏維護多個樣式區域的任務,給大段CSS加上註釋是很好的辦法。顯然這和單行CSS風格配合使用效果更佳,不過這個效果在多行CSS風格里也不是徹底沒用。註釋裏用破折號、等號仍是下劃線起強調做用就見仁見智了,不過下面是我喜歡的方式:
/* === HORIZONTAL NAV === */ #horizNav { width: 100%; display: block; } #horizNav li { display: block; float: left; position: relative; } #horizNav li a { display: block; height: 30px; text-decoration: none; } #horizNav li ul { display: none; position: absolute; top: 30; left: 0; } /* === HOME PAGE - CAROUSEL === */ #carousel { width: 960px; height: 150px; position: relative; } #carousel img { display: none; } #carousel .buttons { position: absolute; right: 10px; bottom: 10px; }
清除一個 <div>
過去意味着額外的DOM,由於這會涉及到增長一個額外的清除元素。更好的辦法是給父元素設置明確的寬度('auto'並非在全部瀏覽器和場景中有效)以及把overflow屬性設爲'auto'或者'hidden'。'hidden'顯然兼容性更好,但在某些兼容IE的版本里'auto'的效果好一些。
HTML:
<div class="parentElement"> <div class="childElement"> I'm floated left! </div> I'm normal text that wraps around the float </div>
CSS:
.parentElement { width: 100%; overflow: hidden; } .childElement { float: left; }
有本項目的貢獻者提醒我注意最新的clearfix。 micro clear-fix 被認爲至關穩定且跨瀏覽器兼容,足以列入最新的HTML5 boilerplate發佈了。 我 強烈 建議你去看看。雖然我不是瀏覽器特定CSS和 :after 這種僞元素的狂熱粉絲,不過這個micro clearfix的確更健壯。它還能避免頂層margin縮回的問題。
水平居中元素實際上不是什麼高精尖的科技,我敢確定大家大部分人都熟悉下面的代碼片斷:
.class { width: 960px; margin: 0 auto; }
前端開發者們使用這種代碼很長時間了,也沒搞明白爲何這種方式對垂直居中不起做用。從個人理解說,很重要的一點是記住父元素通常會有個 height: auto; 樣式, 也沒有垂直居中元素所需的100%高度。而應用 position: absolute; 能有效地把元素轉移到定位模式,而後被設爲auto的margin會自動幫助它調整位置,達到居中效果。
.exactMiddle { width: 100px; height: 100px; position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: auto; }
這種方法的不足之處包括在 IE6 和 IE7 中缺少支持,以及當瀏覽器被縮小到比居中對象還小時不出現滾動條。 在 這個網頁 裏列出了更多的方法(如今這個是第4個),不過如今這個目前是最優方法。
在一個元素裏垂直居中文字也是很直接的。若是文字是單行的,例如一個水平導航元素,你能夠設置 line-height 爲該元素的物理高度。
#horizNav li { height: 32px; line-height: 32px; }
在前面關於Javascript特性檢測的討論中,檢測到瀏覽器是 任何版本 的 IE 而後就運用某些屬性的作法愈來愈成問題了。鐵人 Paul Irish 引領了使用 IE 版本檢測 方法來解決這些問題的大潮,可是 Modernizr 從那時起拯救了咱們。 Modernizr 在 root 元素裏放入一些class,描述某些特性是否獲得支持. 而後前沿的樣式就能夠很容易從這些class級聯出來或者刪除掉。
.my_elem { -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.25); -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.25); box-shadow: 0 1px 2px rgba(0,0,0,0.25); } /* 若是 box shadow 不支持, 就應用 borders 屬性 */ .no-boxshadow .my_elem { border: 1px solid #666; border-bottom-width: 2px; }
依賴於 !important 標籤是個危險的現象。非用它不可的狀況屈指可數,並且是特殊狀況。這些狀況大抵是須要覆蓋另一套樣式表,而你無法或者沒權限編輯它。另外一個場景是對元素的樣式硬編碼以防止Javascript在線產生的樣式有更大優先級。而實際狀況是 !important 每每被用作偷懶的快捷方式,讓某個樣式優先於其餘的樣式,這樣作未來會產生不少問題。
對 !important 標籤的大部分使用是能夠避免的,只要更好地理解CSS選擇器優先級以及如何更準確地定位元素。選擇器越具體,被接受爲適用樣式的可能性就越大。下面來自 vanseodesign 的例子展現了具體化起做用的狀況。
p { font-size: 12px; } p.bio { font-size: 14px; }
關於樣式優先級, 他們的文章 在解釋繼承性方面比我能寫出來的文章都好,因此請給它點個贊吧。
值得注意的是,這段是個人我的觀點,只適用於特定狀況。在依賴老版本瀏覽器的大型商業項目或企業級解決方案中,進取性向下兼容的立場將不容易被接受。
進取性向下兼容的意思是若是某個特定的(老版本)瀏覽器沒法渲染某個特定效果,則應直接忽略它。CSS3 按鈕就是一個好例子。諸如 border-radius, box-shadow, text-shadow 和 gradients 這些效果會在先進的瀏覽器裏顯示出來。對於版本稍微老一點的瀏覽器,能夠用一個 .PNG 圖片做爲無傷大雅的補救辦法,而全部解決辦法中最優雅的應該是針對IE6提供一個PNG-Fix,或者用filter 參數來代替 gradients 和 shadows等屬性。 不過,在這種狀況下,進取性向下兼容方式會讓你忽略老版本瀏覽器,而在其中展現一個平面的還過得去的對象。
簡單地說,進取性向下兼容說白了就是:若是你的瀏覽器渲染不了漸變色或盒子陰影,那是你運氣很差。
雖然這不是對全部狀況都理想,這種方法能確保項目按時交付,且核心產品是可用的,而不需依賴於對瀏覽器的破解辦法。
這個話題我想我已經說的夠多了。用 Modernizr 來檢測特定的 HTML5 和 CSS3 特性是否可用。
在你考慮嵌入一套定製的字體以前,很重要的一點是你要查看 EULA 並檢查是否容許web嵌入。 字體庫廠商天然是不肯意讓設計師和開發者有能力把字體庫文件直接存放在服務器上,而後被熟練的終端用戶拷貝走。某些廠商也禁止嵌入特定的文件類型,例如 .TTF 和 .OTF。
若是,通過慎重考慮,你相信想要的字體是可嵌入的,那就去看一下Font Squirrel的 @font-face 生成器。 它利用了 Fontspring的 防彈 @font-face 結構 並能自動生成全部須要的文件格式。
謝天謝地,瀏覽器對於它不支持的HTML5 和 CSS3 特性的處理已經達到了優雅的本色。加到 <input />
標籤的新類型例如 "email", "search" 等等在瀏覽器本地不支持的狀況下通常會向下兼容爲正常的 <input type="text" />
。 相似的,不支持的CSS3 特性就不會出現,由高度和寬度媒體查詢控制的響應式佈局也不會被應用。
精巧的CSS3效果應該被應用爲對使用現代瀏覽器的用戶的一種獎勵。
在下面的"資源"小節裏包括了一些有助於讓HTML5和CSS3功能在一批老版本瀏覽器中保持正常的庫。
下列的資源對於代碼標準化和現代web頁面的互動是很重要的。它們確保了CSS3 和 HTML5 特性在之前缺少支持能力的一批瀏覽器中可以使用。