<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[@ChingHanHo]]></title>
  <link href="http://blog.chh.tw/atom.xml" rel="self"/>
  <link href="http://blog.chh.tw/"/>
  <updated>2017-01-20T21:02:50+08:00</updated>
  <id>http://blog.chh.tw/</id>
  <author>
    <name><![CDATA[Ching-Han Ho]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[CSS Font (2) - 像素]]></title>
    <link href="http://blog.chh.tw/posts/css-font-pixel/"/>
    <updated>2017-01-14T22:49:00+08:00</updated>
    <id>http://blog.chh.tw/posts/css-font-pixel</id>
    <content type="html"><![CDATA[<p><img src="https://lh3.googleusercontent.com/QYgIGri4TjlqD74S4v_H39wBvIzcSIEr8wtKJAImXvSc-ZQO8B5WGE5qvYD3_k3PdinLcUXJ7UHZBLGtZJtAP880O5B9q-WcU_VXJPzVWAxgl3TsT27kXFIOYuPhXQ8koXbDjeQDmFOQ4btB2nw_cWIWaczmLL70eExzVdO_1_Wo7E6jXGdHlkYC8m2al-azmM_8vIY5zWKlrdT2ldDaAofCIV0wVOYZN3QwaRZ1vQyRLHa3Wtp1aP1pj2mIHhTpZBWtXcXOg6VFXS_ImBMKhzEFUtOHYkxKJ89p2aiYSq47XnLCDbBo-4ZdEHWqDvXBkWJcHXFalGwRm_HjhyravjJvcdiudp1NJdkQmYO8Yd06QNs7FY8DzSImi3sq-oJIuO4eHsWM8zOASEy0IgV6VubRVUq4VcOCjxd7DOxRzE6iEk2waFr7cI4IRiShvGQ2mkDjYRcf2bqk-aNlpSP1f3pMnK9B1pYSwz-_AgfIq4ZCkYSkKAxbxOF0q-HWb-QcDv_qnyU7S6bFnwjHXsAV8A1d41y9o5HCGIwJyejBdtbn4WFf_7o5gWJesDFU2Eg8sJoaFknTgvUMrbtoApsRlR8zNxayvAZZhILYPS_qXt1xfrI1SZYmeFPNgRbL818lTrQVd0lCf6a1UHrgtdZ2sndlRDRRi4nb-xlHiJYQHbM=w1276-h718-no" alt="" /></p>

<p>（圖片取自 <a href="https://acko.net/files/fullfrontal/fullfrontal/webglmath/online.html">unconed</a> 網站，版權為原網站所有。）</p>

<p>瞭解電腦字型如何被創造，能夠進一步理解文字如何在螢幕上顯示。本系列文章目的在於研究電腦字型在螢幕上顯示的原理，以便理解 CSS 有關字型的各項屬性背後的設計目的，以及要解決的問題。本文適合對象為從事網頁設計的專業人員，不論是網頁設計師、前端工程師，或是全端工程師。</p>

<!-- more -->


<h2>Pixel</h2>

<p>現代螢幕最小的基本單位為像素（pixel），由非常非常多的「小燈泡」組成。一個像素是由紅、綠、藍三個顏色的「小燈泡」組成，他們透過控制開關、亮度，組成不同變化的加法混色，能夠產生非常多種顏色。為了簡化概念，可以將像素理解成一個個小格子，整齊排列構成一個巨大的矩形網格。電腦在繪圖時，是按照網格座標逐一設定每個格子（cell）顏色屬性的 <a href="https://en.wikipedia.org/wiki/RGB_color_model">RGB 值</a>來呈現圖案。有個說法，像素的英文 pixel 的是 picture + cell 組成的詞彙。</p>

<p>Full HD 的螢幕解析度是 1920x1080，表示螢幕橫向 X 軸有 1920 個像素單位，縱向 Y 軸有 1080 個像素單位，總共超過 200 萬個像素單位，這種螢幕實際所擁有的像素數量通常稱為裝置像素（device pixel）。</p>

<p>有些藝術家、工程師用人工的方式在網格上一格一格地點上顏色來製作圖案，這種圖案風格稱為 pixel art。使用像素方格將文字筆劃一點一點點出來的字型，稱為<a href="https://en.wikipedia.org/wiki/Computer_font#Bitmap_fonts">點陣字型</a>（bitmap font）。以前螢幕解析度不高，要在有限的像素內顯示可判斷的文字筆畫，需要使用點陣字型。現在使用最多的場合是大眾運輸上的跑馬燈，或是某些車票、收據仍可以看到點陣字型的使用。</p>

<p><img src="https://lh3.googleusercontent.com/4EZC27DSZk60uyIXHkeLNCaCfp6gDi5UzHX6EVZmAbOpDuBWonrSRePE4cgxeslOSH4dzN6a3G8VzCwCEECWxE2finNMJRZtRxFvjk14gxhuBq4518uAd91c-CeI7uXpoV_sIYR7gML4aYNrqzAgepVfSJYHzgle0XQXxU_qsDOWHE_4swdo2ega1XiRaSJcBseZq5zSIxduP5evzrq4sbs6zfgmIY7PkwQdsEsi8xp85WR3_N9n8u25glDHThBRMAdGLyMGpR2FYFkmldkIWT0YmuZ2jnK_d_NqGbdFjL1vzvwA5WAyChxapxpsWAHYu5ie4lvjsQOFgWJKHfYdVGE3fJXZpvmoEw5_uroTV2bDtsswRMB13sED_TI_oHAzD03IFHWvqZfVRi-ZArFwrbxKGpH3maY7liAV24zmXq519SI3NPT9FLFMn4RHprv3YoEJMK-09QwZK_Nn3-x_jZIId0zwnDT8LF4kcXr6HYH2IJCrJ7p5BplXpba7i-BK0ou4GJhY59UMbGScAShHSR1Ku7JngJDnAkPhZmkpNWJEoNHgBpBR63G2m6iInAyM5pPmSxHfe7UlYFuP9zUI4j13Uy2nk7qT78X8sOKYuA6miHvn9DJeK7a7KjCYJBYrqibTAveIFNG9QSdWS2PjB-I1_6Jik4x7jEAODuEyKs0=s1600" alt="點陣字形" /></p>

<p>若要滿足動輒超過一、兩百萬像素的現代螢幕，便不可能一點一點地點出文字的筆劃，需要用數學方程式來表達向量的線條、幾何圖形，例如 <a href="https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm">Bresenham 演算法</a>繪製線條、<a href="https://en.wikipedia.org/wiki/B%C3%A9zier_curve">Bézier 曲線算法</a>繪製曲線、<a href="https://en.wikipedia.org/wiki/Scanline_rendering">Scanline 填充算法</a>填滿實心的圖形。</p>

<p>透過記錄文字線條變化的節點座標（x,y）來繪製筆劃輪廓的字型，叫做<a href="https://en.wikipedia.org/wiki/Computer_font#Outline_fonts">輪廓字型</a>（outline font）。輪廓字型使用許多直線與曲線組成文字筆劃的輪廓形狀，再以填充演算法填滿內部空間，繪製成文字，這個過程稱為算圖（render）。</p>

<p><img src="https://lh3.googleusercontent.com/WHzAidFm9liuCdl8PO8dyPUWFYAOxwI2M4CNCh0xQoBCSo_tCdqQ3hX96y0qYyn4oLtZnjdIzlx4z_b6HBrgRII9UF_THi_EBNzDwsCOEHDqQzdzBb-EiohTtWNdvpNQWQPNI6z4FAesQROqPDil-i2-uLup3kagfCa-0qYAs5qrVYxG_Yb1ojAsxWJuuBQg2-h99jEHmypIBLc9J2MfUNuJReGsUl5tRKgJqjhVjJQatGfH01yjrTPNvSbjR3hnYZPm4CVSa1UT9byv9hGpH-nNl9EjvynQvArA0tzHXwDnV9BMNEaW7Q3A8iXwu03HbecCglRmc6grTr3EHoewmzRes15Hj79qxgCQXCEb3A-RHqZa71MQ9bykR1g4ZXmjTSwWRbdpDBRfHMNHYI7lS2JyaMonlPNWJxnMGg9ytfi2_kigx7EfCL5otj4YQQXnIPFKGt_6GoBBX0rjLYho5z3NkJk0mGrdRApua21Te0WPvR1RLuk7jm0v-0GUYMBX1rvoLvGmHemOuQPLISHFndtFTgPk4RYCWVTv1IvfqQI9HWpMsvFtgM_3QWJr56KcXwvCjMVhMvJ_waQZHQvj8D8sOSHGCPlSmAnwHeAWuVSwG2Bl-LshaZ4JgzboHdC7xR3-l5RL3h6bO4DgHCghpRf0UlsVi36JBtCADzzX6X4=w706-h628-no" alt="輪廓字" /></p>

<p>目前算圖並沒有一個統一的規範標準，各個引擎的實作方式皆有些微差異，因此在不同的瀏覽器（Chrome、Firefox）、作業系統（macOS、Windows）上相同一套字型的同一個字母，都會看起來不太一樣。</p>

<p><img src="https://lh3.googleusercontent.com/9Hy5Ta3RBWYdhc-IS8FaUwRFCVx795D_9jtScJhIaWsQJ2VLMU0HVf9S2ptpwuAyphS7x1sVuN9f3NPONlxsNUNU9DMQCWldsjKr12J-kLVV_4U0bfNiikauuq5RXB6Ytcf-HMZaN57hLk_o8HRXDubsg1jDvTISCCteow8C374bdfOxlmhbzHXMeTROMX9iZQWGWSvXT3aq_UXjHBBKZw_4uzn7utR3CIIp3MF9uy83JJscK-5-lhZiaXmhCJPYHJ3ZnhuGNJ2E_4FBdE1GkXJE2yr--GFiqW3vAR5BzQANp1h87f9iHIq_f4dWpC-IuvXKvzh5txrRBlVhGd06hXHFXjMDVy5OQQj-7Fq_FBTuWa-F5bnyq4pKdzsYh6NP1W3SENKqdn2-5RvKWJSUhg1m9M2pt93AD2PEejuMLzu4GkN1ivfCRoxOStabAi3fOlYv0z7DmlTaMrWBS1LgzpwT9M19gpTzXPRMImmXWJK9Mky66_Tezbd0cm0JXjjoEEfgwFtqCq6y5R4tG87Qi4fAcbcMOYFr_OOVbnxd9rcQ1cuXcB4sYgTh2jYTpBiPp4qGQpsC0r8rkrDJXJkL6t5g7DnroHftjSQWtMmofxT9Jld9unNWGWk3CyVqILN9IhbJZvb2HSB5otvOoI7ZXMCc1v-uR8Lj_0II1BtgHK4=w450-h74-no" alt="相同頁面不同瀏覽器 render 的結果不同" /></p>

<p>不過螢幕像是個巨大的矩形網格，無法直接顯示向量的圖形，顯示過程需要經過點陣化（rasterization），由電腦程式自動設定每個格子的顏色屬性，將向量線條轉映到一格一格的像素上。</p>

<h2>px 不是 Pixel</h2>

<p>裝置像素的單位以 px 表示，但是 CSS 所定義的 px 並不與裝置像素 1:1 直接對應，至少不是想像中那麼單純的 1px 等於 1 個裝置像素單位，儘管他們都會使用相同的表示方式：1px、320px、1920px。可是兩者定義上卻有些微差異。</p>

<p>須知 CSS 支援的長度單位相當多，有字型排版歷史流傳下來的 pt 以及 pc（pica），也可以使用日常生活可能每天用到的公分（cm）、英吋（in），還有個最特別的單位是 px。對於已經熟悉 CSS 的工程師、設計師大概沒人不知道什麼是 px。px 不像其他單位有實際的物理長度可以相互轉換：</p>

<pre><code>1in = 2.54cm = 25.4mm = 72pt = 6pc
</code></pre>

<p>因為他們是由實際的物理長度組成的絕對單位，物理長度不論在哪都是相同的，基本上每個人伸兩根手指大概都可以比出一公分大概有多長，但是螢幕因為解析度不同，每英吋像素密度（pixels per inch，PPI）都不一樣，例如 iPhone 5s 的像素密度是 iPhone 3G 的兩倍，兩者裝置像素 1px 不會是相同的物理長度。</p>

<p>W3 早在 CSS Level 1 就提出了<a href="https://www.w3.org/TR/css-values/#reference-pixel">參考像素（reference pixel）</a>的概念，定義了 CSS 的 px 單位是參考像素而不是裝置像素。參考像素 1px 等於 1/96 英吋（大約 0.26mm）。與其他絕對單位的轉換公式可以寫成：</p>

<pre><code>1in = 96px = 72pt = 25.4mm
</code></pre>

<p>當設定字級 12pt，電腦需要將 pt 單位轉換為參考像素 px，才能知道螢幕需要用多少像素來顯示文字。依照前述的公式做簡單的單位換算：</p>

<pre><code>12 / 72 * 96 = 16
</code></pre>

<p>計算結果是 12pt 的文字在網頁上顯示的合理邊長為 16px；當 CSS <code>font-size</code> 設定 16px 即表示設定 EM square 邊長的對應像素為 16px，換句話說，<code>font-size</code> 的大小等於 EM square 的大小。然而這只是字型的 EM square 的高度，並非字形本身的高度，要計算字形本身輪廓的像素寬高則需要從 EM square 的座標系統換算。</p>

<h2>字形座標轉換 Pixel</h2>

<p>技術上 EM square 是個二維空間的座標系統，FUnit 是等分座標系統的單位，沒有實際的物理長度，只用來表示相對的距離。為了能在螢幕上顯示字型文字，需要將相對的輪廓座標（x,y）等比例縮放到具體的像素座標上。</p>

<p>輪廓字型以 Roboto Black 為例，這個字型 EM square 邊長為 2048 FUnit，大寫 I 用了四個座標點，座標點之間皆為直線線條連接：</p>

<pre><code>x=474 y=0
x=137 y=0
x=137 y=1456
x=474 y=1456
</code></pre>

<p><img src="https://lh3.googleusercontent.com/wwZ5ylRJC6VM5MVFhB7D4he8hF2x3-gjzHQmr_Lj01RJ0MonUrOe3Mzhgd4EgItDuynUZL9FhWjixWmHdfccX_MryTOFAFdy0A5E6s669-lMpzDTjqow_-P1PNVceVxeWud69JzRIh4g8gwVWVljvEZCCKwP9SJJifBjUxQFdGCaghsgvYhbomk2VXM2qdAu6KK-jMwZW_tQAuTq6SIaY294XZFBzMdvbkoFo4MGU89jTDJ0-elKs-WZQUlhBtjrQjbeVdlZA7e57SltdJNw2fCy94mO0GWhR4l_J8pe842wPBeI-qBnjJIimAGmTDwUJTKrhjhRUdyWt4BiMJ0sCW4MCXMh2-TcZXXB8rETfJpgWputpDI1S-QhvWNg56jxeOFee-MucQxPuD0bbicwBh8nQuIjRld4UEto2RyGgODq9T70Wgy_9MBRd30GzGMevFR_OZhFwG_IBhvzryxFS0FWloU90W6q8ispbs2LRnpU8058_JymUlRwmbfrIMJW-bplo_n23hIPV4N06oOFkB0_8zae2S4ecMQwGQO5CPhOoEun7_-TrmGdQioOFjpaX7k3gDlzpHENyrz_D5XcQCqkDTizEJStdsKxNUceH8--eEDAoLlbgIIpM57V4007j6hiVQnhGB8_7kWjni6XXEGX99bgv02Y6gAppvUxz7Q=w500-h382-no" alt="roboto-black" /></p>

<p>網頁上如果設定 12pt 已經知道合理邊長為 16px，做個簡單的等比例縮放計算：</p>

<pre><code>(round(x/2048*16), round(y/2048*16))
</code></pre>

<p>最後的像素座標分別為：</p>

<pre><code>(3.7, 0)
(1.07, 0)
(1.07, 11.38)
(3.7, 11.38)
</code></pre>

<p>由此得知這個字形最後在螢幕像素上會是個寬高 2.63x11.38 的矩形。也可另外使用以下公式計算字形會用到的像素寬度跟高度：</p>

<pre><code>X/Y軸使用的FUnit * ((字級大小pt * PPI / 72 * 字型UPM尺寸))
</code></pre>

<p>試算結果：</p>

<pre><code>337 * ((12 * 96) / (72 * 2048)) = 2.63
1456 * ((12 * 96) / (72 * 2048)) = 11.38
</code></pre>

<p>因此可以計算出 Roboto Black 的大寫 I 寬度使用 2.63 個像素，以及高度使用了 11.38 個像素。不過像素是螢幕上的最小單位，基本上是一個一個的整數，無法只顯示半個像素，為了實現這個目的，需要用到反鋸齒與子像素的技術。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[CSS Font (1) - 基本概念]]></title>
    <link href="http://blog.chh.tw/posts/css-font-em-square/"/>
    <updated>2016-12-17T12:59:00+08:00</updated>
    <id>http://blog.chh.tw/posts/css-font-em-square</id>
    <content type="html"><![CDATA[<p><img src="https://lh3.googleusercontent.com/_vIG5mKzyW0lcp8INazZP3wb3d5tdN2fkEBLHzy-DJMsqzoski-1WcsUA4T-JlFYHgWqRce8Zk0ErcVQn2gR7UvaeN-MJAlFlWGh2n_sJC71dQZ_bFmXpLsOc1an7dH9u6vt44ES-Ljs6x-RbXMz_ObYyZ9vRgH18eTfVFipTJxjxPPgeynvgkWIzz6W2J6aPE6irkS0I8QXUcNMM0WNGW-b5utOd5AQl0qrp0Ti7YHiHArmd-WciTrzdi-M3AngJVw2EPt7WoBPl4DQE-NbIZHEXjp5CEoq-D6fyeefjCK6eWn-wRyqfAbVHID_R_xtajVEUz2ApIi4RxF-urECPudmJFmvy6mJTH1o5exK5-EY9sofFXxiApntimCfoRc1V8J7iyhIAO3er_JrSOAPe76DsQeC2LcHVUIE9zpos4SMgOXj4RsMjsd0U-jOJHeVmOFiMJJKV-BkHGEdQp9EV5L5nFJOoxX-Hd40mgPRwLJa1GflN055qBd0Fh44MxPTkncgBi8mhqaUNpJobO6qWRbXCga1gDRoJDUQL-Df9i5-agXegiwDpzMdW4tmu3QjFQ-e-DPLoeFmT4pYrHsYiBGCuS8pTD0rx5fG6HVaMFMy7W4dKQ=w483-h346-no" alt="2048" /></p>

<p>（圖片取自「<a href="https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html">Digitizing Letterform Designs</a>」，版權為原網站所有。）</p>

<p>瞭解電腦字型如何被創造，能夠進一步理解文字如何在螢幕上顯示。本系列文章目的在於研究電腦字型在螢幕上顯示的原理，以便理解 CSS 有關字型的各項屬性背後的設計目的，以及要解決的問題。本文適合對象為從事網頁設計的專業人員，不論是網頁設計師、前端工程師，或是全端工程師。</p>

<!-- more -->


<h2>EM square</h2>

<p>傳統金屬活版印刷把每個字母刻在一個金屬方塊上，方塊不一定是正方形，寬度可能不同但是高度相同，這樣才能整齊地排列字母。由於英文中「M」這個字母比例接近正方形幾乎是最大的一個，因此金屬塊的寬度被稱為「em（M）」。</p>

<p>在數位時代一個字母的空間容器從實體金屬塊轉移到虛擬的電腦程式上，電腦程式會建構一個虛構的空間容器被稱為 <a href="http://designwithfontforge.com/zh-CN/The_EM_Square.html">EM square</a>、EM size 或 UPM（Unit per EM），術語源自活版印刷技術的歷史，而數位字型也將以此作為容器基礎。</p>

<p>字體（typeface）指的是文字的外觀風格，常見的字體例如標楷體、新細明體、微軟正黑體、蘋方體、Times New Roman、Helvetica 等，基於相似概念組成的集合便稱為字體家族（font family），也是 CSS 的 <code>font-family</code> 所設定的名稱。</p>

<p>字形（glyph）指的是字元的形狀，由程式演算法或是文字工程師、設計師手動調整的形狀本身。一個字型的所有字形都有相同的 EM square 尺寸，差別在於字形的大小不同。</p>

<p><img src="https://lh3.googleusercontent.com/g1lcXEFfL9nixF0Y2Y_iGmWdB_0IDR7x8lc1Qyvsmm9HaADlF3NuwPsYRAgYZGIDfiTkE70Bzplb8wTlXMlWomr5oW3pYh82SeoK4Up0JDWVTTfBFb1uGlhuqeOSgxVxY3EQnZv7z70PqQedGmiKk3bslIllLWK_qkm0UAkz_-bH8Tu5UofMGV79RDcMCLsPcTHmz4aIv8kgwSV1v9QOsBnwzHA5VxGkUhYaI43KF7wrI8671AiRWqdoVC50fEnAilnAZfdEOuJYemEPrK08WILJhE4TsU9vT-HyyNjVbyofFkZjAuoTz38Ar8Ui-fhF_2oyqIQ_eT8IyzcAqWJdID_LQpavb4l7t_oFXvtcUMUCmBgbr0vwwBghubTM3hCP1X-L4uDYLA3ZRcZRxUilyfvx77eY5Ql7ShBQbV_WODZxsEGlTvXJVKG_R63uS01mWg0JEXEmD-hWc75yDofawRB_9wXU9iAbqR6PrFlyUUXvrRBGqDj5tqlnz1IXaOO_yviAqlWaWLjOTEP5sayRQmzlM2XsS0IOalze94YySZN31VJ34Yisf5kBjhdDQVUz5XgENmTyBCjK_CKihb-BiuT1UceXbU_sYPDNrcvMKnV1BJOIEFd2b6pWUQZ0ZtKaFc5_RyiBRZH70dyaCw0VL4_Dm8l9hwMIsaXvK89Yxj0=s755-no" alt="EM square" /></p>

<p>在技術上 EM square 可以看作是個有限的二維空間座標系統（x,y），寬高可能是 2048x2048（單位 FUnit），<a href="https://www.microsoft.com/typography/otspec/head.htm">OpenType 官方規格建議大小是 16 到 16384 之間</a>，但如果主流軟體無法支援便失去了意義，例如 <a href="http://typedrawers.com/discussion/comment/863/#Comment_863">InDesign、Illustrator 特定版本無法正確處理 EM square 超過 5000 的字型</a>，所以 EM square 的尺寸需要取決於軟體的相容性。目前比較常見的尺寸通常是 1000 或是 2048，例如 <a href="https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html#master">Apple 主要字型都是以 2048 FUnit 去設計</a>的。</p>

<p>字形基本上都會設計在 EM square 的範圍內，但也能超出這個範圍，視字型製造商的偏好及決定。</p>

<p><img src="https://lh3.googleusercontent.com/87tTVmRKfgB9GM7NZWF6ip9nHW-NKYGy8gNU9f8K3aMZXCkg0f16JGgT4-_0tht9i5WpLWOHJYi3NKflZiRjHg5ve1V9lKnUVTGiubZwDXkMuizGc2jP-hozP4zLsLPQlVM_Jmfs65TrS_exYL-BmWRc_h2g9YwxAZkB08zoX3CmEiTfVsehGl31MPuB0C3JtpObW19usVSG98AMDSrYQIt_SxYu58sBQEpfTKpJprFjND5IP7um5IKWuqJixDHjr3ZwF4k4y9b3PiCr3KV7OrpzF51Gl7_HvNfZPzCKt-8vCEgIRODN26N5NjEv6Gq7wuKDDItU30Ukj1RUOibGYlv6grb39g2EkiPwQsnYx9R0FEBvOHP_LrZMfzPH8-Yhqka99lIAbQT2-29593zDY3CqKTB3pFADrqM9zJSUNz3zTU_qeBZppdVZ3IflBaDdD1uKDBlVSe9tu6HQqoxFgNpXBmQmuuX6uI7s5CNpWDtocaon9VfyhWPxzRsKYlABBP5L8Ag3TC7GOwFvKGjwK1lse5WIuK1t8HgC9MniNHW1iIenF0H33kvPruTispc31EV8lpz3w4uQNJFmFzMWVB-KmKXqOCdlTu5oJ1iqxVhsNB8bV8X1mVDzKu3w00-oQvVexxWi5FUd_ng1hs7oDY2VnOXW6nSyeCmrxOq0YPA=s799-no" alt="Character extending outside of the em square." /></p>

<p>當指定 CSS <code>font-size</code> 16px 瀏覽器便會將字型 EM square 的大小映射到螢幕 16px 的大小上，可以參考我的另一篇文章「<a href="http://blog.chh.tw/posts/css-font-pixel/">CSS Font (2) - 像素</a>」。</p>

<h2>字形解構</h2>

<p>觀察英文字母的書法規則，可以歸納出一些模式，例如每個字母基本上都坐落在同一條水平線上，這條水平線稱為基準線（baseline），相對於其他字型或字形決定如何對齊，不過這是針對英文（正確來說是拉丁文）字型設計，中文字型由於都是方形等寬等高的，因此不需要基準線的設計。</p>

<p>此外，基線到字形最高的頂部稱為升部（Ascent）；基線到字形最底的底部稱為降部（Descent）。在數位字型中，這項規格制定在 OpenType、TrueType 的 <a href="https://www.microsoft.com/typography/otspec/os2.htm">OS/2 表格</a>中 <code>sTypoAscender</code> 及 <code>sTypoDescender</code> 的值，或是 <a href="https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6hhea.html">HHEA 表格</a>中的 <code>Ascent</code> 及 <code>Descent</code>。OS/2 是給 Windows 的規格、HHEA 則是 Apple 的規格。</p>

<p><img src="https://lh3.googleusercontent.com/qC070S-SC4Z330u2-mHASXfdcuMaSWZeJLLkMrdDcjZ-k5U5mPDwHJJPOSpT_mCwVtofFUjevRD3BI9mqIXEfJp39UFkk9cCRD-KcciLuOGQalz2xBk8i3skrqOCgv92jiJsqAnK99jXGV_Qjr0vosSo2_tgZmZXdMrGSRemvVDsw9Gn2PYg8VNhEjxnZNAZkoeCUPe9hPg7ecTpWWpJKhWgUY-UnQTRtV3KIGKEIufRnhjwMQrE4rkO2l3v6l5BX3_Gultxc-hNkJ9-0ScKhGMz5gyPHKHBLiykv0MATtp04_292JxcO8079Qoy65mMWIE8XPjvYdcfJR5GhxiKk2seNof0f4gAb-jjhDl3u7SvA8XI8-VAHm2wPS2qgMCP_w8jxM__VhbJDnOcBqBLBpbNz3P_o3AjXPUy6S5fVGbbT7DSfhPDSn2RAEUIi0K68ZnfaeX0VRWqPY3vQ_jq_wDsasqZYw2NedOFpR5VVvgK3MSfKN40jw1qn7_IaXnClwSgZzNZJqZ7UwYthjUO-QxZlTGQyCILBnnye3b5aEAJmIlDXD08GWMj9Hu778uap1AJcX1mseJb4L_fwlv3NSQzutLmJMeC2zFrCXtvO3Om970ucDOllxt3kP2-n08cy9igomlsEgUa1G46u3HyVvITc51D22ZbbkpfH0gLfMw=w914-h738-no" alt="" /></p>

<h2>行高</h2>

<p>印刷排版中的行高英文是 leading，指的是兩行文字中間的距離或空白，但是 CSS 的行高（line height）略有不同的定義，因為它不是只是單純地加在行與行的中間，而是先計算出 leading：</p>

<blockquote><p>leading = <code>line-height</code> - (ascent + descent)</p></blockquote>

<p>然後 CSS 將其中一半的 leading 加到文字的上方，一半加到下方。舉例來說，指定某區塊字級大小 16px，行高設定 24px，則 (24 - 16) = 4，CSS 會在 16px 的文字上面及下面同時加上 4px 的空白，最後整體文字區塊（inline box）才會得到 24px 的高度。</p>

<p>W3 規定 CSS <code>line-height</code> <a href="https://www.w3.org/TR/2011/PR-CSS2-20110412/visudet.html#propdef-line-height">預設的值是 normal</a>，並且建議這個值可以介於 1.0 ~ 1.2 之間。為了測試實際 line-height 到底是多少，我準備了一個測試網頁，在 Chrome 跟 Firefox 兩種不同的 render engine 測試不同英文字跟中文字體，得到以下 4 個測試結果：</p>

<ul>
<li>不同瀏覽器 normal 不同；</li>
<li>同個瀏覽器 <code>font-size</code> 不同 normal 實際值也不同；</li>
<li>同個瀏覽器 <code>font-size</code> 相同 font-family 不同 normal 實際值也不同；</li>
<li>雖然 W3 建議 normal 應該介於 1.0 ~ 1.2 但實際上隨著 <code>font-size</code> 與 <code>font-family</code> 變化，可能會大於 1.2；</li>
</ul>


<p><img src="https://lh3.googleusercontent.com/2YoOk7Z7nao8okS7x8r351ZcSxuz9OHWziJEkoYIIEfsZlm6pcN-2vEGGL_Meh001IBPfSdw_JApeQ2ONLzlIdjs-1jkWS9Nz1REdtiY6pbY4SUKZFYEcPTDLk5WuZFoo_UiGfgSVBUJ6F-mm549PqzgxBp279iQM0B5GrrAA62MKUAfHxVJmRLQohvPVh2PKA9I5tvHdQUO0Y0N1J_Up3CCSlPaSB9h4Zvoj4wZ6M51GeJi39OeqZUu_XL-YAPOmQSTXvDAgBwaiMlAXUevxBCkoARGDOKGXB8Z3mW_OyPHwv4Af37-MYgzO4SyMQWoHoocYLBxtPIV4QzRRQTUaU9lroOE2q5blXCwQHSTVWY5tIej_tjB_P4Gy6AV4RSyKJDnUXom5s5vCMGCma2CU851laqZV4nYiLRVQXv61ngtRDBLn5xujjTLM66AG4nwfr7yeCXrbCLpO8aA0__33F5lHlZITIaq5zvbDYfe2wME_j3AWmunQ2zir6pBJ9W8MTDttq0LG4d6MVW9P4_joHIcvO-670lGG6rLMiY14AJtTqrx6aminh9E4u_e2Nve6ayuPHipD5GxFtbRYHEJLFk81kgpNtdtQcGAuT79HxNn0TaHKg=w1071-h799-no" alt="line-height-compare" /></p>

<p>不同瀏覽器預設 <code>line-height</code> 不同，要解決這個問題也容易，只要在 <code>&lt;html&gt;</code>、<code>&lt;body&gt;</code> 指定固定的值即可，例如 <a href="https://necolas.github.io/normalize.css/">normalize.css</a> 指定了 <code>line-height</code> 為 1.15，<a href="http://meyerweb.com/eric/tools/css/reset/">reset.css</a> 設定 <code>line-height</code> 為 1。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Facebook Instant Articles「即時文章」是什麼？]]></title>
    <link href="http://blog.chh.tw/posts/fb-instant-articles/"/>
    <updated>2016-11-10T00:53:00+08:00</updated>
    <id>http://blog.chh.tw/posts/fb-instant-articles</id>
    <content type="html"><![CDATA[<p><img src="https://lh3.googleusercontent.com/QFqpxXZV3qUjUcR3LLrV3R5rcEPxvm-4DIP7Can_KyABedGdX9MEBFKYEasCx3VwVzoAZN9PqHmigIkyAkzMPswzcg1-BNiQxxPsKC3BhwWSG_ZboFlvygNePknmJAUlo-sCxAZMOwl8F1ZujQp-i_YxnvXEMJkSDqSYHNQESg7mCISjGUymV7KcQe-8hFh8jVhd7lHZkYWoeXwgJXjNPVYzzGcUkA26mnpSVo4yaQyf0aesuY-5-KIRxzb1WgCPUuhmsO5dTgTsTxU0zXBAX_XfldjuJ8AUx0SqOOPkzE9XKu6-Kw_rbTuoW07AeUAro_9Ly4sJgYf1yU3AF77W27uOtPWCQGf2eZypNES5NvyH8pgmvdZislP_hLzJ3vms8ffc3xqe1woCxDK69vfGyOQvQkgWP1o8C1a19sRaUncjhHVr_5AT17eqsRC8UHA_wB6o9XxXf26OOHlMQoQVJtAXMZNTvQY_ZSQvOqOwdETRCndDsWTy6Bm9dFp2ZWA19DdtVQkrwFMIQmvee58CVoH5d8cHe7JGOq-k3tm1P8U96PE9-XnqeJWPd_XyPQ_Z7oqQrDoloMXlHOovYlOwSvgcu44d8NaBhCMo0UopW5mUcEYWYA=w1280" alt="速度" /></p>

<p>行動裝置時代瓶頸：</p>

<ul>
<li>手機頻寬小；</li>
<li>手機速度慢；</li>
</ul>


<p>但是人們希望：</p>

<ul>
<li>速度快；</li>
<li>速度要快；</li>
<li>速度更快；</li>
</ul>


<p>快有什麼好處？遠古的網路傳說：</p>

<ul>
<li>Amazon 網頁平均載入時間多 1 秒，公司年度營收少 16 億美元；</li>
<li>Google 網頁平均載入時間多 0.4 秒，每天搜尋次數減少 800 萬；</li>
<li>使用者開啟網頁 4 秒內沒有出現任何內容便會放棄；</li>
</ul>


<p>所以 Facebook 推出「<a href="https://developers.facebook.com/docs/instant-articles">即時文章</a>」，讓文章內容可以在毫秒之間顯示。</p>

<!-- more -->


<h3>技術</h3>

<p>即時文章原理：</p>

<ul>
<li>簡單說，他們預先把內容載入到 FB app 裡，讓使用者可以「不離開 FB app」直接讀取內容，省去網路訊號來往半個地球的時間；</li>
<li>僅支援 iOS and Android，需要 iPhone iOS 7.0+ &amp; FB app 30.0+，以及 Android Jelly Bean+ &amp; FB app 57+。</li>
</ul>


<p>我想要我的網站內容可以有即時文章，有什麼條件？</p>

<ul>
<li>得要先有個網站；</li>
<li>遵守 FB <a href="https://developers.facebook.com/docs/instant-articles/policy">文章政策</a>；</li>
<li>遵守 FB <a href="https://developers.facebook.com/docs/instant-articles/design/overview#design-guidelines">設計規範</a>；</li>
<li>網站內容頁面程式結構要為「即時文章」做準備；</li>
<li>提交申請，至少準備 10 篇文章做「<a href="https://developers.facebook.com/docs/instant-articles/get-started/article-review">文章審查</a>」。</li>
</ul>


<p>「即時文章」要怎麼做？有以下幾種方式：</p>

<ul>
<li>RSS：網站要另外製作 RSS feed 的端口方便給 FB 抓資料，文件參考「<a href="https://developers.facebook.com/docs/instant-articles/publishing/setup-rss-feed">透過 RSS 摘要發佈</a>」。</li>
<li>API：網站內容頁面的結構需要特別設計過，符合 HTML5 語義話結構；然後網站的內容在 CRUD（建立、讀取、更新、刪除）每個動作，都要與 FB 的程式溝通一次。文件參考「<a href="https://developers.facebook.com/docs/instant-articles/api">即時文章 API</a>」。</li>
<li>另外還有 SDK 跟 WordPress 套件，前者要用 PHP 不討論，後者要用 WordPress 架站。</li>
</ul>


<p>實作了以上功能之後，要先提交 10 篇文章給 FB 進行「文章審查」，在那之前無法發佈即時文章。</p>

<p>一旦完成設定以及審查過程後，FB app 上有 Instant Articles 的內容會出現一個閃點符號，點了<a href="https://twitter.com/mattjroper/status/598489543478751232">幾乎可以毫秒級出現內容</a>。</p>

<h3>商業</h3>

<p>內容都跑到 FB 上去顯示了，我的網站流量豈不是沒了？</p>

<ul>
<li>對，因為讀者「不離開 FB app」；</li>
<li>可以用 <a href="http://www.comscore.com/">comScore</a>、<a href="https://www.google.com.tw/intl/zh-TW/analytics/">Google Analytics</a>、<a href="https://my.omniture.com/login/">Omniture</a> 或 Facebook 自己的工具追蹤「即時文章」的流量；</li>
<li>因為網站本身流量減少，所以原本網站上的廣告收益減少；</li>
<li>但是可以在即時文章放廣告，詳細見「<a href="https://developers.facebook.com/docs/instant-articles/monetization">即時文章的獲利方式</a>」。</li>
</ul>


<p>我的內容在 FB app 上出現得好快好爽，都沒有副作用？FB 轉型做慈善事業？</p>

<p>簡單說，這是 FB 繼吃掉通訊平台、電商平台、支付平台的夢之後，另一個吃掉出版平台的夢。</p>

<p>首先，FB 為內容產出者提供非常好的平台，為許多媒體帶來非常大的流量、讀者和廣告收益等，但這有點像嗑藥，FB 是個一但染上很難戒除的癮，因為：</p>

<ul>
<li>開始需要繳交「演算法維護費」跟「保護費」來維持流量；</li>
<li>Facebook 網站如果掛了就無法導流；</li>
<li>Facebook 有自己的一套「內容審查」決定權在他們，例如粉絲團被關閉的案例；</li>
</ul>


<p>尤其當「即時文章」是要媒體把內容「直接顯示在 FB 上」，讀者連媒體自家網站都不用過去了，對於媒體來說，對自家網站的控制權變得更弱了。</p>

<p>所以，話說回來，我的網站適合「即時文章」嗎？ 以下是個思路：</p>

<ul>
<li>問問為什麼當初選擇花錢自架網站？為什麼不去用免費的 BSP？</li>
<li>如果答案是說自己架網站可以對網站樣式、內容有更多的客製化跟掌控權……</li>
<li>……</li>
<li>……</li>
<li>……</li>
<li>……</li>
<li>那用「即時文章」等於放棄以上這些，那怎麼不去用 BSP？</li>
</ul>


<p>報告完畢！👾</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[SCSS 物件導向模組設計 (1)]]></title>
    <link href="http://blog.chh.tw/posts/scss-object-oriented/"/>
    <updated>2016-10-02T19:47:00+08:00</updated>
    <id>http://blog.chh.tw/posts/scss-object-oriented</id>
    <content type="html"><![CDATA[<p><img src="https://lh3.googleusercontent.com/mZCl_NgujdrKc-XhTqKsXA30gUb7dGQaQhe4Jjx8Blj4_97XWHoy5Zbfq6bk2GCu59jt0Gdu1Li8wCI3iCr9ejKu_wFJxzI4u6IrFl--RQ3KER-J0s4WXZ7f5VuQkH9Kc1TijUI6tHbGMdCt-r_fYO9wUI9ImbRlIhBTW4dgkg2YRDwIFbJjeMGWgQHBtjUb1dmsmjmKtcqWVPH5yfdnXxItyvLUCuA2zuN1dW90gljU6fdj5p1ivtoNQERUrJpXUhF0F_sDQcYsc2m9YzzOKvVnmvYDo0tUtmw1YzUts1PwrybI-G9c-7gKrc12Z_8PZl9dmF4GqOmi4c8ODPFFTxnZZGW5OYTGYah3LtiEQR8OzDY5HuOEKm2LUGPOLdBHRZVT-Xs6Ljy1cx6DLIAVPb1Q1SukfmDigXDyaLimn9-oEazRlugDF9Q2qStJaRzrsi2Ht6tnFZ8LK1XsTjgFpMh3mRnGQCKBewIjd7FiVnYGtT0f3XMhkSjv24UYW3gJAZuPLBjl4P8YQBW20ZLWQi33oCDxQKLr6MOLp-cx7YjOGSqfoYkAvcy3F08TyA2XAhV2PL_4g5gAqnETmUZOPmep9kHwy1gFL1eYJhTdLAcH982D-w=w1101-h755-no" alt="" /></p>

<p>三年前曾經寫過「<a href="http://blog.chh.tw/posts/oocss-smacss-and-css-guidelines/">劣以為的 OOCSS 和 SMACSS 以及其他 CSS 規範</a>」探討 OOCSS 模組化的方法論，時至今日對於模組化設計又有新的認識跟理解，大原則跟三年前的方法沒有出入，只是多做解釋跟補充。</p>

<p>OOCSS 物件導向是解釋設計原則，但是不限於語法的設計。</p>

<p>如果這個議題有興趣，歡迎繼續往下閱讀，如果有任何想法也歡迎留言與我討論！</p>

<!-- more -->


<p>這篇文章會解釋的內容，包括四個設計原則：</p>

<ul>
<li><a href="#srp">單一責任原則</a></li>
<li><a href="#lkp">極少化原則</a></li>
<li><a href="#isp">介面設計原則</a></li>
<li><a href="#ocp">開放封閉原則</a></li>
</ul>


<p>SCSS 模組化設計模式：</p>

<ul>
<li><a href="#cp">元件模式</a></li>
<li><a href="#sp">語義化模式</a></li>
</ul>


<hr />

<p><a name="srp"></a></p>

<h2>單一責任原則</h2>

<p>一個 class 只負責一件事情。這個原則不是指 <a href="https://github.com/marmelab/universal.css">universal.css</a> 這種設計方式，事實上這個專案是個反諷。單一責任原則是指職責獨立、目的明確的 class。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='scss'><span class='line'><span class="nc">.clearfix</span><span class="nd">:before</span><span class="o">,</span>
</span><span class='line'><span class="nc">.clearfix</span><span class="nd">:after</span> <span class="p">{</span>
</span><span class='line'>  <span class="na">display</span><span class="o">:</span> <span class="n">table</span><span class="p">;</span>
</span><span class='line'>  <span class="na">content</span><span class="o">:</span> <span class="s2">&quot;&quot;</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="nc">.clearfix</span><span class="nd">:after</span> <span class="p">{</span>
</span><span class='line'>  <span class="na">clear</span><span class="o">:</span> <span class="no">both</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p><a name="lkp"></a></p>

<h2>極少化原則</h2>

<p>對於層級的依賴應該盡可能減少。</p>

<p>多半的人剛開始寫 SCSS 都為它的巢狀語法感到著迷：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class='scss'><span class='line'><span class="nc">.page</span> <span class="p">{</span>
</span><span class='line'>  <span class="nc">.content</span> <span class="p">{</span>
</span><span class='line'>    <span class="nc">.header</span> <span class="p">{</span>
</span><span class='line'>      <span class="nc">.inner</span> <span class="p">{</span>
</span><span class='line'>        <span class="nc">.group-list</span> <span class="p">{</span>
</span><span class='line'>          <span class="nc">.group-item</span> <span class="p">{</span>
</span><span class='line'>            <span class="nt">a</span> <span class="p">{</span>
</span><span class='line'>              <span class="nc">...</span>
</span><span class='line'>            <span class="p">}</span>
</span><span class='line'>          <span class="p">}</span>
</span><span class='line'>        <span class="p">}</span>
</span><span class='line'>      <span class="p">}</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>這個寫法有改善的空間，因為：</p>

<ul>
<li>不容易閱讀：當層級非常多的時候，哪段屬性屬於哪層 class 會看不清楚。</li>
<li>太倚賴 DOM 結構：一旦改變 DOM 層級結構，SCSS 也可能會需要做層級調整，層級越多耦合性越高，意味維護成本越高。</li>
</ul>


<p>改善的方式便是在相同的命名空間下，試著將層級攤平。適當使用巢狀語法的範例：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='scss'><span class='line'><span class="nc">.nav</span> <span class="p">{</span>
</span><span class='line'>  <span class="na">list-style-type</span><span class="o">:</span> <span class="no">none</span><span class="p">;</span>
</span><span class='line'>  <span class="na">margin</span><span class="o">:</span> <span class="mi">0</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>  <span class="nt">li</span> <span class="p">{</span>
</span><span class='line'>    <span class="na">display</span><span class="o">:</span> <span class="no">inline</span><span class="o">-</span><span class="no">block</span><span class="p">;</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="nt">a</span> <span class="p">{</span>
</span><span class='line'>    <span class="na">display</span><span class="o">:</span> <span class="no">block</span><span class="p">;</span>
</span><span class='line'>    <span class="na">text-decoration</span><span class="o">:</span> <span class="no">none</span><span class="p">;</span>
</span><span class='line'>    <span class="na">color</span><span class="o">:</span> <span class="nb">blue</span><span class="p">;</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>即便 <code>&lt;a&gt;</code> 的 DOM 結構是屬於 <code>&lt;li&gt;</code> 的子元素，仍然不影響它們的作用：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">&quot;nav&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>  <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">&quot;...&quot;</span><span class="nt">&gt;</span>...<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
</span><span class='line'>  <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">&quot;...&quot;</span><span class="nt">&gt;</span>...<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
</span><span class='line'>  <span class="nt">&lt;li&gt;&lt;a</span> <span class="na">href=</span><span class="s">&quot;...&quot;</span><span class="nt">&gt;</span>...<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
</span><span class='line'><span class="nt">&lt;/ul&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>有時候與 DOM 元素本身有絕對關聯的 class，可以在使用區塊註解加以說明：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='scss'><span class='line'><span class="cm">/* ul */</span><span class="nc">.nav</span> <span class="p">{</span>
</span><span class='line'>  <span class="nc">...</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p><a name="isp"></a></p>

<h2>介面設計原則</h2>

<p>針對介面設計，而不是針對實踐方式設計。這個原則可以減少重複的程式碼，增加可維護性。</p>

<p>例如兩個有著相似樣式的區塊，往往會針對區塊實踐它們各別的樣式：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='scss'><span class='line'><span class="nc">.card-default</span> <span class="p">{</span>
</span><span class='line'>  <span class="na">border</span><span class="o">:</span> <span class="mi">1</span><span class="kt">px</span> <span class="no">solid</span> <span class="nf">hsla</span><span class="p">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="kt">%</span><span class="o">,</span> <span class="mi">33</span><span class="kt">%</span><span class="o">,</span> <span class="mi">0</span><span class="mf">.85</span><span class="p">);</span>
</span><span class='line'>  <span class="na">padding</span><span class="o">:</span> <span class="mi">15</span><span class="kt">px</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="nc">.card-primary</span> <span class="p">{</span>
</span><span class='line'>  <span class="na">border</span><span class="o">:</span> <span class="mi">1</span><span class="kt">px</span> <span class="no">solid</span> <span class="nf">hsla</span><span class="p">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="kt">%</span><span class="o">,</span> <span class="mi">66</span><span class="kt">%</span><span class="o">,</span> <span class="mi">1</span><span class="p">);</span>
</span><span class='line'>  <span class="na">padding</span><span class="o">:</span> <span class="mi">20</span><span class="kt">px</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>




<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;card-default&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>  ...
</span><span class='line'><span class="nt">&lt;/div&gt;</span>
</span><span class='line'>
</span><span class='line'><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;card-primary&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>  ...
</span><span class='line'><span class="nt">&lt;/div&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>應該先設計這個模組的介面（interface），再依照介面實踐它不同的樣式特性：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
</pre></td><td class='code'><pre><code class='scss'><span class='line'><span class="c1">// 先設計介面</span>
</span><span class='line'><span class="nc">.card</span> <span class="p">{</span>
</span><span class='line'>  <span class="na">border</span><span class="o">:</span> <span class="mi">1</span><span class="kt">px</span> <span class="no">solid</span> <span class="no">transparent</span><span class="p">;</span>
</span><span class='line'>  <span class="na">padding</span><span class="o">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// 再實踐不同的介面樣式</span>
</span><span class='line'><span class="nc">.card-default</span> <span class="p">{</span>
</span><span class='line'>  <span class="na">border-color</span><span class="o">:</span> <span class="nf">hsla</span><span class="p">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="kt">%</span><span class="o">,</span> <span class="mi">33</span><span class="kt">%</span><span class="o">,</span> <span class="mi">0</span><span class="mf">.85</span><span class="p">);</span>
</span><span class='line'>  <span class="na">padding</span><span class="o">:</span> <span class="mi">15</span><span class="kt">px</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="nc">.card-primary</span> <span class="p">{</span>
</span><span class='line'>  <span class="na">border-color</span><span class="o">:</span> <span class="nf">hsla</span><span class="p">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="kt">%</span><span class="o">,</span> <span class="mi">66</span><span class="kt">%</span><span class="o">,</span> <span class="mi">1</span><span class="p">);</span>
</span><span class='line'>  <span class="na">padding</span><span class="o">:</span> <span class="mi">20</span><span class="kt">px</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>




<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;card card-default&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>  ...
</span><span class='line'><span class="nt">&lt;/div&gt;</span>
</span><span class='line'>
</span><span class='line'><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;card card-primary&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>  ...
</span><span class='line'><span class="nt">&lt;/div&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>一旦先有了介面，後續也才能夠知道該怎麼對此模組進行擴充。</p>

<p><a name="ocp"></a></p>

<h2>開放封閉原則</h2>

<p>對修改封閉、對擴充開放。除非是根本性上地調整模組的樣式，才會需要去改動到介面層級的樣式。這裡引用上一則原則的範例：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='scss'><span class='line'><span class="nc">.card</span> <span class="p">{</span>
</span><span class='line'>  <span class="na">border</span><span class="o">:</span> <span class="mi">1</span><span class="kt">px</span> <span class="no">solid</span> <span class="no">transparent</span><span class="p">;</span>
</span><span class='line'>  <span class="na">padding</span><span class="o">:</span> <span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="nc">.card-default</span> <span class="p">{</span>
</span><span class='line'>  <span class="na">border-color</span><span class="o">:</span> <span class="nf">hsla</span><span class="p">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="kt">%</span><span class="o">,</span> <span class="mi">33</span><span class="kt">%</span><span class="o">,</span> <span class="mi">0</span><span class="mf">.85</span><span class="p">);</span>
</span><span class='line'>  <span class="na">padding</span><span class="o">:</span> <span class="mi">15</span><span class="kt">px</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>




<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;card card-default&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>  ...
</span><span class='line'><span class="nt">&lt;/div&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>當某個頁面需要對此介面做特殊調整，可以使用開放封閉原則，對此介面進行擴充，而不會影響到其他頁面樣式：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='scss'><span class='line'><span class="nc">.card-users</span> <span class="p">{</span>
</span><span class='line'>  <span class="na">border-color</span><span class="o">:</span> <span class="nf">hsla</span><span class="p">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="kt">%</span><span class="o">,</span> <span class="mi">100</span><span class="kt">%</span><span class="o">,</span> <span class="mi">1</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>




<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;card card-default card-users&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>  ...
</span><span class='line'><span class="nt">&lt;/div&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<hr />

<p><a name="cp"></a></p>

<h2>元件模式</h2>

<p>元件模式的哲學在於 class 本身與語義化無關，應該關注它們是否合理，不要刻意強調 class 名稱要符合語義，而要注重使用的合理性與未來性。例如：子元素區塊使用 <code>.list-item</code> 上層元素使用 <code>.list-group</code> 作為子元素的集合，這與元素本身是否是個序列清單（<code>&lt;ol&gt;</code> ）無關。</p>

<p>在前面瞭解過四大設計原則之後，現在已經可以很輕易地設計出模組。先設計介面（interface），再實踐不同的模組樣式：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='scss'><span class='line'><span class="nc">.card</span> <span class="p">{</span>
</span><span class='line'>  <span class="na">background-color</span><span class="o">:</span> <span class="no">transparent</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="nc">.card-default</span> <span class="p">{</span>
</span><span class='line'>  <span class="na">background-color</span><span class="o">:</span> <span class="nb">white</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="nc">.card-primary</span> <span class="p">{</span>
</span><span class='line'>  <span class="na">background-color</span><span class="o">:</span> <span class="nb">red</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>在 HTML 上的使用方式：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;card card-default&quot;</span><span class="nt">&gt;</span>...<span class="nt">&lt;/div&gt;</span>
</span><span class='line'><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;card card-primary&quot;</span><span class="nt">&gt;</span>...<span class="nt">&lt;/div&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>元件模式好處在於開發前端版型，只需要專注在刻寫 HTML 上，快速調用各種模組 class 名稱、減少花時間替 class 命名的 context switch 成本。缺點亦即很容易過度膨脹 HTML 體積，例如使用熱門框架 <a href="http://getbootstrap.com/">Bootstrap</a> 的人們應該對此都不陌生：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;col-lg-9 col-md-9 col-sm-9 col-xs-12 col-lg-offset-3 col-md-offset-3 col-sm-offset-3&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>  ...
</span><span class='line'><span class="nt">&lt;/div&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p><a name="sp"></a></p>

<h2>語義化模式</h2>

<p>語義化強調元素本身所代表的意義，但並非漫無目的地設計 class；結合四種模組設計原則，加上 SCSS 語法的便利性，可以很容易地設計出容易維護及擴充的模組：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
</pre></td><td class='code'><pre><code class='scss'><span class='line'><span class="nt">card</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">@at-root</span> <span class="p">{</span>
</span><span class='line'>    <span class="err">%</span><span class="nn">#</span><span class="p">{</span><span class="na">&amp;}</span><span class="err"> </span><span class="na">{</span>
</span><span class='line'>      <span class="na">background-color</span><span class="o">:</span> <span class="no">transparent</span><span class="p">;</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="err">%</span><span class="nn">#</span><span class="p">{</span><span class="na">&amp;}-default</span><span class="err"> </span><span class="na">{</span>
</span><span class='line'>     <span class="na">background-color</span><span class="o">:</span> <span class="nb">white</span><span class="p">;</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="err">%</span><span class="nn">#</span><span class="p">{</span><span class="na">&amp;}-primary</span><span class="err"> </span><span class="na">{</span>
</span><span class='line'>      <span class="na">background-color</span><span class="o">:</span> <span class="nb">red</span><span class="p">;</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="nc">.content</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">@extend</span> <span class="err">%</span><span class="nt">card</span><span class="o">;</span>
</span><span class='line'>  <span class="o">@</span><span class="nt">extend</span> <span class="err">%</span><span class="nt">card-default</span><span class="o">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="nc">.sidebar</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">@extend</span> <span class="err">%</span><span class="nt">card</span><span class="o">;</span>
</span><span class='line'>  <span class="o">@</span><span class="nt">extend</span> <span class="err">%</span><span class="nt">card-primary</span><span class="o">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>這會產生出以下的結果：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='scss'><span class='line'><span class="nc">.content</span><span class="o">,</span>
</span><span class='line'><span class="nc">.sidebar</span> <span class="p">{</span>
</span><span class='line'>  <span class="na">background-color</span><span class="o">:</span> <span class="no">transparent</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="nc">.content</span> <span class="p">{</span>
</span><span class='line'>  <span class="na">background-color</span><span class="o">:</span> <span class="nb">white</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="nc">.sidebar</span> <span class="p">{</span>
</span><span class='line'>  <span class="na">background-color</span><span class="o">:</span> <span class="nb">red</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>因此可以清晰、明確地定義出區塊所代表的意義：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;sidebar&quot;</span><span class="nt">&gt;</span>...<span class="nt">&lt;/div&gt;</span>
</span><span class='line'><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;content&quot;</span><span class="nt">&gt;</span>...<span class="nt">&lt;/div&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>語義化模式的優點在於減少 HTML 冗長的 class 名稱串聯，透過 SCSS 語法優勢，對不同的區塊套入相同的模組樣式。缺點在於切出每個區塊時沒有那麼容易替其命名，增加了中間「做決定」的思考成本。</p>

<p>兩個模式並非相互衝突，可以在適當的時機交互結合應用。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[使用一個 HTML 樣版引擎的選擇重點]]></title>
    <link href="http://blog.chh.tw/posts/how-to-select-html-template-engines/"/>
    <updated>2016-07-22T15:02:00+08:00</updated>
    <id>http://blog.chh.tw/posts/how-to-select-html-template-engines</id>
    <content type="html"><![CDATA[<p><img src="https://lh3.googleusercontent.com/QgvDvJX1TZztm_lBHTgAD2gEhw89v82uk9DVs1l69GlRVlSQ_fRxQ_WiNk54B-iUbyPB7AoUm2ZoBpHUD3cN99AHB6VTcSVUG24zeEypIKoWgk9cUnbnPMHsvmU5eoBjjQSBKaPBitjKvu82xnqYL5Gm0mMlU8OAzHcmh3_WxZx8EUsqB-roXuFp31zGkW84Z4JY3l01F6mPK6vTss_Xdg707k0y4lo0OX8mUnETc196rK2L5-y1clcgvLB33qvaBAHQq6JOqbuOmcV3_qbJb-NDC714KqTB-R6m15KBcTYk_72s8rUUOTKDGjDpsm-nVIGdwxJAjYICl8Cz7mB_c9pVeRKdx17ennNpyhUrK1JYuWAk4Gk9wPQv3_lt8PuxrvUMZwwkranlg1Ob0MB6XuQSn2MFaEGU1XFbgAOMZ6iPKjxceKupt9bE5aPevLjMk_O_WvKQAAzwg7Ne8BK_tUrmHWbYwvhUUpcwV-sKSsCFrE4Ps31LvgxqMWQ-c_Z0iq7Ou5WFWfc2eDrx_JWptmkTeWDfBmjo9uVuusVuXjy4g1G-GpSUIhU8ZYTBlKZZJA3dFRwevNTOmlC_hsFL8kgcfqbm_SXP=w1101-h493-no" alt="" /></p>

<h3>語法</h3>

<p>首先當然是要喜歡上該樣版引擎的語法，因為使用樣版引擎的主要目的就是為了加速撰寫 HTML 的生產力，給先讓自己喜歡使用它，才有辦法寫得有效率。多數樣版引擎的入口頁會用簡單的範例，快速火力展示它的特點，這是很好的開始。但也因為這是精心設計的著陸頁，目的是攻取心裡的小惡魔，所以在選擇採用這套樣版引擎前也得特別小心。</p>

<h3>擴充性</h3>

<p>一個好的樣版引擎可以讓自己掌控專案的伸縮性，例如註冊新的 helper 跟 block，節省撰寫重複的程式碼，靈活地設計版型架構。</p>

<h3>安全性</h3>

<p>對於經驗不足的開發者來說這很容易鑄成大錯，在沒有意識下的輸出未消毒的內容，都可能會造成使用者傷害，而一個好的樣版引擎應該要預設消毒輸出。如果對自己的經驗很有信心，覺得這是初學者才會犯的錯誤，但也不能夠保證其他同事們不會粗心大意。</p>

<h3>勿矯枉過正</h3>

<p>使用樣版引擎是為了增加團隊在撰寫 HTML 的效率，所以應該以團隊的技術水平作為優先考量，如果團隊的平均技術水平沒有達到而貿然採用也只是增加大家困擾而已。 不要為了使用而使用。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[使用 Zepto + Velocity 無縫取代 jQuery 更輕巧]]></title>
    <link href="http://blog.chh.tw/posts/using-zepto-replace-jquery/"/>
    <updated>2015-10-01T00:26:00+08:00</updated>
    <id>http://blog.chh.tw/posts/using-zepto-replace-jquery</id>
    <content type="html"><![CDATA[<p><img src="https://lh3.googleusercontent.com/fKcLfP4rJK5syiKv-cfmDYlbdC0_dV8sAdyQfYM3DxZW76knVkgxFsMC4sWsBpaN_27emoOHF504CNpmSDn0rnlDG2Eu1vw6RNowi18owUxdnBYaotT3hz2BIWnrQioS-tfQfOU4iDNAss3pzDKuNOPmSLWjNVP-zQrZJhZOK1Xf78TU9GdCSKnIApESyUZ777gjz7LC5PKw9Yk_NcNr8GCrKRsd7cCQciMf_sSmmZ1sqWKRcIAVWdt-B7_5fV9nW4vNfBYkFvJCI-BaIC_KmR-KPiVMUHi7y4hMzW1DmT4uzAJwfKIk3tvjWW6pEe345hE3R0nxqq-y0apP64DcndcDHFq16S1KqW465nsZRwvg6412LAjzp1cVM_XEimA9NekxAlTC1u89PNLyALrNtaaNRsAsj02D43lSFKu0gEKGMdAl23BhXkBtL-khwLYgoKWCbRkvZ7eznqnONx7zyGxxbNNU48Rn5NLDhw74Bxr0Xy72I1ROoGjm7E22V5-5BSl3CbsBAgczJ-fxCgxHzYWsmJpdqAIA6DVFmD5A8Vk=w690" alt="zeptojs" /></p>

<p>Zepto 是個跟 jQuery API 相容的套件，但是非常輕巧。</p>

<p>jQuery 1.11.2 不壓縮 278KB，壓縮後是 94.8KB。儘管 jQuery 2.0 比 jQuery 1.11 減少了 12% 的體積大小，仍然是個 200KB 級的套件。而 Zepto 不壓縮 56KB，壓縮後大約是 24.5KB，比 jQuery 平均小了 74%！</p>

<p>Zepto 極其輕巧的秘訣在於它預設只有 jQuery 最關鍵的幾個核心功能，並且用友善的模組化設計，保持每個功能能夠輕易地被擴充。</p>

<!-- more -->


<h2>擴充 animate 模組</h2>

<p>jQuery 的 <code>animate</code> 效能不是很好，上次在製作公司官網作品牆，讓圖片載完進行 <code>fadeIn</code> 的效果，造成 FPS 低到明顯感受到 lag。</p>

<p>通常需要用到大量的動態視覺效果的首選是 GreenSock 所提供的 TweenMax（344KB）。如果只是需要用來取代 jQuery 的 <code>animate</code> 操作 DOM 的動態效果，那麼能夠跟 jQuery 無縫整合的 Velocity（215KB）有更好的條件。Velocity 優點是效能高，體積比較小，也能夠相容 jQuery API。</p>

<p>Zepto 因為模組化設計的關係，預設是不包括 <code>animate</code> 這個方法的，因此便可以改用 Velocity 來擴充。</p>

<p>外部網站參考：</p>

<ul>
<li><a href="http://zeptojs.com/">Zepto 的專案網站</a></li>
<li><a href="http://julian.com/research/velocity/">Velocity 的專案網站</a></li>
<li><a href="https://greensock.com/tweenmax">TweenMax 的專案網站</a></li>
</ul>


<h2>瀏覽器相容性</h2>

<p>jQuery 2.0 開始就直接放棄 IE 9 以下的瀏覽器，Zepto 更狠直接跳到 IE 10+；而 Velocity 則是不支援 IE 8 以下，所以能不能使用 Zepto + Velocity 這個組合要先觀察一下產品的目標使用群。</p>

<p>如果打算支援 IE 8，還是去用 jQuery 1.11.3 吧！</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[9 個存取硬體裝置的 Javascript API]]></title>
    <link href="http://blog.chh.tw/posts/9-javascript-apis-accessing-device-sensors/"/>
    <updated>2015-08-30T17:09:00+08:00</updated>
    <id>http://blog.chh.tw/posts/9-javascript-apis-accessing-device-sensors</id>
    <content type="html"><![CDATA[<p>原生 HTML5 和 Javascript API 可以直接從瀏覽器存取硬體組件和感測器。這裏的硬體裝置主要是指手機。</p>

<h3>點擊連結傳送簡訊</h3>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">&quot;tel:0912345678&quot;</span><span class="nt">&gt;</span>打給我！<span class="nt">&lt;/a&gt;</span>
</span><span class='line'>
</span><span class='line'><span class="c">&lt;!-- Android --&gt;</span>
</span><span class='line'><span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">&quot;sms:0912345678?body=你到哪了？&quot;</span><span class="nt">&gt;</span>傳簡訊給我！<span class="nt">&lt;/a&gt;</span>
</span><span class='line'><span class="c">&lt;!-- iOS --&gt;</span>
</span><span class='line'><span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">&quot;sms:0912345678&amp;amp;body=你到哪了？&quot;</span><span class="nt">&gt;</span>傳簡訊給我！<span class="nt">&lt;/a&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>延伸資料：</p>

<ul>
<li><a href="http://stackoverflow.com/questions/6480462/how-to-pre-populate-the-sms-body-text-via-an-html-link">How to pre-populate the sms body text via an html link - StackOverflow</a></li>
</ul>


<h3>地理定位 API</h3>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="k">if</span> <span class="p">(</span><span class="nx">navigator</span><span class="p">.</span><span class="nx">geolocation</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="nx">navigator</span><span class="p">.</span><span class="nx">geolocation</span><span class="p">.</span><span class="nx">getCurrentPosition</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">position</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="kd">var</span> <span class="nx">whereareyou</span> <span class="o">=</span> <span class="nx">position</span><span class="p">.</span><span class="nx">coords</span><span class="p">.</span><span class="nx">latitude</span> <span class="o">+</span> <span class="s1">&#39; ,&#39;</span> <span class="o">+</span> <span class="nx">position</span><span class="p">.</span><span class="nx">coords</span><span class="p">.</span><span class="nx">longitude</span>
</span><span class='line'>    <span class="nx">alert</span><span class="p">(</span><span class="nx">whereareyou</span><span class="p">)</span>
</span><span class='line'>  <span class="p">})</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<h3>裝置方向與裝置體感 API</h3>

<p>這兩個功能是建立在裝置的陀螺儀和指南針感測器上，它能夠傳回目前裝置的旋轉角度，以及三個維度。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="k">if</span> <span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nx">DeviceOrientationEvent</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="nb">window</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;deviceorientation&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="c1">// gamma 是左到右傾斜的角度</span>
</span><span class='line'>    <span class="c1">// beta  是前到後傾斜的角度</span>
</span><span class='line'>    <span class="c1">// alpha 是裝置面向在指南針方位上的角度</span>
</span><span class='line'>    <span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="nx">event</span><span class="p">.</span><span class="nx">gamma</span> <span class="o">+</span> <span class="s1">&#39; ,&#39;</span> <span class="o">+</span> <span class="nx">event</span><span class="p">.</span><span class="nx">beta</span> <span class="o">+</span> <span class="s1">&#39; ,&#39;</span> <span class="o">+</span> <span class="nx">event</span><span class="p">.</span><span class="nx">alpha</span>
</span><span class='line'>
</span><span class='line'>  <span class="p">},</span> <span class="kc">false</span><span class="p">)</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>有了裝置體感的 API，也可以做出搖一搖復原輸入的功能。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="k">if</span> <span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nx">DeviceMotionEvent</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="nb">window</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;devicemotion&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">evnet</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>
</span><span class='line'>    <span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="nx">evnet</span><span class="p">.</span><span class="nx">acceleration</span><span class="p">.</span><span class="nx">x</span> <span class="o">+</span> <span class="s1">&#39;&lt;br/&gt;&#39;</span> <span class="o">+</span> <span class="nx">evnet</span><span class="p">.</span><span class="nx">acceleration</span><span class="p">.</span><span class="nx">y</span> <span class="o">+</span> <span class="s1">&#39;&lt;br/&gt;&#39;</span> <span class="o">+</span> <span class="nx">evnet</span><span class="p">.</span><span class="nx">acceleration</span><span class="p">.</span><span class="nx">z</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// 加速感測</span>
</span><span class='line'>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">evnet</span><span class="p">.</span><span class="nx">acceleration</span><span class="p">.</span><span class="nx">x</span><span class="p">)</span>
</span><span class='line'>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">evnet</span><span class="p">.</span><span class="nx">acceleration</span><span class="p">.</span><span class="nx">y</span><span class="p">)</span>
</span><span class='line'>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">evnet</span><span class="p">.</span><span class="nx">acceleration</span><span class="p">.</span><span class="nx">z</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// 加速感測包括重力參數</span>
</span><span class='line'>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">evnet</span><span class="p">.</span><span class="nx">accelerationIncludingGravity</span><span class="p">.</span><span class="nx">x</span><span class="p">)</span>
</span><span class='line'>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">evnet</span><span class="p">.</span><span class="nx">accelerationIncludingGravity</span><span class="p">.</span><span class="nx">y</span><span class="p">)</span>
</span><span class='line'>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">evnet</span><span class="p">.</span><span class="nx">accelerationIncludingGravity</span><span class="p">.</span><span class="nx">z</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// 旋轉率</span>
</span><span class='line'>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">evnet</span><span class="p">.</span><span class="nx">rotationRate</span><span class="p">.</span><span class="nx">alpha</span><span class="p">)</span>
</span><span class='line'>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">evnet</span><span class="p">.</span><span class="nx">rotationRate</span><span class="p">.</span><span class="nx">beta</span><span class="p">)</span>
</span><span class='line'>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">evnet</span><span class="p">.</span><span class="nx">rotationRate</span><span class="p">.</span><span class="nx">gamma</span><span class="p">)</span>
</span><span class='line'>  <span class="p">},</span> <span class="kc">false</span><span class="p">)</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>延伸資料：</p>

<ul>
<li><a href="https://developers.google.com/web/fundamentals/device-access/device-orientation/dev-motion?hl=zh-tw">裝置動作 - Web Fundamentals</a></li>
<li><a href="https://developers.google.com/web/fundamentals/device-access/device-orientation/?hl=zh-tw">裝置定向 - Web Fundamentals</a></li>
</ul>


<h3>震動馬達</h3>

<p>目前只支援 Android 的 Chrome 以及 Opera、Firefox，iOS 尚不支援。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="kd">var</span> <span class="nx">btn</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">&#39;btn&#39;</span><span class="p">)</span>
</span><span class='line'><span class="kd">var</span> <span class="nx">vibrate</span> <span class="o">=</span> <span class="nx">navigator</span><span class="p">.</span><span class="nx">vibrate</span> <span class="o">||</span> <span class="nx">navigator</span><span class="p">.</span><span class="nx">mozVibrate</span> <span class="o">||</span> <span class="nx">navigator</span><span class="p">.</span><span class="nx">webkitVibrate</span>
</span><span class='line'><span class="nx">btn</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;click&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="nx">vibrate</span><span class="p">(</span><span class="mi">1000</span><span class="p">)</span>
</span><span class='line'><span class="p">})</span>
</span></code></pre></td></tr></table></div></figure>


<p>延伸資料：</p>

<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Navigator/vibrate">Navigator.vibrate() - MDN</a></li>
</ul>


<h3>剩餘電力管理</h3>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="kd">var</span> <span class="nx">battery</span> <span class="o">=</span> <span class="nx">navigator</span><span class="p">.</span><span class="nx">battery</span> <span class="o">||</span> <span class="nx">navigator</span><span class="p">.</span><span class="nx">webkitBattery</span> <span class="o">||</span> <span class="nx">navigator</span><span class="p">.</span><span class="nx">mozBattery</span>
</span><span class='line'>
</span><span class='line'><span class="kd">function</span> <span class="nx">log</span><span class="p">(</span><span class="nx">_battery</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="s1">&#39;目前電力剩下：&#39;</span> <span class="o">+</span> <span class="p">(</span><span class="nx">_battery</span><span class="p">.</span><span class="nx">level</span> <span class="o">*</span> <span class="mi">100</span><span class="p">)</span> <span class="o">+</span> <span class="s1">&#39;%&#39;</span>
</span><span class='line'>  <span class="nx">_battery</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;chargingchange&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'>    <span class="nx">alert</span><span class="p">(</span><span class="s1">&#39;開始充電！&#39;</span><span class="p">)</span>
</span><span class='line'>  <span class="p">},</span> <span class="kc">false</span><span class="p">)</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="k">if</span> <span class="p">(</span><span class="nx">navigator</span><span class="p">.</span><span class="nx">getBattery</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="nx">navigator</span><span class="p">.</span><span class="nx">getBattery</span><span class="p">().</span><span class="nx">then</span><span class="p">(</span><span class="nx">log</span><span class="p">)</span>
</span><span class='line'><span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">battery</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="nx">log</span><span class="p">(</span><span class="nx">battery</span><span class="p">)</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<h3>亮度感測器</h3>

<p>目前只有 Firefox 支援這個 API。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="k">if</span> <span class="p">(</span><span class="s1">&#39;ondevicelight&#39;</span> <span class="k">in</span> <span class="nb">window</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="nb">window</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s2">&quot;devicelight&quot;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="c1">// 回傳的是亮度單位 lux</span>
</span><span class='line'>  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">event</span><span class="p">.</span><span class="nx">value</span> <span class="o">+</span> <span class="s2">&quot; lux&quot;</span><span class="p">)</span>
</span><span class='line'>  <span class="p">})</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<h3>近距離感測 API</h3>

<p>這個也是只有 Firefox 支援。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="k">if</span><span class="p">(</span><span class="s1">&#39;ondeviceproximity&#39;</span> <span class="k">in</span> <span class="nb">window</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="c1">// Fired when object is in the detection zone</span>
</span><span class='line'>  <span class="nb">window</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;deviceproximity&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="c1">// Object distance in centimeters</span>
</span><span class='line'>      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">event</span><span class="p">.</span><span class="nx">value</span> <span class="o">+</span> <span class="s2">&quot; centimeters&quot;</span><span class="p">)</span>
</span><span class='line'>    <span class="p">})</span>
</span><span class='line'><span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class='line'>  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&quot;deviceproximity not supported&quot;</span><span class="p">)</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="k">if</span><span class="p">(</span><span class="s1">&#39;ondeviceproximity&#39;</span> <span class="k">in</span> <span class="nb">window</span><span class="p">){</span>
</span><span class='line'>  <span class="c1">// Fired when object is in the detection zone</span>
</span><span class='line'>  <span class="nb">window</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;userproximity&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="k">if</span><span class="p">(</span><span class="nx">event</span><span class="p">.</span><span class="nx">near</span> <span class="o">==</span> <span class="kc">true</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&quot;Object is near&quot;</span><span class="p">)</span>
</span><span class='line'>    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class='line'>      <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&quot;Object is far&quot;</span><span class="p">)</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>  <span class="p">})</span>
</span><span class='line'><span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span><span class='line'>  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&quot;userproximity not supported&quot;</span><span class="p">)</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<hr />

<p>參考：</p>

<ul>
<li><a href="http://www.webondevices.com/9-javascript-apis-accessing-device-sensors/">9 JavaScript APIs accessing Device Hardware</a></li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[io.js 1.1 VS node.js 0.12.0 VS node.js 0.10.36]]></title>
    <link href="http://blog.chh.tw/posts/iojs-nodejs-performance/"/>
    <updated>2015-02-10T23:37:00+08:00</updated>
    <id>http://blog.chh.tw/posts/iojs-nodejs-performance</id>
    <content type="html"><![CDATA[<p>這篇文章不是要做深入的效能評比，只是最近 node.js v0.12.0 正式版釋出，又剛好人品很好地用 io.js 1.1 把專案建起來了，乾脆就在本機上做一下 node.js 新舊版和現在很熱的 io.js 效能紀錄。圖有點小，要嘛自己想辦法放大，要嘛就直接看結論吧！XD</p>

<h3>Page 1</h3>

<p><img src="https://lh3.googleusercontent.com/-AWI4LN6fELs/VNomvCU_iMI/AAAAAAAAIKs/Im1igPcG3EI/w1118-h331-no/Screen%2BShot%2B2015-02-10%2Bat%2B11.28.59%2BPM.png" alt="node.js v0.12.0 page1" /></p>

<p>node.js v0.12.0 TTFB 1.36s。</p>

<p><img src="https://lh6.googleusercontent.com/-tl-PFTsvs-0/VNomy_t_IkI/AAAAAAAAILU/YRiVxSVD5Dc/w1118-h331-no/Screen%2BShot%2B2015-02-10%2Bat%2B11.34.28%2BPM.png" alt="io.js v1.1.0 page1" /></p>

<p>io.js v1.1.0 TTFB 1.21s。</p>

<p><img src="https://lh4.googleusercontent.com/-pJ4XM3ov8v4/VNomx2fPf-I/AAAAAAAAILE/RxH-DOoQygg/w1118-h331-no/Screen%2BShot%2B2015-02-10%2Bat%2B11.30.32%2BPM.png" alt="node.js v0.10.36 page1" /></p>

<p>node.js v0.10.36 TTFB 603ms。</p>

<!-- more -->


<h3>Page 2</h3>

<p><img src="https://lh4.googleusercontent.com/-5LGXJ2DInfM/VNomvEBYaQI/AAAAAAAAIK0/UyWZldWsB-4/w1118-h331-no/Screen%2BShot%2B2015-02-10%2Bat%2B11.29.22%2BPM.png" alt="node.js v0.12.0 page2" /></p>

<p>node.js v0.12.0 TTFB 910ms。</p>

<p><img src="https://lh3.googleusercontent.com/-CePlsRGHndI/VNomzP3ZMzI/AAAAAAAAILc/YlkhDkjRHAY/w1118-h331-no/Screen%2BShot%2B2015-02-10%2Bat%2B11.34.49%2BPM.png" alt="io.js v1.1.0 page2" /></p>

<p>io.js v1.1.0 TTFB 776ms。</p>

<p><img src="https://lh5.googleusercontent.com/-AemhYmtokBw/VNomx8aIBMI/AAAAAAAAILg/3GBjTwsTs1w/w1118-h331-no/Screen%2BShot%2B2015-02-10%2Bat%2B11.30.43%2BPM.png" alt="node.js v0.10.36 page2" /></p>

<p>node.js v0.10.36 TTFB 604ms。</p>

<h3>Page 3</h3>

<p><img src="https://lh3.googleusercontent.com/-sbjgcsYBKEI/VNomvAQ99yI/AAAAAAAAIKw/1kKSgNjzysw/w1118-h331-no/Screen%2BShot%2B2015-02-10%2Bat%2B11.29.37%2BPM.png" alt="node.js v0.12.0 page3" /></p>

<p>node.js v0.12.0 TTFB 221ms。</p>

<p><img src="https://lh4.googleusercontent.com/-D1D5stJUzPg/VNomxwPjWOI/AAAAAAAAILI/Zj_XEEIcOxs/w1118-h331-no/Screen%2BShot%2B2015-02-10%2Bat%2B11.30.51%2BPM.png" alt="node.js v0.10.36 page3" /></p>

<p>io.js v1.1.0 TTFB 217ms。</p>

<p><img src="https://lh3.googleusercontent.com/-ZnrOiohW9VU/VNomzm0vZCI/AAAAAAAAILk/cT8R99I1tJc/w1118-h331-no/Screen%2BShot%2B2015-02-10%2Bat%2B11.35.08%2BPM.png" alt="io.js v1.1.0 page3" /></p>

<p>node.js v0.10.36 TTFB 150ms。</p>

<h3>結論</h3>

<p>每個頁面我都土法重複 reload 過好幾次，大概抓的數字是看到的平均值，想說這樣的測試太土法了，沒參考性，但是三個頁面的測試結果彼此比較後都很相像，所以應該可以說明什麼了吧！</p>

<ul>
<li>node.js v0.12.0 TTFB 1.36s +0%</li>
<li>io.js v1.1.0 TTFB 1.21s +12%</li>
<li>node.js v0.10.36 TTFB 603ms +126%</li>
</ul>


<p>頁面一舊版 node.js v0.10.36 比其他兩頁都快得多！跟 io.js v1.1.0 比起來也快了至少 100%。</p>

<ul>
<li>node.js v0.12.0 TTFB 910ms +0%</li>
<li>io.js v1.1.0 TTFB 776ms +17%</li>
<li>node.js v0.10.36 TTFB 604ms +51%</li>
</ul>


<p>頁面二也是 node.js v0.10.36 最快。</p>

<ul>
<li>node.js v0.12.0 TTFB 221ms +0%</li>
<li>io.js v1.1.0 TTFB 217ms +1.8%</li>
<li>node.js v0.10.36 TTFB 150ms +47%</li>
</ul>


<p>頁面三其實都相差不遠，但 node.js v0.10.36 仍然反應最快。</p>

<p>結論就是……等網站上到遠端 server 之後再來測一次真實網路環境下的 TTFB 吧！以目前在本機測試的結果，還沒有很想更新到 node.js v0.12.0，而且以<a href="http://blog.chh.tw/posts/what-is-iojs-nodejs-forking/">現在這局勢</a>看來 io.js 勢頭很高，再過一段時間來評估直接把專案跳去改用 io.js 算了。:p</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[io.js 是什麼？Node.js 社群分裂事件觀察]]></title>
    <link href="http://blog.chh.tw/posts/what-is-iojs-nodejs-forking/"/>
    <updated>2014-12-07T04:29:00+08:00</updated>
    <id>http://blog.chh.tw/posts/what-is-iojs-nodejs-forking</id>
    <content type="html"><![CDATA[<p><img src="https://lh3.googleusercontent.com/-mDHp26oTCxg/VINpfJZV2ZI/AAAAAAAAIJk/FlmyYl4aRBY/w770-h333-no/Screen%2BShot%2B2014-12-07%2Bat%2B4.38.35%2BAM.png" alt="" /></p>

<p>這個事件已經燒了好幾天，剛開始注意到是 Hacker News 上出現「<a href="https://news.ycombinator.com/item?id=8669557">IO.js – Evented I/O for V8 javascript</a>」這篇推文，我甚至還不曉得到底該寫 IO.js 還是 io.js 比較正確。</p>

<p>整件事情發展詭譎得像 <a href="http://www.imdb.com/title/tt1446714/">Prometheus</a> 的 Elisabeth Shaw 剛發現黑色黏液一樣，不知道到底是希望還是崩壞的開始。最近公司有要用 Node.js 所以我就追了一下新聞，大概統整出來的概況寫了這篇觀察紀錄，或許有些可能有錯麻煩在幫我指正，感謝喔！</p>

<!-- more -->


<h3>故事的序章</h3>

<p>希臘傳說中的巨人族自殺喝下奇怪的黑色黏液來開創人類世界，Node.js 的創建者 <a href="https://github.com/ry">ry</a>（Ryan Dahl） 確實也有點像上帝創世後神龍見首不見尾地消失無蹤，怎麼有種 <a href="http://www.smashingmagazine.com/2010/05/15/why-a-tale-of-a-post-modern-genius/">_why</a> 風格的感覺……都回到真實世界去了嗎（<a href="http://www.imdb.com/title/tt0133093/">The Matrix</a> 梗）？</p>

<p>在 ry <a href="https://groups.google.com/forum/#!topic/nodejs/hfajgpvGTLY">消失</a>之前他把 Node.js 版權賣給了 <a href="https://www.joyent.com/">Joyent</a> 還替他們工作了一陣子，但稍微有點信仰的 developer 都不會喜歡參與的 Open Source 專案跟商業公司扯上關係，這次 io.js 事件主導人之一的 <a href="https://github.com/mikeal">mikeal</a>（Mikeal Rogers）就寫了一篇「<a href="https://medium.com/@mikeal/on-corporate-ownership-of-open-source-786ebd15847e">On Corporate Ownership of Open Source</a>」說出他的想法。</p>

<p>Node.js 有另外兩個非常重要的 core commiter 分別是 <a href="https://github.com/piscisaureus">piscisaureus</a>（Bert Belder）和 <a href="https://github.com/bnoordhuis">bnoordhuis</a>（Ben Noordhuis），他們成立的公司 <a href="http://strongloop.com/">StrongLoop</a> 想要搶奪 Node.js 社群統治權的野心非常強，是 Joyent 最大的兢爭對手，但無奈商標權就是 Joyent 的，StrongLoop 也不能拿他們怎麼辦。</p>

<p>StrongLoop 你就直說吧！你就是想要取代 Joyent 來主導 Node.js 的發展！XD</p>

<h3>分裂的跡象</h3>

<p>Open Source 這回事嘛……就是授權範圍允許，當然可以 fork 一份出去改成自己想要的版本，只是看整個社群願不願意支持而已。我不是很了解 Node.js 核心的開發上，Joyent 是用什麼樣的風格來管理，但顯然有很多 core commiter 不太滿意，從很久之前就出現了分裂的聲音。</p>

<p>Joyent 做為 Node.js 所有者、掌門人也聞到了這個味道，當然不會坐視這種情況不管，因此成立了所謂的 <a href="http://nodejs.org/about/advisory-board/">Advisory Board</a>，目的就是在於廣納所有 Node.js developer 的意見跟想法。</p>

<p>呃，傾聽人民的聲音？但似乎此舉在某些人眼裡看起來就是獨裁者的作秀，實質上沒什麼幫助，所以熱血革命鬥士開始組織 <a href="http://nodeforward.org/">Node Forward</a> 來討論該怎麼「推翻」政府，最後有了今日的 <a href="https://github.com/iojs/io.js/">io.js</a>。</p>

<p>說說看在這之間難道 StrongLoop 的人難道不會煽風點火嗎？:p</p>

<p>Update 2015.01.14：今天 io.js 發佈 1.0.0 版本把整個 Twitter 洗版洗得一塌糊塗，然後我也看到另外一個軼聞，就是 Ben Noordhuis 被當初被 Joyent「驅逐」的原因竟然是因為<a href="https://github.com/joyent/libuv/commit/804d40ee14dc0f82c482dcc8d1c41c14333fcb48">性別歧視用字</a>的問題，也可以<a href="https://github.com/joyent/libuv/pull/1015#issuecomment-29568172">在這裏</a>找到他本人的說法。另一層考量就是 Ben 為 Joyent 競爭對手工作，很難不讓人聯想這是一起政治事件。</p>

<h3>io.js 是什麼？</h3>

<p>io.js 目前在 Github 上的專案位置：<a href="https://github.com/iojs/io.js">https://github.com/iojs/io.js</a></p>

<p>它的前身是 <a href="https://github.com/node-forward/">node-forward</a>/node，也就是 Node Forward 用來抵抗 Joyent 的專案，另一個 Node.js fork 版本，在正式 public release 前醞釀了大概 4 個禮拜左右。</p>

<p>io.js 目的是希望可以讓 Node.js 更加擁抱社群、更自由、更公開、更透明……之類的，而不是被 Joyent「跋扈的專制統治」，其實我也不曉得真實狀況是怎樣。總之，目前的核心成員有原本 Node.js 的重要貢獻者：</p>

<ul>
<li>Fedor Indutny（@indutny）</li>
<li>Trevor Norris（@trevnorris）</li>
<li>Ben Noordhuis（@bnoordhuis）</li>
<li>Isaac Z. Schlueter（@isaacs）</li>
<li>Nathan Rajlich（@TooTallNate）</li>
<li>Bert Belder（@piscisaureus）</li>
</ul>


<p>也有邀請 Advisory Board 大家長 TJ Fontaine（@tjfontaine）但是被婉拒了，劇情超像 <a href="http://www.imdb.com/title/tt3110960/">Jimmy&#8217;s Hall</a> 的神父啊！lol</p>

<h3>賤人就是矯情</h3>

<p>StrongLoop 在 io.js 公諸於世之後發表了「<a href="http://strongloop.com/strongblog/position-on-io-js/">StrongLoop’s Position on io.js</a>」文章，來表示「其實我們還是愛著 Node.js 啦！但如果……」，彷彿是在向 Joyent 下達最後通牒，不好好處理我們就分手吧！</p>

<p>分裂其實對於整個 Node.js 生態系來說絕對是有害無益，但 StrongLoop 的態度就是師馬昭之心。看吧！文末還不忘歌功頌德一下他們自己。</p>

<p>最近常在他們公司網站上看到自我宣傳的文宣，尤其是這次 v0.12 版本當中有很大比例的程式碼是由 StrongLoop 的人 commit 的，那是因為 v0.12 可以視為 v1.0 版本的候選版本，這也意味著在告訴大家 Node.js v1.0 正式版最強力的推動者是我們 StrongLoop 啊！</p>

<p>其實這也沒什麼不好，而且 io.js 給的方向確實就是現在 Node.js 需要處理以及解決的問題，純粹是一種給人的觀感差異罷了。:p</p>

<h3>小結</h3>

<p>「這是個政治問題，需要政治的智慧來解決」，已經無關乎技術。</p>

<p>整個事件對於 Node.js 還是有點影響的，那就是 Joyent 終於<a href="http://blog.nodejs.org/2014/12/03/advisory-board-update/">發佈消息</a>說 v0.12 即將到來，可能也意味著 v1.0 正式版本要隨之釋出，不過……我想這已經無法阻止 io.js 那群人繼續 forking，接下來會如何繼續拭目以待吧！</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Node 樣版引擎評估：Jade、Handlebars]]></title>
    <link href="http://blog.chh.tw/posts/node-template-engine-jade-vs-handlebars/"/>
    <updated>2014-11-29T01:38:00+08:00</updated>
    <id>http://blog.chh.tw/posts/node-template-engine-jade-vs-handlebars</id>
    <content type="html"><![CDATA[<p><img src="https://lh3.googleusercontent.com/-aa-cbFoMPDs/VHi1FfBlM-I/AAAAAAAAIJM/T6wEE0RlEtQ/w640-h201-no/Screen%2BShot%2B2014-11-29%2Bat%2B1.44.09%2BAM.png" alt="" /></p>

<h2>短文版</h2>

<p>用 jade。</p>

<h2>長文版</h2>

<p>因為這個專案效能不會是評估重點，語法設計、擴充性、使用彈性會是比較在意的部分。</p>

<p>活在樣版引擎這個群雄割據的戰國時代實在太多選擇，從各方的評論和簡略地掃描文件上的語法特性，挑出以下幾個我比較喜歡的：</p>

<ul>
<li><a href="https://github.com/tj">TJ</a> 早期樣版引擎代表作 <a href="https://github.com/tj/ejs/">ejs</a></li>
<li>以及 TJ 後來的 <a href="https://github.com/jadejs/jade">jade</a></li>
<li>還有 <a href="https://github.com/wycats">wycats</a>（<a href="http://yehudakatz.com/">Yehuda Katz</a>）的 <a href="https://github.com/wycats/handlebars.js">handlebars</a></li>
</ul>


<p>TJ 當初設計 <a href="http://expressjs.com/">Express</a> 承襲 Ruby micro-framework <a href="http://www.sinatrarb.com/">Sinatra</a> 的設計理念，ejs 好像是因應而生（？），從 ejs 語法上面可以看到非常多 Ruby 樣版引擎 ERb 的影子，對我來說是最「友善」的。不過 TJ 另創 jade 樣版引擎加上投奔 Go 世界以後，ejs 的活躍程度越來越低，從今年 5 月之後就再也沒有更新過了。</p>

<p>我向來都會先以「社群活躍度」來評量一個程式專案計畫可靠度，jade 貢獻者在 Github 上成立 <a href="https://github.com/jadejs">jadejs</a> 組織來維護專案，長久來看蠻可靠的。而 handlebars 在 Github 上也廣受 Javascript 開發者歡迎，所以最後我就拿這兩套樣版引擎來比較，以下是值得提出來講的部分。</p>

<p>（再強調一次好了：語法設計、擴充性、使用彈性是我比較在意的項目）</p>

<!-- more -->


<h3>Layouts</h3>

<p>寫過 Rails 後就很喜歡那種把不同 controller actions 的 view，跟 layouts 拆得乾乾淨淨的做法。這點 handlebars 可以做到，也是我最喜歡的一點，jade 必須在每一個 view 裡面寫上重複的 code，來表示外層的 layout：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='jade'><span class='line'><span class="nt">extends</span> layout
</span><span class='line'>
</span><span class='line'><span class="nt">block</span> content
</span><span class='line'>  <span class="nt">h1</span><span class="p">=</span> <span class="n">post</span><span class="o">.</span><span class="n">title</span>
</span></code></pre></td></tr></table></div></figure>


<p>把內容的部分宣告成 block，然後套進 layout 裏去。這也不是大缺點啦，block 寫法可以讓 view 不同區塊使用上更有彈性，但這就很考驗 block 的拆分功力了，不然真的會很容易寫出大量讓人崩潰的縮進層級。</p>

<h3>Partials</h3>

<p>版型上共用的部分一定會拆出來到同個檔案去維護，例如 header、footer、sidebar 之類的，handlebars 要做到這點繞得也太大圈：得先告訴 handlebars 的實例（instance）某個目錄放著我要的 partials 檔案，例如有個 <code>header.hbs</code> partial 放在 <code>/views/partials</code> 目錄下，然後要在 app 主要程式中寫：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="kd">var</span> <span class="nx">hbs</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;hbs&#39;</span><span class="p">);</span>
</span><span class='line'><span class="nx">hbs</span><span class="p">.</span><span class="nx">registerPartial</span><span class="p">(</span><span class="nx">__dirname</span><span class="p">,</span> <span class="s1">&#39;/views/partials&#39;</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<p>才能在 view 裡面帶入 header 這個 partial：<code>{{&gt; header}}</code>。這樣讓檔案的組織非常缺乏彈性，如果 partials 不是在同個地方而是多個目錄，這樣光是找到檔案就很直覺。</p>

<h3>條件判斷</h3>

<p>這個是壓死駱駝最後一根稻草，handlebars 沒有辦法用很簡單的條件判斷式，內建的 <code>#if</code> helper 根本不是拿來寫「條件判斷」的，當初掃描完文件後一定會很自然地寫下 <code>{{#if query === 'list'}}</code>，這樣是不行的喔！</p>

<p><code>#if</code> 頂多拿來判斷物件裡面有東西還是沒東西而已，如果真要寫個「條件判斷」一樣要拆去寫 helper，不管你的是多簡單的判斷。</p>

<h3>結論</h3>

<p>當初 wycats 寫 handlebars 時主要是為了解決前端樣版引擎的問題，所以可以發現很多 server-side 應用的場景 handlebars 都不適用。jade 是 TJ 寫給 Express 用的，讓我最不適應的地方是像 <a href="http://haml.info/">HAML</a> 那樣「縮進崇拜主義」簡化的語法我實在不敢恭維，但顯然目前沒有比「不習慣」更好的理由來阻止我用它，因為 jade 其他面向提供的 solution 確實都能解決問題。</p>

<p>結論就是用 jade！</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[MongoDB 的 ODM：mongoose 簡單介紹]]></title>
    <link href="http://blog.chh.tw/posts/mongodb-odm-mongoose/"/>
    <updated>2013-09-06T11:11:00+08:00</updated>
    <id>http://blog.chh.tw/posts/mongodb-odm-mongoose</id>
    <content type="html"><![CDATA[<p><img src="https://lh3.googleusercontent.com/-Tdo_5cAPDnk/UilIbkRmleI/AAAAAAAAGqQ/vh6dM2gZvV4/w690-h450-no/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2013-09-06+%25E4%25B8%258A%25E5%258D%258811.12.48.png" alt="mongoose" /></p>

<p><a href="http://mongoosejs.com/">mongoose</a> 是一套給 Node.js 用的 MongoDB ODM，跟常聽到的 ORM 不同的地方只是一些<a href="http://stackoverflow.com/questions/12261866/what-is-the-difference-between-an-orm-and-an-odm">技術名詞定義上的把戲</a>，其實是差不多的意思。</p>

<p>透過 mongoose 可以用包裝過的、更高階的、更直覺的 API 語法，以及模擬 SQL 資料庫 schema-based 的方式，來操作 MongoDB 資料庫。以下是個官方文件給的簡單範例，先建立了一個叫做 Cat 的 Model，<code>model</code> 的第二個參數就是建立 schema 的所在：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="kd">var</span> <span class="nx">Cat</span> <span class="o">=</span> <span class="nx">mongoose</span><span class="p">.</span><span class="nx">model</span><span class="p">(</span><span class="s1">&#39;Cat&#39;</span><span class="p">,</span>
</span><span class='line'>  <span class="p">{</span> <span class="nx">name</span><span class="o">:</span> <span class="nb">String</span> <span class="p">}</span>
</span><span class='line'><span class="p">);</span>
</span><span class='line'>
</span><span class='line'><span class="kd">var</span> <span class="nx">kitty</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Cat</span><span class="p">({</span> <span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;Zildjian&#39;</span> <span class="p">});</span>
</span><span class='line'><span class="nx">kitty</span><span class="p">.</span><span class="nx">save</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">if</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="c1">// ...</span>
</span><span class='line'>  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;meow&#39;</span><span class="p">);</span>
</span><span class='line'><span class="p">});</span>
</span></code></pre></td></tr></table></div></figure>




<!-- more -->


<h2>與 MongoDB 建立連線</h2>

<p>這裡繼續沿用上一篇文章「<a href="http://blog.chh.tw/posts/node-http-vs-connect-vs-express/">Node.js 的 Http vs Connect vs Express</a>」的例子，先把上一篇文章的範例程式碼複製過來，檔案名稱命名為 <em>server.js</em>，下指令執行 <code>node server.js</code> 這樣可以得到一台簡單的伺服器：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="kd">var</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;express&#39;</span><span class="p">)</span>
</span><span class='line'>  <span class="p">,</span> <span class="nx">app</span>     <span class="o">=</span> <span class="nx">express</span><span class="p">()</span>
</span><span class='line'>
</span><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="nx">cookieParser</span><span class="p">())</span>
</span><span class='line'>
</span><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">cookies</span><span class="p">)</span>
</span><span class='line'>  <span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="s1">&#39;hello&#39;</span><span class="p">)</span>
</span><span class='line'><span class="p">})</span>
</span><span class='line'>
</span><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="s1">&#39;4000&#39;</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>打開瀏覽器訪問 <a href="http://localhost:4000">http://localhost:4000</a> 應該可以看到「hello」的文字，從 console 應該也能看到有關 cookies 的資訊（有可能只是一個空的物件）。</p>

<p>再來就是把 mongoose 給 requrie 進來，然後讓它跟 MongoDB 嘗試建立連線，連線的 URL 協議一定要用 <code>mongodb://</code> 這個 prefix：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="kd">var</span> <span class="nx">mongoose</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;mongoose&#39;</span><span class="p">)</span>
</span><span class='line'><span class="nx">mongoose</span><span class="p">.</span><span class="nx">connect</span><span class="p">(</span><span class="s1">&#39;mongodb://localhost/test&#39;</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<h2>mongoose 的兩個概念：Schema 與 Model</h2>

<p>MongoDB 是以 documents 為基礎，在 SQL 資料庫稱為 table 的東西，在 NoSQL 裡稱為 collection。當然，這又是一種名詞定義上的把戲，實質上大同小異。</p>

<h3>Schema</h3>

<p>mongoose 的 Schema 概念就是用 schema-based 的方式，定義一個 collection 的組成結構，用程式碼描述會這樣子寫：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="kd">var</span> <span class="nx">Schema</span> <span class="o">=</span> <span class="nx">mongoose</span><span class="p">.</span><span class="nx">Schema</span>
</span><span class='line'><span class="kd">var</span> <span class="nx">UserSchema</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Schema</span><span class="p">(</span>
</span><span class='line'>  <span class="p">{</span>
</span><span class='line'>    <span class="nx">name</span><span class="o">:</span>      <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="nb">String</span> <span class="p">},</span>
</span><span class='line'>    <span class="nx">login</span><span class="o">:</span>     <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="nb">String</span><span class="p">,</span> <span class="nx">unique</span><span class="o">:</span> <span class="kc">true</span> <span class="p">},</span>
</span><span class='line'>    <span class="nx">email</span><span class="o">:</span>     <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="nb">String</span><span class="p">,</span> <span class="nx">unique</span><span class="o">:</span> <span class="kc">true</span> <span class="p">},</span>
</span><span class='line'>    <span class="nx">create_at</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="nb">Date</span><span class="p">,</span> <span class="k">default</span><span class="o">:</span> <span class="nb">Date</span><span class="p">.</span><span class="nx">now</span> <span class="p">},</span>
</span><span class='line'>    <span class="nx">update_at</span><span class="o">:</span> <span class="p">{</span> <span class="nx">type</span><span class="o">:</span> <span class="nb">Date</span><span class="p">,</span> <span class="k">default</span><span class="o">:</span> <span class="nb">Date</span><span class="p">.</span><span class="nx">now</span> <span class="p">}</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>因為 MongoDB 是 schema-less 相當有彈性，所以如果上面這個 schema 某些「欄位」沒有賦值，那麼在 MongoDB 裡就不會有那個「欄位」。說「欄位」是 SQL 的思維，可是我覺得這樣講會比較好理解。</p>

<h3>Model</h3>

<p>而 mongoose 的 Model 概念，則是對一個 collection 結構定義與操作方法的集合，也就是用 Schema 定義了一個 collection 的結構，加上其他對這個 collection 的驗證設定、操作方法等等，便構成了一個 Model。</p>

<p>結合剛剛的 schema 範例，可以再加上一些驗證跟操作的方法：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="nx">UserSchema</span><span class="p">.</span><span class="nx">pre</span><span class="p">(</span><span class="s1">&#39;save&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">next</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="c1">// do something...</span>
</span><span class='line'><span class="p">})</span>
</span><span class='line'>
</span><span class='line'><span class="nx">UserSchema</span><span class="p">.</span><span class="nx">statics</span> <span class="o">=</span> <span class="p">{</span>
</span><span class='line'>
</span><span class='line'>  <span class="nx">getUserByLogin</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">login</span><span class="p">,</span> <span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="k">this</span><span class="p">.</span><span class="nx">findOne</span><span class="p">({</span> <span class="nx">login</span><span class="o">:</span> <span class="nx">login</span> <span class="p">})</span>
</span><span class='line'>      <span class="p">.</span><span class="nx">exec</span><span class="p">(</span><span class="nx">callback</span><span class="p">)</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>最後將這個 Schema 定義到一個叫做 User 的 model：</p>

<pre><code>mongoose.model('User', UserSchema)
</code></pre>

<p>當要使用這個 model 只要用 <code>mongoose.model()</code> 將 model 讀出來，便可以對他進行操作了：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="kd">var</span> <span class="nx">User</span> <span class="o">=</span> <span class="nx">mongoose</span><span class="p">.</span><span class="nx">model</span><span class="p">(</span><span class="s1">&#39;User&#39;</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'><span class="nx">User</span><span class="p">.</span><span class="nx">getUserByLogin</span><span class="p">(</span><span class="nx">login</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">user</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="c1">// here we have a user...</span>
</span><span class='line'><span class="p">})</span>
</span></code></pre></td></tr></table></div></figure>


<h2>為什麼 Schema-less 的資料庫需要 Schema-based？</h2>

<p>不過這就很奇怪了，NoSQL 的 MongoDB 本身就是 schema-less 的資料庫，結果用 mongoose 還要去刻意模擬成 schema-based，這樣的思路是什麼？</p>

<p>其實這是對 NoSQL 的 schema-less 的誤解，schema-less 並不代表 no-schema。在應用當中還是需要一個 schema 來代表 model，而 schema-less 只是代表一種彈性的模式。</p>

<p>否則的話，會需要在很多地方寫髒亂的判斷條件，像是這樣的東西：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="k">if</span> <span class="p">(</span><span class="nx">cat</span><span class="p">.</span><span class="nx">name</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">cat</span><span class="p">.</span><span class="nx">name</span><span class="p">)</span>  <span class="c1">// I got a name</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Node.js 的 http vs Connect vs Express]]></title>
    <link href="http://blog.chh.tw/posts/node-http-vs-connect-vs-express/"/>
    <updated>2013-09-05T02:17:00+08:00</updated>
    <id>http://blog.chh.tw/posts/node-http-vs-connect-vs-express</id>
    <content type="html"><![CDATA[<p><img src="https://lh5.googleusercontent.com/-mk_3GdVqmSI/Uid55DfCYHI/AAAAAAAAGp4/3mW_vcrS63Q/w690-h450-no/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2013-09-05+%25E4%25B8%258A%25E5%258D%25882.19.28.png" alt="node-express" /></p>

<p>這篇應該是我第一篇寫有關 <a href="http://nodejs.org/">Node.js</a> 的文章，未來應該會開始多寫一些有關 Javascript 的東西。這次主題要來聊聊 Node.js 的 http 模組，跟知名的 Connect 和 Express 之間的關係，如果上網去問，有人會回說就像是 Ruby 的 <a href="http://rack.github.io/">Rack</a> 一樣，但是具體到底是什麼東西呢？</p>

<!-- more -->


<h2>http 模組</h2>

<p>Node.js 自身就帶有一個叫做 http 的 <a href="http://nodejs.org/api/http.html">module</a>，可以呼叫 <code>http.createServe</code> 建立一個相當基本伺服器，具體用法會長得像是以下這個樣子，可以建立一份檔案命名為 <em>server.js</em> 來測試一下：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="kd">var</span> <span class="nx">http</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;http&#39;</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'><span class="nx">http</span><span class="p">.</span><span class="nx">createServer</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="nx">res</span><span class="p">.</span><span class="nx">writeHead</span><span class="p">(</span><span class="mi">200</span><span class="p">)</span>
</span><span class='line'>  <span class="nx">res</span><span class="p">.</span><span class="nx">end</span><span class="p">(</span><span class="s2">&quot;hello world\n&quot;</span><span class="p">)</span>
</span><span class='line'><span class="p">}).</span><span class="nx">listen</span><span class="p">(</span><span class="mi">8000</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>然後在終端機執行 <code>node server.js</code> 指令來啟動伺服器，因為程式碼裡面指定了 8000 port，所以當在瀏覽器裡打開 <a href="http://localhost:8000">http://localhost:8000</a> 看到「hello world」就代表成功了。</p>

<h2>Connect</h2>

<p>然而我需要更多的細節，例如讀取送來的 request 中的 cookies，因此 <a href="http://www.senchalabs.org/connect/">Connect</a> 這樣的 middleware 框架，便是用來輕鬆安插各種 middleware 來處理 request，透過 <code>connect.cookieParser()</code> 讓 <code>req</code> 物件多了一個 <code>cookies</code> 屬性：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="kd">var</span> <span class="nx">http</span>    <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;http&#39;</span><span class="p">)</span>
</span><span class='line'>  <span class="p">,</span> <span class="nx">connect</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;connect&#39;</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'><span class="kd">var</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">connect</span><span class="p">()</span>
</span><span class='line'>  <span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">connect</span><span class="p">.</span><span class="nx">cookieParser</span><span class="p">())</span>
</span><span class='line'>  <span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">cookies</span><span class="p">);</span>
</span><span class='line'>    <span class="nx">res</span><span class="p">.</span><span class="nx">end</span><span class="p">(</span><span class="s1">&#39;hello&#39;</span><span class="p">);</span>
</span><span class='line'>  <span class="p">})</span>
</span><span class='line'>
</span><span class='line'><span class="nx">http</span><span class="p">.</span><span class="nx">createServer</span><span class="p">(</span><span class="nx">app</span><span class="p">).</span><span class="nx">listen</span><span class="p">(</span><span class="mi">8000</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>但是 Connect 充其量只是提供了安插 middleware 的 API，其他像是 route、view rendering 等工作，就會需要靠 Express 這套框架了。</p>

<h2>Express</h2>

<p><a href="http://expressjs.com/">Express</a> 其實就是延伸自 Connect 的加強版，所有 Connect 的 API 在 Express 裡都可以使用，並且提供了更多實用的 functions，一次解決所有問題。</p>

<p>將剛剛寫的程式碼修改成以下的範例，其中 <code>get</code> 這個 function 就是 HTTP 的動詞，有了這樣的 API 便能很輕鬆地策劃路由了：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="kd">var</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;express&#39;</span><span class="p">)</span>
</span><span class='line'>  <span class="p">,</span> <span class="nx">app</span>     <span class="o">=</span> <span class="nx">express</span><span class="p">()</span>
</span><span class='line'>
</span><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="nx">cookieParser</span><span class="p">())</span>
</span><span class='line'>
</span><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">cookies</span><span class="p">)</span>
</span><span class='line'>  <span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="s1">&#39;hello&#39;</span><span class="p">)</span>
</span><span class='line'><span class="p">})</span>
</span><span class='line'>
</span><span class='line'><span class="nx">app</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="s1">&#39;4000&#39;</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>一言以蔽之，http 之於 Connect，就如 Connect 之於 Express。</p>

<h3>參考資料</h3>

<ul>
<li><a href="http://stackoverflow.com/questions/5284340/what-is-node-js-connect-express-and-middleware">What is Node.js&#8217; Connect, Express and “middleware”?</a></li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[劣以為的 OOCSS 和 SMACSS 以及其他 CSS 規範]]></title>
    <link href="http://blog.chh.tw/posts/oocss-smacss-and-css-guidelines/"/>
    <updated>2013-08-05T10:40:00+08:00</updated>
    <id>http://blog.chh.tw/posts/oocss-smacss-and-css-guidelines</id>
    <content type="html"><![CDATA[<p>真心覺得寫出 CSS 並不難，但是要寫出可被維護的 CSS 比其他程式語言都還難。所幸已經有許多大師級的人物，提出許多設計模式和思維，藉由站在巨人的肩膀上可以讓事情事半功倍。這篇文章就來說說 OOCSS、SMACSS 和撰寫 CSS 時應該注意的規範。</p>

<p>（本文的例子用的是 SCSS 語法）</p>

<!-- more -->


<h2>OOCSS</h2>

<p>OOCSS 不是什麼新技術，只是一種撰寫 CSS 的設計模式，或者可以說是一種「道德規範」，大致上我覺得重點只有兩個：</p>

<ul>
<li><a href="#html-dependency">減少對 HTML 結構的依賴</a></li>
<li><a href="#reuse-classes">增加 CSS class 重複性的使用</a></li>
</ul>


<p><a name="html-dependency"></a></p>

<h3>減少對 HTML 結構的依賴</h3>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt">&lt;nav</span> <span class="na">class=</span><span class="s">&quot;nav--main&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>  <span class="nt">&lt;ul&gt;</span>
</span><span class='line'>    <span class="nt">&lt;li&gt;&lt;a&gt;</span>.........<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
</span><span class='line'>    <span class="nt">&lt;li&gt;&lt;a&gt;</span>.........<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
</span><span class='line'>    <span class="nt">&lt;li&gt;&lt;a&gt;</span>.........<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
</span><span class='line'>  <span class="nt">&lt;/ul&gt;</span>
</span><span class='line'><span class="nt">&lt;/nav&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>一般的導航欄寫法，結構應該會像上面的 HTML 範例一樣，如果要對那些 <code>&lt;a&gt;</code> 標籤定義樣式，CSS 的寫法可能寫成 <code>.nav--main ul li a {}</code>，這種寫法先不管效能上的問題，可以看出來過度地依賴元素標籤的結構，有可能之後 HTML 結構改變，這個 CSS 就必須跟著重構，造成維護上多餘的成本。</p>

<p>若從這個例子來考量，原則上 <code>&lt;a&gt;</code> 都一定會接在 <code>&lt;li&gt;</code> 標籤的後面，一個 <code>&lt;li&gt;</code> 只會有一個 <code>&lt;a&gt;</code>，通常不會獨立存在，那就可以寫成 <code>.nav--main a {}</code>，會是比較好的寫法，甚至是直接給 <code>&lt;a&gt;</code> 加上 class <code>nav--main_item</code>。後者是 OOCSS 所提倡的用法。</p>

<p>這樣的寫法，一來效能理論上比較好（我沒辦法驗證），二來層次比較單純。</p>

<p><a name="reuse-classes"></a></p>

<h3>增加 CSS class 的重複使用</h3>

<p>在 OOCSS 的觀念中，強調重複使用 class，而應該避免使用 id 作為 CSS 的選擇器。這種想法就是像 <a href="https://en.wikipedia.org/wiki/Object-oriented_programming">OOP</a> 盡量抽離重複的程式碼，例如以下這個例子，這是兩種按鈕的 CSS 樣式屬性：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='scss'><span class='line'><span class="nc">.button</span> <span class="p">{</span>
</span><span class='line'>  <span class="na">display</span><span class="o">:</span> <span class="no">inline</span><span class="o">-</span><span class="no">block</span><span class="p">;</span>
</span><span class='line'>  <span class="na">padding</span><span class="o">:</span> <span class="mi">6</span><span class="kt">px</span> <span class="mi">12</span><span class="kt">px</span><span class="p">;</span>
</span><span class='line'>  <span class="na">color</span><span class="o">:</span> <span class="nf">hsla</span><span class="p">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">100</span><span class="kt">%</span><span class="o">,</span> <span class="mi">100</span><span class="kt">%</span><span class="o">,</span> <span class="mi">1</span><span class="p">);</span>
</span><span class='line'>  <span class="k">&amp;</span><span class="nc">.button-default</span> <span class="p">{</span> <span class="na">background</span><span class="o">:</span> <span class="nf">hsla</span><span class="p">(</span><span class="mi">180</span><span class="o">,</span> <span class="mi">1</span><span class="kt">%</span><span class="o">,</span> <span class="mi">28</span><span class="kt">%</span><span class="o">,</span> <span class="mi">1</span><span class="p">);</span> <span class="p">}</span>
</span><span class='line'>  <span class="k">&amp;</span><span class="nc">.button-primary</span> <span class="p">{</span> <span class="na">background</span><span class="o">:</span> <span class="nf">hsla</span><span class="p">(</span><span class="mi">208</span><span class="o">,</span> <span class="mi">56</span><span class="kt">%</span><span class="o">,</span> <span class="mi">53</span><span class="kt">%</span><span class="o">,</span> <span class="mi">1</span><span class="p">);</span> <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>上面的 CSS 將兩種不同樣式的 button，抽離出重複的部份，並且定義在同個 class 上。因此，要使用這樣的樣式，HTML 的寫法可能長這個樣子：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt">&lt;a</span> <span class="na">class=</span><span class="s">&quot;button button-default&quot;</span><span class="nt">&gt;</span>
</span><span class='line'><span class="nt">&lt;a</span> <span class="na">class=</span><span class="s">&quot;button button-primary&quot;</span><span class="nt">&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>先用 <code>button</code> 宣告此為一個按鈕的樣式，再用 <code>button-default</code> 或 <code>button-primary</code> 作為按鈕底色的區別。這麼做可以維護成本變得比較低，例如：想要改網站上所有按鈕的大小，就只要修改 <code>.button</code> 的 <code>padding</code> 而已。</p>

<h2>SMACSS</h2>

<p>我對 SMACSS 的理解還不是很深入，或許把 <a href="http://smacss.com/">Scalable and Modular Architecture for CSS</a> 看完後會有更深一曾的理解。目前對 SMACSS 的概念僅限於它對 CSS 不同的業務邏輯所做的劃分方式：</p>

<p>但我認為原本的設計不是很妥當，因此我自己做了一些改良：</p>

<ul>
<li><a href="#base">Base</a></li>
<li><a href="#layout">Layout</a></li>
<li><a href="#module">Module</a></li>
<li><a href="#partial">Partial</a></li>
<li><a href="#state">State</a></li>
<li><a href="#theme">Theme</a></li>
</ul>


<p><a name="base"></a></p>

<h3>Base</h3>

<p>Base 就是設定標籤元素的預設值，例如瀏覽器的 reset 可以寫在這裡，如果用的是 Compass，只要 <code>@include global-reset</code> 即可。這裡只會對標籤元素本身做設定，不會出現任何 class 或 id，但是可以有屬性選擇器或是偽類：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='scss'><span class='line'><span class="nt">html</span> <span class="p">{}</span>
</span><span class='line'><span class="nt">input</span><span class="o">[</span><span class="nt">type</span><span class="o">=</span><span class="nt">text</span><span class="o">]</span> <span class="p">{}</span>
</span><span class='line'><span class="nt">a</span><span class="nd">:hover</span> <span class="p">{}</span>
</span></code></pre></td></tr></table></div></figure>


<p><a name="layout"></a></p>

<h3>Layout</h3>

<p>Layout 是指整個網站的「大架構」的外觀，而非 <code>.button</code> 這種小元件的 class。網站通常會有一些主要的大區塊，可能是 header 或 footer，Layout 就是用來定義這些「大架構」的 CSS。如果有做 Responsive Web Design 或是用 Grid System，也是把規則寫在 Layout 這裡。</p>

<p>以下這是個範例：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='scss'><span class='line'><span class="nn">#header</span> <span class="p">{</span> <span class="na">margin</span><span class="o">:</span> <span class="mi">30</span><span class="kt">px</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span>
</span><span class='line'><span class="nn">#articles-wrapper</span> <span class="p">{</span> <span class="nc">......</span><span class="o">;</span> <span class="p">}</span>
</span><span class='line'><span class="nc">.sidebar</span> <span class="p">{</span>
</span><span class='line'>  <span class="k">&amp;</span><span class="nc">.sidebar--right</span> <span class="p">{</span> <span class="nc">......</span><span class="o">;</span> <span class="p">}</span>
</span><span class='line'>  <span class="k">&amp;</span><span class="nc">.sidebar-left</span> <span class="p">{</span> <span class="nc">......</span><span class="o">;</span> <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>通常只有一個選擇器，一個 id、或一個 class。</p>

<p><a name="module"></a></p>

<h3>Module</h3>

<p>原本的 SMACSS 對 Module 的設計我覺得不是很好，所以我硬是將 Module 拆分出一個 <a href="#partial">Partial</a>。</p>

<p>這裡的 Module 顧名思義，就是可以在其他地方被重複使用，如果要找更明確的例子，我想就像 Twitter Bootstrap 的 <a href="http://getbootstrap.com/2.3.2/components.html">Components</a> 一樣，或者像前面 OOCSS 所舉例的 <code>.button</code> 這種會被重複使用的元件模組。</p>

<p>模組不需要用任何的 prefix，因為 Module 就是設計來可以重複應用在不同的 page 上。</p>

<h3>Partial</h3>

<p><a name="partial"></a></p>

<p>Partial 跟 Latout 不同，也跟 Module 不同，他比 Layout 的範圍小，可能是 header 底下的某個子元素。他不像 Module，他是特定單一領域下特別的設定。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='scss'><span class='line'><span class="nc">.nav--main</span> <span class="p">{</span>
</span><span class='line'>  <span class="nt">a</span> <span class="p">{</span> <span class="nc">......</span><span class="o">;</span> <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>通常會將 Partial 的名稱加在子 class 作為 prefix，例如 <code>.nav--main</code> 底下的 <code>.nav--main_item</code>。至於為什麼要用這麼奇怪的命名方式？這等等在 <a href="#bem">CSS 規範</a>部分會說明介紹。</p>

<p><a name="state"></a></p>

<h3>State</h3>

<p>State 負責定義元素不同的狀態下，所呈現的樣式。但是並非指一個元素的 <code>:hover</code> 或 <code>:active</code> 下的狀態。舉例來說，一個導航欄分頁，目前所在頁面的分頁需要加上 <code>.active</code> 的屬性表示目前位置是在這個分頁，HTML 會長這樣：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt">&lt;nav</span> <span class="na">class=</span><span class="s">&quot;nav--main&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>  <span class="nt">&lt;ul&gt;</span>
</span><span class='line'>    <span class="nt">&lt;li&gt;&lt;a&gt;</span>.........<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
</span><span class='line'>    <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">&quot;active&quot;</span><span class="nt">&gt;&lt;a&gt;</span>.........<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
</span><span class='line'>    <span class="nt">&lt;li&gt;&lt;a&gt;</span>.........<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
</span><span class='line'>  <span class="nt">&lt;/ul&gt;</span>
</span><span class='line'><span class="nt">&lt;/nav&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>因此可以替 <code>.nav--main</code> 增加 <code>.active</code> 這樣的子 class：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='scss'><span class='line'><span class="nc">.nav--main</span> <span class="p">{</span>
</span><span class='line'>  <span class="c1">// others…;</span>
</span><span class='line'>  <span class="nc">.active</span> <span class="p">{</span>
</span><span class='line'>    <span class="na">background</span><span class="o">:</span> <span class="nf">darken</span><span class="p">(</span><span class="nv">$background-color</span><span class="o">,</span> <span class="mi">16</span><span class="kt">%</span><span class="p">);</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>有時候為了讓閱讀更貼近語義，會用比較友善的命名方式，以此段的範例來說，<code>.is-active</code> 就比 <code>.active</code> 來得好讀。</p>

<p><a name="theme"></a></p>

<h3>Theme</h3>

<p>Theme 是畫面上所有「主視覺」的定義，例如 <code>border-color</code>、<code>background-image</code> 或是 <code>font-family</code> 等相關的 Typography 設定。為什麼說是「主視覺」？因為有些元件模組仍然是留在 Module 去定義，Theme 就像 Layout 一樣負責「大架構」上的視覺樣式。</p>

<h2>CSS 規範</h2>

<p>這裡整理的是我覺得一定要知道的，其他還有很多規範可以轉到文末的參考資源連結，那篇文章有介紹更多的細節。</p>

<p><a name="bem"></a></p>

<h3>BEM</h3>

<p>BEM 即 Block、Element、Modifier 的縮寫，這是一種 class 的命名技巧。如果整個 project 只有自己一個人做，那當然是不太可能出現 class 重複的問題，但是如果同時多個 F2E 一起寫同個部分的 CSS，就很容易出現共用 class 的問題，因此有了 BEM 這樣的命名技巧。</p>

<p>將 Block 區塊作為起始開頭，像前面 SMACSS 介紹的 Partial 就可以拿來作為 Block 的 prefix 名稱；Element 則是 Block 下的元素；Modifier 則是這個元素的屬性。</p>

<p>不同 Block 和 Element 用 <code>__</code> 兩個底線區隔開來，不同的 Modifier 則用 <code>--</code> 兩個 dash 區隔。至於 <code>-</code> 一個 dash 則表示這個 class 不依賴任何 Block 或 Element，是個獨立的存在，例如：<code>.page-container</code> 或 <code>.article-wrapper</code>。</p>

<p>這裡有個範例：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='scss'><span class='line'><span class="nc">.sidebar</span> <span class="p">{</span>
</span><span class='line'>  <span class="nc">.sidebar--left__section</span> <span class="p">{</span>
</span><span class='line'>    <span class="nc">.sidebar--left__section--header</span> <span class="p">{}</span>
</span><span class='line'>    <span class="nc">.sidebar--left__section--footer</span> <span class="p">{}</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<h3>Javascript Hook</h3>

<p>透過 CSS class 來作為 Javascript 選取 DOM 節點的方式，就是 Javascript Hook。用 jQuery 可以常常看到這樣的寫法：<code>$('.nav--main a')</code>，可是當 CSS 跟 Javascript 攪在一起反而造成兩邊維護上的不便，當改了 CSS 時 Javascript 也要跟著改。</p>

<p>所以用 HTML 的屬性去選取 DOM 節點會更好，如果非要用 CSS 的 class 那也可以多寫一個 <code>js-</code> 的 prefix，以表示這個節點有被 Javascript 使用，例如：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">&quot;nav--main__item  js-nav--main__item&quot;</span><span class="nt">&gt;&lt;a&gt;</span>.........<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
</span><span class='line'><span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">&quot;nav--main__item  js-nav--main__item&quot;</span><span class="nt">&gt;&lt;a&gt;</span>.........<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
</span><span class='line'><span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">&quot;nav--main__item  js-nav--main__item&quot;</span><span class="nt">&gt;&lt;a&gt;</span>.........<span class="nt">&lt;/a&gt;&lt;/li&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>PS. HTML 裡兩個 class 之間用兩個空格，會比一個空格看起來好閱讀。</p>

<h3>合理的選擇器</h3>

<blockquote><p>class 無所謂是否語意化的問題；你應該關注它們是否合理，不要刻意強調 class 名稱要符合語意，而要注重使用的合理性與未來性。</p></blockquote>

<p>有時候為了表示更明確，在使用 CSS 的選擇器時，要表示某的 class 是搭配某個標籤元素使用，會寫成這樣：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='css'><span class='line'><span class="nt">ol</span><span class="nc">.breadcrumb</span><span class="p">{}</span>
</span><span class='line'><span class="nt">p</span><span class="nc">.intro</span><span class="p">{}</span>
</span><span class='line'><span class="nt">ul</span><span class="nc">.image-thumbs</span><span class="p">{}</span>
</span></code></pre></td></tr></table></div></figure>


<p>但是上面這個寫法效能不是很好，同樣的目的但可以減少多餘的修飾，試試改用下面這種寫法，將標籤名稱用註解標示起來，維護上有相同的效果，但是瀏覽器處理的速度會比較快：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='css'><span class='line'><span class="c">/*ol*/</span><span class="nc">.breadcrumb</span><span class="p">{}</span>
</span><span class='line'><span class="c">/*p*/</span><span class="nc">.intro</span><span class="p">{}</span>
</span><span class='line'><span class="c">/*ul*/</span><span class="nc">.image-thumbs</span><span class="p">{}</span>
</span></code></pre></td></tr></table></div></figure>


<h2>參考資源</h2>

<ul>
<li><a href="https://github.com/doggy8088/CSS-Guidelines">撰寫可管理、可維護的 CSS 高階技巧</a></li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[每個人都應該有一套自己的密碼演算法]]></title>
    <link href="http://blog.chh.tw/posts/my-password-algorithm/"/>
    <updated>2013-06-29T16:06:00+08:00</updated>
    <id>http://blog.chh.tw/posts/my-password-algorithm</id>
    <content type="html"><![CDATA[<p><img src="https://lh4.googleusercontent.com/-XJ2BlPNnueY/Uc7GM1tq0bI/AAAAAAAAGgM/EDQev1B22wU/s690/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7%25202013-06-29%2520%25E4%25B8%258B%25E5%258D%25887.32.00.png" alt="the-matrix" /></p>

<p>最近有位朋友的 Facebook 帳號第二次被盜，然後一堆人被他加進一些討厭又奇怪的團購社團，那位朋友也是尷尬又無奈，所以我就教他一些我設定密碼的「演算法」，聊天內容很多，我就順便整理到部落格來分享，希望對其他人有用。</p>

<p>在設定密碼前應該要有個基本認識，就是這個密碼可能對於你媽而言是保密的，但是在<del>室友</del>駭客面前、或是網站管理員面前，它是透明毫無隱藏的，所以在這前提下就不應該把每個網站全部設同個密碼，因為駭客可以拿這套帳號密碼去登入其他網站。</p>

<h2>密碼演算法</h2>

<p>但是每個網站密碼都不一樣怎麼記得住？所以需要一套「演算法」，以後只需要記憶這套算法，而不是去記密碼。「演算法」聽起來好像很神奇，其實只是一套組合的方法，隨便舉例：</p>

<blockquote><p>網站分級變數 + 常數 + 網站辨識代號 = 密碼</p></blockquote>

<p>以下來分別說明這些東西是什麼。</p>

<!-- more -->


<h3>網站分級變數</h3>

<p>網站分級是指依照網站的重要性分類，並且替每個級別設定不同的密碼。最核心的網站通常是信箱服務，例如 Google、Yahoo，你應該替他們設定一個獨立的密碼，與那些亂七八糟的小網站區隔開來。</p>

<p>那應該拿什麼來當變數？我的建議是，你可以選你最愛顏色的 16 進位色碼（如果你偏愛 HSL 也行…… :p），或是圓周率小數點後的第 108 位數到 116 位數（前提是你得背起來 XDD），又或者是一句名言每個字的開頭第一個字母，例如「<em>Why join the navy if you can be a pirate</em>」變成「<em>Wjtniycbap</em>」。</p>

<p>將網站依照重要性分成三種等級，並且每種等級分配一種變數：</p>

<ul>
<li>核心（Google&#8230;）：<em>Wjtniycbap</em></li>
<li>次等（Evernote&#8230;）：<em>bion</em></li>
<li>下等（亂七八糟論壇&#8230;）：<em>wwantm</em></li>
</ul>


<p>太多不好記？寫下來也沒關係，反正別人猜不到你的算法，給他看也沒關係，只要別在紙上寫「這是密碼」就好了。不過，用不著分類太多，三種級別其實也不難記。</p>

<h3>常數</h3>

<p>這是一組夾雜在密碼裡不會改變的常數，主要目的是增加密碼整體的複雜度。最好是數字跟英文的混合，甚至大小寫混合都可以。綜合上一個變數，現在密碼變成了：</p>

<ul>
<li>核心（Google&#8230;）：<em>Wjtniycbap</em> + <em>0rz</em></li>
<li>次等（Evernote&#8230;）：<em>bion</em> + <em>0rz</em></li>
<li>下等（亂七八糟論壇&#8230;）：<em>wwantm</em> + <em>0rz</em></li>
</ul>


<h3>網站辨識代號</h3>

<p>這是這個網站的獨有特徵，可以是這個網站 domain 名稱的變體，例如 Google 的偶數字母：oge；或是該字母在 26 個字母當中的索引位置，o 是第 15 個字母、g 是第 7 個、e 是第 5 個，合起來就是 1575。</p>

<p>最後，我們的密碼就變成了這樣：</p>

<ul>
<li>核心（Google&#8230;）：<em>Wjtniycbap0rz</em> + <em>oge</em></li>
<li>次等（Evernote&#8230;）：<em>bion0rz</em> + <em>vro</em></li>
<li>下等（亂七八糟論壇&#8230;）：<em>wwantm0rz</em> + <em>xxx</em></li>
</ul>


<p>這樣就能產生每個網站都不一樣的密碼，而且不同級別的網站也不會彼此影響到。密碼不是背起來的，而是推理出來的。很酷！也很宅，對吧？</p>

<h3>還有些事情必須知道</h3>

<ul>
<li>正妹說會經常換密碼的男人最性感，你可以定期更改「網站分級變數」這個部分，或是修改整套算法。</li>
<li>網站分級不是依你常去的網站來劃分（我知道你常去那種網站，但你也要知道那種網站一定會偷你的密碼），而是這個網站不可被攻破的重要性來區別。</li>
<li>越重要的核心服務建議啟用多一點的認證機制，例如 Google、Facebook 都有提供手機簡訊的登入認證機制，請一定要啟用它。</li>
<li>可以變化的不是只有密碼，不同網站當然也可以使用不同的帳號。如果有些網站是「只使用一次」性質的網站，可以多多利用 <a href="http://10minutemail.com/">10 Minute Mail</a> 這個服務。</li>
<li>依賴算法其實也有些缺點，例如網路銀行的密碼通常會硬性規定要 8 個字元，迫使我必須要另外想一個特例的密碼給網路銀行，下場就是我從來記不住我網路銀行的密碼是什麼。:p</li>
</ul>


<h2>關於密碼管理工具</h2>

<p>儘管現在很多人喜歡用 <a href="http://keepass.info/">KeePass</a> 和 <a href="http://lastpass.com/">LastPass</a> 這類的軟體，但我始終不是很信任這類軟體，也不喜歡用。況且……人類發明了機器，並且替機器上了鎖，卻又用了另外一台機器來管理這把鎖，然後又替這台機器上了另外一把鎖，還真是有趣？要是這把鎖掉了，那就真的全面失控了啊！</p>

<p>再說……連<a href="http://youtu.be/VRCUpXLguHM?t=36m6s">駭客都說不敢用</a>了，你敢用嗎？XDD</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[OS X 與 Windows 切換應用程式的介面體驗]]></title>
    <link href="http://blog.chh.tw/posts/osx-windows-switch-applications-ux/"/>
    <updated>2013-06-10T15:39:00+08:00</updated>
    <id>http://blog.chh.tw/posts/osx-windows-switch-applications-ux</id>
    <content type="html"><![CDATA[<p>用了好一陣子 OS X 回頭去用 Windows，發現有好多不習慣，除了主要的功能鍵 <kbd>Ctrl</kbd> 跑到鍵盤邊緣去了（OS X 主要功能鍵 <kbd>Command</kbd> 就在空白鍵旁邊比較近），手指頭常常按錯之外，最近在整理硬碟資料夾的時候又被一個小小的切換視窗功能給煩到。</p>

<p>常用電腦的人一定都很熟悉 Ctrl + Tab 這個功能，可以快速在不同視窗之間切換，可是在 Windows 下當我使用這個功能時，給我的介面是這樣的：</p>

<p><img src="https://lh5.googleusercontent.com/-izHKKLQ5a8Q/UbWDPvs5uiI/AAAAAAAAGY4/FiR5NnVj9Ys/s592/switch-windows.png" alt="windows-switching-windows" /></p>

<p>主要是一個視窗縮圖，和一個小小的應用程式 icon 塞在右下角，辨識度非常地差，我很難一眼就快速認出哪個視窗是我要切換的應用程式。再來看看 OS X 切換視窗的介面：</p>

<!-- more -->


<p><img src="https://lh3.googleusercontent.com/-DDB7DNKyzHU/UbWDQdjQICI/AAAAAAAAGZM/uPy8c1vtHug/s690/osx-switch-apps.png" alt="osx-switching-windows" /></p>

<p>清楚的應用程式 icon 辨別度非常的強，我一眼就能看出哪個應用程式是我想要切換過去的。這裡也能說明一個應用程式的 icon 設計也是很重要，不需要特別的華麗只需要留下足夠的印象，讓人很容易辨識。</p>

<p>順便分享一下我的 Chrome 常用書籤長這樣，也是靠清楚的 icon 來做為辨識：</p>

<p><img src="https://lh6.googleusercontent.com/-lsfa98IeCCA/UbWLW0EBq8I/AAAAAAAAGZ4/foancUbzS2M/s690/chrome-bookmarks.jpg" alt="chrome-bookmarks" /></p>

<p>但是我在整理 Windows 那台電腦硬碟時，遇到最惱人的狀況其實是這個，同一個應用程式都是長得差不多的縮圖：</p>

<p><img src="https://lh6.googleusercontent.com/-7iT_R82qZL4/UbWDPgCeZ7I/AAAAAAAAGZE/NT9pARWEpBU/s690/switch-windows-2.png" alt="windows-switching-windows-2" /></p>

<p>這樣我完全不知道到底該切到哪一個視窗，而 Windows 下好像也沒有類似 <kbd>Command</kbd> + <kbd>`</kbd> 的功能。如果是 OS X 下，還可以用 Mission Control 或是 Expose 等方式，方便地在不同視窗之間做選擇，這部份 Windows 的介面體驗就做得讓人很難受。</p>

<p>好在我現在只是要整理資料夾，以前我有玩過不少檔案總管的視窗管理軟體，可是介面都做得很宅（不友善）。OS X 上我現在用的是 <a href="http://www.trankynam.com/xtrafinder/">XtraFinder</a> 這套模擬 Chrome 的標籤介面，看起來相當簡潔，外觀長這樣：</p>

<p><img src="https://lh5.googleusercontent.com/-7IbTgHfR58s/UbWGHC3jXwI/AAAAAAAAGZc/RbgfKBfGgGM/s690/osx-xfinder.png" alt="osx-xfinder" /></p>

<p>所以我也想要在 Windows 上，找一個相似風格的視窗管理軟體，後來找到了 <a href="http://cn.ejie.me/">Clover 3</a> 用起來還不錯，還有類似書籤的功能，可惜我覺得有點雞肋就是了，外觀長這樣：</p>

<p><img src="https://lh6.googleusercontent.com/-K5h38CcBicI/UbWDPuGCQsI/AAAAAAAAGZA/8MybmGE3WCM/s690/cover-3.PNG" alt="windows-cover-3" /></p>

<p>題外話，我現在已經漸漸不太用 <kbd>Command</kbd> + <kbd>Tab</kbd> 的方式切換應用程式，而是改用 <a href="http://www.alfredapp.com/">Alfred</a> 這套軟體直接輸入應用程式名稱關鍵字來切換，因為有時候程式開得太多，一直 <kbd>Tab</kbd>、<kbd>Tab</kbd>、<kbd>Tab</kbd> 也是很煩的。XD</p>

<p>過幾天，有空來寫一篇介紹一些 mouseless 操作電腦的方法好了。:)</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[更好用的 Vim 外掛管理工具：Vundle]]></title>
    <link href="http://blog.chh.tw/posts/vim-vundle/"/>
    <updated>2013-05-25T16:38:00+08:00</updated>
    <id>http://blog.chh.tw/posts/vim-vundle</id>
    <content type="html"><![CDATA[<p><img src="https://lh4.googleusercontent.com/-_0FBYCCvjPU/UaB5LuYVrWI/AAAAAAAAGXY/ewSOLLQ8_xU/s690/vim-vundle.png" alt="vim-vundle" /></p>

<p>先前曾經寫過怎麼使用 <a href="http://blog.chh.tw/posts/vim-plugins-manager-pathogen/">Pathogen</a> 管理 Vim 的外掛，Git 的 submodule 用久了開始覺得很不方便，有時候只是要測試一下新玩具，用完就刪掉，可是<a href="http://blog.chh.tw/posts/git-submodule/">前後要操作的指令</a>至少超過四個，實在有夠麻煩。</p>

<p>正打算來寫個 script 自動化過程，但這種東西怎麼可能沒人寫過，於是上網找了一下，被我發現 <a href="https://github.com/gmarik/vundle">Vundle</a> 這個管理工具，看完 README 後馬上就把 Pathogen 刪掉了，然後寫了這篇文章。XD</p>

<!-- more -->


<h2>Vundle 的優點</h2>

<ul>
<li>可以保持 git repo 的簡潔</li>
<li>讓安裝/更新/刪除外掛更方便</li>
</ul>


<p>需要參考的話，可以看我放在 <a href="https://github.com/chinghanho/.dotfiles/blob/4c53d90d3e1efffb3fdc1ebc44bdac1781154b19/.vimrc#L1-L39">Github 上的 <em>.vimrc</em></a> 範例。</p>

<h3>保持 git repo 的簡潔</h3>

<p>透過 Vundle 管理外掛我不再需要讓 git 追蹤 <em>.vim/bundle/</em> 目錄，甚至連 Vundle 本身也不用追蹤，只要在 <em>.vimrc</em> 裡這樣寫：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='vim'><span class='line'><span class="k">let</span> iCanHazVundle<span class="p">=</span><span class="m">1</span>
</span><span class='line'><span class="k">let</span> vundle_readme<span class="p">=</span>expand<span class="p">(</span><span class="s1">&#39;~/.vim/bundle/vundle/README.md&#39;</span><span class="p">)</span>
</span><span class='line'><span class="k">if</span> <span class="p">!</span>filereadable<span class="p">(</span>vundle_readme<span class="p">)</span>
</span><span class='line'>  echo <span class="s2">&quot;Installing Vundle..&quot;</span>
</span><span class='line'>  echo <span class="s2">&quot;&quot;</span>
</span><span class='line'>  <span class="k">silent</span> <span class="p">!</span><span class="k">mkdir</span> <span class="p">-</span><span class="k">p</span> <span class="p">~</span><span class="sr">/.vim/</span>bundle
</span><span class='line'>  <span class="k">silent</span> <span class="p">!</span>git clone https:<span class="sr">//</span>github.<span class="k">com</span><span class="sr">/gmarik/</span>vundle <span class="p">~</span><span class="sr">/.vim/</span>bundle/vundle
</span><span class='line'>  <span class="k">let</span> iCanHazVundle<span class="p">=</span><span class="m">0</span>
</span><span class='line'><span class="k">endif</span>
</span></code></pre></td></tr></table></div></figure>


<p>這樣一來，啟動 Vim 的時候就會自動去檢查 Vundle 安裝了沒，因此可以在 <em>.gitignore</em> 裡把 <em>bundle</em> 目錄直接忽略掉，不用再拖著一坨外掛跟著跑了。XD</p>

<h3>安裝/更新/刪除外掛更方便</h3>

<p>安裝、更新外掛是同一條指令，在 <em>.vimrc</em> 裡加上外掛的 Github 的作者名和 repo 名稱，像這樣：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='vim'><span class='line'>Bundle <span class="s1">&#39;Lokaltog/vim-easymotion&#39;</span>
</span><span class='line'>Bundle <span class="s1">&#39;Lokaltog/vim-powerline&#39;</span>
</span><span class='line'>Bundle <span class="s1">&#39;airblade/vim-gitgutter&#39;</span>
</span><span class='line'>Bundle <span class="s1">&#39;Townk/vim-autoclose&#39;</span>
</span><span class='line'>Bundle <span class="s1">&#39;kien/ctrlp.vim&#39;</span>
</span></code></pre></td></tr></table></div></figure>


<p>然後下指令 <code>:BundleInstall</code>，Vundle 會去搜尋對應的 repo，如果已經下載過便會檢查有沒有更新。要移除也很簡單，只要把該外掛那行刪掉或是註解掉，重新下一次指令就行了。</p>

<p>Vim 的外掛腳本基本上都可以在 <a href="http://vim-scripts.org/vim/scripts.html">vim-scripts.org</a> 搜尋到，如果沒有 host 在 Github 上也可以直接輸入該外掛的名稱，例如這樣：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='vim'><span class='line'>Bundle <span class="s1">&#39;L9&#39;</span>
</span><span class='line'>Bundle <span class="s1">&#39;FuzzyFinder&#39;</span>
</span></code></pre></td></tr></table></div></figure>


<p>若是該外掛放在別的 git 主機上，也可以丟 git URL，Vundle 會很聰明地判斷該去哪裡抓：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='vim'><span class='line'>Bundle <span class="s1">&#39;git://git.wincent.com/command-t.git&#39;</span>
</span></code></pre></td></tr></table></div></figure>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Git Submodule 用法筆記]]></title>
    <link href="http://blog.chh.tw/posts/git-submodule/"/>
    <updated>2013-04-11T12:57:00+08:00</updated>
    <id>http://blog.chh.tw/posts/git-submodule</id>
    <content type="html"><![CDATA[<p><img class="center" src="https://lh3.googleusercontent.com/-FDLtETH15RA/UWZCV-K5HvI/AAAAAAAAF_8/_V4T3qnbxGQ/s512/submodule-screen.png" title="'git-submodule'" ></p>

<p>早上整理 <a href="https://github.com/chinghanho/.dotfiles">.dotfiles</a> 因為對 Git 的 submodule 指令不熟悉弄得灰頭土臉，最後把整個目錄砍掉重新 clone 回來，結果發現 submodule 裡面的目錄都是空的，才知道原來 Git 不會自動去抓 submodule 的 repo，還要另外加一些指令。</p>

<p>這些指令因為不會很常用（吧？），最近是因為在摸索 <a href="http://blog.chh.tw/posts/vim-plugins-manager-pathogen/">Vim 的補丁管理</a>才開始碰到 git submodule 問題，如果不寫可能後天就忘光了，所以我把今天碰到的問題整理記錄下來。</p>

<!-- more -->


<h3>新增 submodule</h3>

<pre><code>git submodule add git://github.com/majutsushi/tagbar.git .vim/bundle/tagbar
</code></pre>

<p>如果這個 repo 先前沒有用過 submodule 那麼 Git 會在目錄下建立一個叫做 <em>.gitmodules</em> 的目錄，這裡記錄了 remote repo 的 URL 和這個 submodule 在此專案的路徑。</p>

<p>執行此命令後 submodule 和 <em>.gitmodules</em> 會自動 staged，這個時候可以 commit 和 push。</p>

<h3>更新 submodule</h3>

<p>個別 repo 更新比較麻煩，必須到個別的目錄底下執行 <code>git pull</code> 去拉 upstream 的程式碼，可是這樣會比較安全；若要一次全部更新所有的 submodule 可以用這 <code>foreach</code> 指令：</p>

<pre><code>git submodule foreach --recursive git pull origin master
</code></pre>

<h3>刪除 submodule</h3>

<p>本以為會有像是 <code>git submodule rm</code> 這樣的指令，結果竟然沒有，必須辛苦地一個一個手動移除，不知道不實作這個指令的考量是什麼，希望未來的版本能把它加上去。</p>

<p>移除 submodule 有以下幾個步驟要做，先把 submodule 目錄從版本控制系統移除：</p>

<pre><code>git rm --cached /path/to/files
rm -rf /path/to/files
</code></pre>

<p>再來是修改 <em>.gitmodules</em>，把不用的 submodule 刪掉，例如：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='diff'><span class='line'> [submodule &quot;.vim/bundle/vim-gitgutter&quot;]
</span><span class='line'>   path = .vim/bundle/vim-gitgutter
</span><span class='line'>   url = git://github.com/airblade/vim-gitgutter.git
</span><span class='line'><span class="gd">-[submodule &quot;.vim/bundle/vim-autoclose&quot;]</span>
</span><span class='line'><span class="gd">-  path = .vim/bundle/vim-autoclose</span>
</span><span class='line'><span class="gd">-  url = git://github.com/Townk/vim-autoclose.git</span>
</span></code></pre></td></tr></table></div></figure>


<p>還沒完喔！還要修改 <em>.git/config</em> 的內容，跟 <em>.gitmodules</em> 一樣，把需要移除的 submodule 刪掉，最後再 commit。</p>

<h3>clone 時把 submodule 一起抓下來</h3>

<p>執行 <code>git clone</code> 時 Git 不會自動把 submodule 一起 clone 過來，必須加上 <code>--recursive</code> 遞歸參數，這樣可以連帶 submodule 的 submodule 通通一起抓下來：</p>

<pre><code>git clone --recursive git@github.com:chinghanho/.dotfiles.git
</code></pre>

<p>如果已經抓下來才發現 submodule 是空的，可以用以下指令去抓，<code>init</code> 會在 _.git/config` 下註冊 remote repo 的 URL 和 local path：</p>

<pre><code>git submodule init
git submodule update --recursive
</code></pre>

<p>或是合併成一行 <code>git submodule update --init --recursive</code> 也可以，如果 upstream 有人改過 <em>.gitmodules</em>，那 local 端好像也是用這個方法 update。</p>

<h2>指令解釋</h2>

<ul>
<li><code>git submodule init</code>：根據 <em>.gitmodules</em> 的名稱和 URL，將這些資訊註冊到 <em>.git/config</em> 內，可是把 <em>.gitmodules</em> 內不用的 submodule 移除，使用這個指令並沒辦法自動刪除 <em>.git/config</em> 的相關內容，必須手動刪除；</li>
<li><code>git submodule update</code>：根據已註冊（也就是 <em>.git/config</em> ）的 submodule 進行更新，例如 clone 遺失的 submodule，也就是上一段講的方法，所以執行這個指令前最好加上 <code>--init</code>；</li>
<li><code>git submodule sync</code>：如果 submodule 的 remote URL 有變動，可以在 <em>.gitmodules</em> 修正 URL，然後執行這個指令，便會將 submodule 的 remote URL 更正。</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[終端機必備的多工良伴：tmux]]></title>
    <link href="http://blog.chh.tw/posts/tmux-terminal-multiplexer/"/>
    <updated>2013-04-09T17:11:00+08:00</updated>
    <id>http://blog.chh.tw/posts/tmux-terminal-multiplexer</id>
    <content type="html"><![CDATA[<p>每次把終端機關掉後，先前的狀態都無法記錄，這個問題困擾我好久，最近才知道 tmux 這個工具，終於解決了這個問題。</p>

<p>從官網上的描述，<a href="http://tmux.sourceforge.net/">tmux</a> 是個 terminal multiplexer，意思就是可以讓終端機同時跑多個程式，不用的時候可以把他們藏到背景去，需要的時候再叫出來，甚至 ssh 登入到遠端主機也不會斷掉，此外還可以在同個視窗下切割區塊，如下圖（<a href="http://www.psteiner.com/2012/05/tmux-for-ruby-on-rails.html">圖片來源</a>）：</p>

<p><img src="http://lh5.googleusercontent.com/-Z0XpVHmJ-ks/UWO-JgwbszI/AAAAAAAAF_M/QdewyOkH1xw/s690/rumble.png" alt="tmux-demo" /></p>

<p>右邊開 Vim 寫程式，左上角跑 RSpec 測試，同時左下角開 Rails server 看 log，神奇的是這些狀態可以保存起來，不需要的時候可以藏到背景去，可是用 Sublime Text 2 就沒這麼理想，害我有種想改用 Vim 的衝動。</p>

<!-- more -->


<h2>在 OS X 上使用 Homebrew 安裝 tmux</h2>

<p>首先要安裝 <a href="http://brew.sh/index_zh-tw.html">Homebrew</a>，沒有安裝過的話只要在終端機執行這一行指示即可：</p>

<pre><code>ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)"
</code></pre>

<p>儘管剛剛才安裝 Homebrew 但是還是要先更新一下再安裝程式：</p>

<pre><code>brew update
brew install tmux
</code></pre>

<h2>tmux 運作方式</h2>

<p>2013.04.19 更新：Youtube 上 <a href="http://www.youtube.com/watch?v=wKEGA8oEWXw">tmux Quick Start</a> 這部影片介紹非常清楚，值得一看。</p>

<p>從 SuperUser 看到的<a href="http://superuser.com/questions/398735/difference-between-tmux-and-shell-split-options-on-iterm2">答案</a>，如果關閉終端機掛載在上面的 shells 也會跟著被刪除，結構就像是這樣：</p>

<pre><code>iterm2
  +---- shell
  +---- shell
  +---- shell
</code></pre>

<p>tmux 採用 client-server 的 model，每一個 session 作為一個 client。透過 tmux 仍然會保持所有 shells 繼續運作，即便把整個終端機都關閉，因此可以之後重新將他們重新掛載上去，這也是為什麼在 tmux 下用 ssh 登入遠端主機不會斷線的原因：</p>

<pre><code>iterm2
  +---- tmux
          +---- shell
          +---- shell
          +---- shell
</code></pre>

<h2>tmux 基本用法</h2>

<p>直接在終端機執行 <code>tmux</code> 會開啟第一個 client，可以執行 <code>tmux ls</code> 查看有哪些 client，如果沒有任何 client 可以用，tmux 會自動建立一個。執行 tmux 後終端機底部會顯示一條狀態欄：</p>

<p><img src="http://lh5.googleusercontent.com/-eG1xoULfnn0/UWPNebkAeDI/AAAAAAAAF_c/m3RIih2HklI/s690/tmux.png" alt="tmux" /></p>

<p>tmux 預設的操作要加上 <kbd>Ctrl-b</kbd> 功能鍵；tmux 也有類似 Vim 的指令模式，快捷鍵 <kbd>Ctrl-b</kbd> 後按 <code>:</code> 可以執行指令。以下是一些基本、常用的功能：</p>

<ul>
<li><kbd>Ctrl-b</kbd> + <kbd>c</kbd>：建立新的視窗；</li>
<li><kbd>Ctrl-b</kbd> + <kbd>d</kbd>：卸載目前的 client；</li>
<li><kbd>Ctrl-b</kbd> + <kbd>l</kbd>：與先前選擇的視窗間切換；</li>
<li><kbd>Ctrl-b</kbd> + <kbd>n</kbd>：移動到下個視窗；</li>
<li><kbd>Ctrl-b</kbd> + <kbd>p</kbd>：移動到上個視窗；</li>
<li><kbd>Ctrl-b</kbd> + <kbd>&amp;</kbd>：刪除目前的視窗；</li>
<li><kbd>Ctrl-b</kbd> + <kbd>,</kbd>：重新命名目前的視窗；</li>
<li><kbd>Ctrl-b</kbd> + <kbd>%</kbd>：將目前的視窗分離到兩個區塊；</li>
<li><kbd>Ctrl-b</kbd> + <kbd>q</kbd>：顯示各分割區塊的號碼（用來切換到不同的區塊）</li>
<li><kbd>Ctrl-b</kbd> + <kbd>o</kbd>：切換到下個區塊；</li>
<li><kbd>Ctrl-b</kbd> + <kbd>?</kbd>：列出所有快捷鍵的說明；</li>
<li><kbd>Ctrl-b</kbd> + <kbd>w</kbd>：列出目前 clinet 的視窗，可以用數字鍵切換；</li>
</ul>


<p>要將目前視窗切割多個區塊，快捷鍵如下：</p>

<ul>
<li><kbd>Ctrl-b</kbd> + <kbd>%</kbd>：垂直分離視窗；</li>
<li><kbd>Ctrl-b</kbd> + <code>:split-window</code>：水平分離視窗；</li>
<li><kbd>Ctrl-b</kbd> + <kbd>o</kbd>：移往下一個區塊；</li>
<li><kbd>Ctrl-b</kbd> + <kbd>q</kbd>：顯示區塊的數字代號，當數字顯示時使用數字鍵移往該區塊；</li>
<li><kbd>Ctrl-b</kbd> + <kbd>{</kbd>：將目前的區塊移往左邊；</li>
<li><kbd>Ctrl-b</kbd> + <kbd>}</kbd>：將目前的區塊移往右邊；</li>
</ul>


<h2>個人設定</h2>

<p>切割面板區塊的快捷鍵好像有點難記，可以在根目錄下建立 <em>~/.tmux.conf</em> 檔案，定義自己容易記憶的快捷鍵：</p>

<pre><code>unbind %
bind | split-window -h
bind – split-window -v
</code></pre>

<p><kbd>Ctrl-b</kbd> 距離太遠也很難按，先前有用 GNU screen 的人會將它改成 <kbd>Ctrl-a</kbd>，可是這會和某些快捷鍵衝突，所以我把它改成 <kbd>Ctrl-f</kbd>：</p>

<pre><code>set -g prefix C-f
unbind C-b
bind C-f send-prefix
</code></pre>

<p>我的 .tmux.conf 檔案放在我 Github 上的 <a href="https://github.com/chinghanho/.dotfiles/blob/master/.tmux.conf">.dotfiles</a> 裡，有興趣可以去看看，這裡附上最後我修改的成果圖，加上原本 <a href="http://blog.chh.tw/posts/oh-my-zsh/">oh-my-zsh</a> 修改結果，整個變得超級花俏啊 XD（點圖可放大）：</p>

<p><a href="https://lh5.googleusercontent.com/-zmNq9I6M8wY/UWQHQAdk1BI/AAAAAAAAF_s/ejDrVE8N_4M/s1788/tmux-final.png"><img src="https://lh5.googleusercontent.com/-zmNq9I6M8wY/UWQHQAdk1BI/AAAAAAAAF_s/ejDrVE8N_4M/s690/tmux-final.png" alt="tmux-final" /></a></p>

<p>底下的 status bar 是抄 <a href="https://github.com/zolrath/wemux">wemux</a> 作者的設定，我覺得非常漂亮。最後推薦這兩個連結的文章，介紹非常詳細：</p>

<ul>
<li><a href="http://blog.hawkhost.com/2010/06/28/tmux-the-terminal-multiplexer/">TMUX – The Terminal Multiplexer (Part 1)</a></li>
<li><a href="http://blog.hawkhost.com/2010/07/02/tmux-%E2%80%93-the-terminal-multiplexer-part-2/">TMUX – The Terminal Multiplexer (Part 2)</a></li>
</ul>


<h2>可以與 iTerm2 整合</h2>

<p>iTerm2 <a href="https://code.google.com/p/iterm2/wiki/TmuxIntegration">wiki 頁面</a>上有教怎麼跟 tmux 整合，看了一下說要下載一些東西，然後還要編譯過才能用，可是我發現我直接輸入 <code>tmux -CC</code> 就可以用了，不清楚發生什麼事。</p>

<p>跟 iTerm2 整合的好處是可以用 iTerm2 的分頁和切割區塊功能取代 tmux 那些一堆的指令，可是我試用的結果發現很多不方便的地方，所以我還是用原本 tmux 切割區塊的方式。</p>

<h2>已知問題</h2>

<p>目前發現有兩個問題。</p>

<p>在 tmux 下無法使用系統 <code>pbcopy</code> 等複製貼上的指令，在 <a href="http://robots.thoughtbot.com/post/19398560514/how-to-copy-and-paste-with-tmux-on-mac-os-x">thoughtbot</a> 網站上找到解決方法：</p>

<pre><code>brew install reattach-to-user-namespace
</code></pre>

<p>然後在 <em>.tmux.conf</em> 檔案裡加上以下這行設定：</p>

<pre><code>set-option -g default-command "reattach-to-user-namespace -l zsh"
</code></pre>

<p>還有個問題是 <code>git commit</code> 我預設用的是 Sublime Text 2 編輯器，可是編輯提交訊息後會卡住不動，也就是 <code>subl -w</code> 無法返回，目前無解。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Vim 補丁管理器：Pathogen]]></title>
    <link href="http://blog.chh.tw/posts/vim-plugins-manager-pathogen/"/>
    <updated>2013-04-03T09:07:00+08:00</updated>
    <id>http://blog.chh.tw/posts/vim-plugins-manager-pathogen</id>
    <content type="html"><![CDATA[<p><img src="https://lh5.googleusercontent.com/-8oZ4apnadkQ/UVuFq3nS-NI/AAAAAAAAF9A/oJi0DRBBXYk/s690/mvim-screenshot.png" alt="mvim-screenshot" /></p>

<p>2013.04.12 更新：今天把 Command-T 移除掉換用 <a href="https://github.com/kien/ctrlp.vim">ctrlp</a>，優點是用不用 Ruby 去編譯，用的是 Vimscript 去寫，所以效能跟問題也會比較少。
2013.05.25 更新：今天起改用 Vundle 來管理，可以參考我的新文章：「<a href="http://blog.chh.tw/posts/vim-vundle/">更好用的 Vim 外掛管理工具：Vundle</a>」</p>

<h2>安裝 Pathogen</h2>

<p>管理 Vim 補丁我用的是 <a href="https://github.com/tpope/vim-pathogen">Pathogen</a> 這套，可以讓所有補丁統一放在 <em>~/.vim/bundle</em> 下，每個補丁就是一個獨立的資料夾，想要移除就直接砍掉即可。安裝方法是將 <em>pathogen.vim</em> 腳本放在 <em>~/.vim/autoload</em> 目錄下，可以用以下指令完成：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>mkdir -p ~/.vim/autoload ~/.vim/bundle; \
</span><span class='line'>curl -Sso ~/.vim/autoload/pathogen.vim \
</span><span class='line'>    https://raw.github.com/tpope/vim-pathogen/master/autoload/pathogen.vim</span></code></pre></td></tr></table></div></figure>


<p>然後將這行加進 <em>.vimrc</em> 裡，啟動 Vim 時便會自動讀取 <em>~/.vim/bundle</em> 下的補丁檔案：</p>

<pre><code>" auto load all plugins in vim bundle
execute pathogen#infect()
</code></pre>

<h2>安裝補丁</h2>

<p>之後只要將下載的補丁資料夾拖進 <em>~/.vim/bundle</em> 裡面即可，不過我更偏愛使用 <a href="http://git-scm.com/">Git</a> 來管理。假設要安裝 <a href="https://github.com/wincent/Command-T">Command-T</a> 補丁，可以用 Git 的 submodule 指令完成：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>cd ~/.vim
</span><span class='line'>mkdir ~/.vim/bundle // if you have not yet created this directory
</span><span class='line'>git submodule add https://github.com/wincent/Command-T.git bundle/command-t
</span><span class='line'>git add .
</span><span class='line'>git commit -m "install Command-T plugin as a submodule"</span></code></pre></td></tr></table></div></figure>




<!-- git submodule update --init -->


<h2>更新補丁</h2>

<p>使用 Git 安裝補丁的好處是可以自己動手 hack，也可以保持更新。對單一補丁更新只要變更所在目錄到該補丁的位置，然後 <code>git pull</code> 去拉 upstream 的最新程式碼：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>cd ~/.vim/bundle/command-t
</span><span class='line'>git pull origin master</span></code></pre></td></tr></table></div></figure>


<p>要一次更新所有已安裝的補丁，則可以用 Git 的 <code>foreach</code> 指令來更新每個補丁的最新版本：</p>

<pre><code>git submodule foreach git pull origin master
</code></pre>

<h2>後記</h2>

<p>平常被 Sublime Text 的 Package Control 寵慣了，來用 Vim 感到非常的麻煩和不習慣，而且 Command-T 安裝後還要用 Ruby 跟 C 去編譯才能用，這到底是什麼鬼編輯器啦！XD</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Google 搜尋加密有兩種]]></title>
    <link href="http://blog.chh.tw/posts/https-www-google-com-vs-https-encrypted-google-com/"/>
    <updated>2013-03-22T13:53:00+08:00</updated>
    <id>http://blog.chh.tw/posts/https-www-google-com-vs-https-encrypted-google-com</id>
    <content type="html"><![CDATA[<p>剛剛看 <a href="http://www.businessinsider.com/google-products-youve-never-heard-of-2013-3#encryptedgooglecom-is-a-more-secure-way-to-search-for-things-encrypted-uses-secure-sockets-layer-ssl-which-is-the-same-security-that-banks-use-online-11">Business Insider</a> 提到了 Google 的 <a href="https://encrypted.google.com/">encrypted.google.com</a> 這個網址，記得在 Google 還沒有對已登入用戶全面預設用 <a href="http://en.wikipedia.org/wiki/HTTP_Secure">HTTPS</a> 連線以前，<em>encrypted.google.com</em> 是專門用來使用 HTTPS 的網址，也就是當連線到 <em>https://www.google.com</em> 時會被自動跳轉到 <em>https://encrypted.google.com</em>。</p>

<p>既然現在 Google 對於已登入的用戶已經預設用 HTTPS 連線，那這個東西還留著幹嘛？所以<a href="http://security.stackexchange.com/questions/32367/what-is-the-difference-between-https-google-com-and-https-encrypted-google-c">問一下 Google 找答案</a>，原來 <em>encrypted.google.com</em> 另有其他特異功能，兩者之間的差異，主要在於點擊廣告與搜尋結果時，處理 <a href="https://zh.wikipedia.org/wiki/HTTP%E5%8F%82%E7%85%A7%E4%BD%8D%E5%9D%80">HTTP 參照位址</a>的方式不同。</p>

<!-- more -->


<h3>點擊一個廣告</h3>

<ul>
<li><p><em>https://www.google.com</em>：Google 將會把你帶到一個 HTTP 的重新導向頁面，在那裡他們會把你的搜尋字串塞進參照資訊裡去。</p></li>
<li><p><em>https://encrypted.google.com</em>：如果這個廣告主用的是 HTTP，Google 不會讓他們知道你的查詢字串是什麼。而如果廣告主用的是 HTTPS，他們將會如常地收集到你的參照資訊（包括查詢字串）。</p></li>
</ul>


<h3>點擊一般的搜尋結果</h3>

<ul>
<li><p><em>https://google.com</em>：除果網站使用 HTTP 連線，Google 將會把你帶到 HTTP 的重新導向頁面，但是不會把你的搜尋字串給塞進參照資訊裡面。他們只會告訴網站你是從 Google 來的。如果你的網站使用 HTTPS 連線，便可以正常地搜集到參照資訊。</p></li>
<li><p><em>https://encrypted.google.com</em>：如果你點擊的網站使用 HTTP 連線，Google 既不會告訴它查詢字串是什麼，也不會告訴它你是哪裡來的。如果該網站使用 HTTPS 連線，它則會正常地收到參照資訊。</p></li>
</ul>


<p>所以我的 blog 從搜尋引擎來的訪客中，用關鍵字去查有 74% 都是「not provided」大概就是這個原因。如果這篇答案的結果是正確的，採用 HTTPS 連線加密的網站便可以正確地搜集到帶有查詢字串的參照資料，那網站採用 HTTPS 將會變成最基本的條件。</p>
]]></content>
  </entry>
  
</feed>
