2015年1月20日 星期二

CSS3 的魔力 : 如何製作交談氣泡 (Speech bubble)

這幾天 EasyuiCMS 的開發進度慢了下來, 因為動手寫留言板功能時, 對於排版與呈現方式感到苦惱, 這就是完美主義者自戀自愛的代價.

上周末看到 EasyUI 的 tooltip 元件範例, 突然發現用 tooltip 來呈現留言很不錯, 但試了兩天還是放棄了, 原因是 tooltip 預設為隱藏, 等游標移到上面時才會現身, 而留言板是進入頁面就應該顯示最近幾筆留言, 若還要使用者移到人名或日期上才顯示內容, 還要多一步操作, 這樣就有點怪了.

在看過幾本 PHP 書籍的範例仍無頭緒後, 開始上網以留言板為 keyword 去搜尋, 啊哈, 經由 "那些 CSS 偽元素可以幫你做的 10 個效果" 找到下面兩個超棒網站 :

Pure CSS speech bubbles
How to Create CSS3 Speech Bubbles Without Images

實際測試後發現前者比較適合, 這位作者對 CSS3 的掌握真的是太神了, 主要是以 CSS3 的偽元素 before 與 after 來製作兩個一大一小 size 為 0 的三角形, 利用其上下左右方向的 border 寬度與 background-color 顏色不同, 使兩個三角形重疊出一個三角框, 然後將三角框的一邊與圓角方框的一邊重疊, 這樣就能做出交談氣泡的指引箭頭了. 我是透過詳讀第二個網站的詳細說明才真正了解其原理的.

OK, 現在就來測試一下. 我的留言板規劃是左邊隨機顯示一個圖檔與留言者, 其下顯示留言日期, 右方則顯示其留言內容, 因此我需要的是一個箭頭在左邊的交談氣泡, 也就是 "Pure CSS speech bubbles" 中 "Sample Examples" 倒數第二個圖. 觀其網頁原始碼, 可以發現其樣式設定在 default.css 這個檔 :

http://nicolasgallagher.com/pure-css-speech-bubbles/demo/default.css

我需要的是 triangle border 與其 left 部分, 也就是將 "BUBBLE WITH A BORDER AND TRIANGLE" 這區塊中的 top 與 right 部分去除即可.

  .triangle-border {
    position:relative;
    padding:15px;
    margin:1em 0 3em;
    border:1px solid #95B8E7;
    color:#333;
    background:#fff;
    /* css3 */
    -webkit-border-radius:10px;
    -moz-border-radius:10px;
    border-radius:10px;
    }
  .triangle-border:before {
    content:'';
    position:absolute;
    bottom:-20px;
    left:40px;
    border-width:20px 20px 0;
    border-style:solid;
    border-color:#5a8f00 transparent;
    /* reduce the damage in FF3.0 */
    display:block;
    width:0;
    }
  .triangle-border:after {
    content:"";
    position:absolute;
    bottom:-13px;
    left:47px;
    border-width:13px 13px 0;
    border-style:solid;
    border-color:#fff transparent;
    /* reduce the damage in FF3.0 */
    display:block;
    width:0;
    }
  .triangle-border.left {margin-left:30px;}
  /* creates the larger triangle */
  .triangle-border.left:before {
    top:10px;
    bottom:auto;
    left:-20px;
    border-width:10px 20px 10px 0;
    border-color:transparent #95B8E7;
    }
  /* creates the smaller  triangle */
  .triangle-border.left:after {
    top:11px;
    bottom:auto;
    left:-19px;
    border-width:9px 19px 9px 0;
    border-color:transparent #fff;
    }

這裡我修改了原作者關於邊框顏色與粗細的設定, 因為我的邊框只要 1px 即可, 原作是設為 5px, 太粗了. 需要修改的數據如上藍色部分, 目的是擠出一個邊框 1px 的三角形, 其計算原理如下 :


這裡我們的交談氣泡指標是以交談框的左上角為原點, 外三角往左 20px, 往下 10px 開始描繪, 故 triangle-border.left:before 裡, top 設為 10, left 設為 -20 (負為往左), 其邊框寬度要設為 10 (上), 20 (右), 10(下), 左邊要壓扁, 故為 0. 而內三角的底與外三角的底 (右方) 重疊, 高少 1px, 因此 triangle-border.left:after 的 top 設為 11, left 設為 -19, 其邊框寬度設為 9 (上), 19 (右), 9(下), 同樣左邊要壓扁, 故為 0. 重點是內三角邊框顏色設為白色, 剛好把外三角的顏色蓋掉, 只剩上下兩個 1px 的線.

網頁部分如下, 只要設定 P, SPAN, 或 DIV 元素的樣式類別為 "triangle-border left" 即可 :

  <div>
    <img src="male.png" style="border-width:0px;">
    <span class="triangle-border left">
      Hello Emma!
      How is everything going?
    </span>
  </div>
  <div>
    <img src="female.png" style="border-width:0px;">
    <span class="triangle-border left">
      Hi, Sam!
      Ya, just fine. And You?
    </span>
  </div>

測試範例 1 : http://mybidrobot.allalla.com/css3test/speech-bubble-1.htm [看原始碼]

下面是用 Chrome 瀏覽的結果, 看來很不錯 (版本 39.0.2171.95 m) :


下面是用 IE 瀏覽結果, 不佳 (版本 11.0.9600) :


下面是用 Firefox, 同樣不佳 (版本 35.0) :


最後是 Opera, 雖然渲染效果與 Chrome 稍有不同, 但也 OK (版本 26.0.1656.60) :


從這一點可看出, Chrome 與 Opera 還是瀏覽器界數一數二的優等生, 對於 CSS3 與 HTML5 的支援度是最棒的. Firefox 與 IE 則要加油了.

下午又找到一個更棒的 CSS 箭頭產生器, 直接選取所需要的屬性, 就會自動產生 CSS 檔 :

# CSS Arrow Please: CSS 箭頭產生器
# http://cssarrowplease.com/

我選了左方箭頭, 寬度 1px 的, 然後稍加調整屬性如下 :

    .arrow_box {
      padding: 15px;
      height: auto;
      border-radius: 10px;
      position: relative;
      background: #ffffff;
      border: 1px solid #95B8E7;
      }
    .arrow_box:after, .arrow_box:before {
      right: 100%;
      top: 50%;
      border: solid transparent;
      content: " ";
      height: 0;
      width: 0;
      position: absolute;
      pointer-events: none;
      }
    .arrow_box:after {
      border-right-color: #ffffff;
      border-width: 13px;
      margin-top: -10px;
      }
    .arrow_box:before {
      border-right-color: #95B8E7;
      border-width: 14px;
      margin-top: -11px;
      }

原理其實跟上面範例 1 是一樣的, 只是所用的樣式屬性稍有不同而已. 我改動了一些屬性值來達成與範例 1 同樣的結果. 只要把上面範例 1 的 class 改為 arrow_box 即可 :

  <div>
    <img src="male.png" style="border-width:0px;">
    <span class="arrow_box">
      Hello Emma!
      How is everything going?
    </span>
  </div>
  <div>
    <img src="female.png" style="border-width:0px;">
    <span class="arrow_box">
      Hi, Sam!
      Ya, just fine. And You?
    </span>
  </div>

如下範例 2 所示 :

測試範例 2 : http://mybidrobot.allalla.com/css3test/speech-bubble-2.htm [看原始碼]

這個做法比範例 1 要好, 在 Chrome, Firefox, 與 Opera 均正常, 僅 IE 無法覆蓋與三角形重疊的邊框. IE 到底是哪根筋不對啊? 是因為老大當太久了嗎?

上面兩個範例都有一個問題, 就是留言內容不可太長, 否則留言內容框會斷成兩節 :


這是因為我們使用 span 元素之故, 若使用 div 元素就不會這樣, 但如此一來留言框就會佔據整列了. 所以現在考慮改用向上箭頭 :

    .arrow_box {
      margin-top:30px;
      padding: 15px;
      height: auto;
      border-radius: 10px;
      position: relative;
      background: #ffffff;
      border: 1px solid #95B8E7;
      }
    .arrow_box:after, .arrow_box:before {
      bottom: 100%;
      left: 60px;
      border: solid transparent;
      content: " ";
      height: 0;
      width: 0;
      position: absolute;
      pointer-events: none;
      }
    .arrow_box:after {
      border-bottom-color: #ffffff;
      border-width: 15px;
      margin-left: -12px;
      }
    .arrow_box:before {
      border-bottom-color: #95B8E7;
      border-width: 16px;
      margin-left: -13px;
      }

網頁部分做了些修改, 加上姓名與時間 :

  <div>
    <img src="male.png" style="border-width:0px;"> Sam 於 2015-01-13 23:11:06
    <div class="arrow_box">
      Hello Emma!
      How is everything going?
    </div>
  </div>
  <div>
    <img src="female.png" style="border-width:0px;"> Emma 於 2015-01-13 23:12:50
    <div class="arrow_box">
      Hi, Sam!
      Ya, just fine. And You?
    </span>
  </div>

如下列範例 3 所示 :

測試範例 3 : http://mybidrobot.allalla.com/css3test/speech-bubble-3.htm [看原始碼]



沒有留言 :