實現"輸入框"得到焦點時外邊框變藍

背景

以前作了一個網頁,網頁中的全部輸入框都被設計爲「得到鼠標焦點時外邊框不變藍」。忽然某一天,產品以爲這樣用戶體驗很差,不能很明顯地告訴用戶當前鼠標停在哪裏,因而要求改成「當輸入框得到鼠標焦點時,外邊框自動變藍;失去焦點時外邊框恢復原樣」。php

瀏覽器自動會給輸入框inputtextareaoutline 屬性設置一個默認值,效果就是當輸入框得到鼠標焦點時外邊框會自動帶上顏色,失去焦點時外邊框顏色消失。因爲不一樣瀏覽器outline 屬性的默認值不一樣,致使外邊框的顏色也不一樣。若是不想要瀏覽器的outline默認設置,只須要將 outline 屬性設置爲none 便可。css

因此一開始聽到這個需求,感受特別簡單,不就是純 CSS 的問題嘛!我只要將全部輸入框的 outline 屬性設置爲瀏覽器默認的值就行了,但我想的太天真了。。。。web

一、如何複製瀏覽器默認的 outline 樣式

因爲網頁中已有的輸入框的樣式遍及在各個文件中,有一種很是機械的辦法,那就是到每一個文件中去刪除掉輸入框的 outline:none樣式,這樣輸入框就會使用瀏覽器默認的 outline 樣式了。可是這樣作要改的地方太多了,會瘋掉的!再想一想有沒有更省事的方法,有了!在最基本的base.css樣式文件中給輸入框添加一個focus時候的outline樣式不就解決了麼。那麼問題來了,該將outline 設置何值,才能自動使用瀏覽器默認的outline樣式呢?瀏覽器

我第一個想到的方法是將 outline設置爲auto,但發現只有webkit 內核的瀏覽器才支持這個屬性值,firefox 不支持,由於auto 並非標準的outline 值。因此要想直接複製瀏覽器默認的outline樣式是作不到的。難道我要針對每一個瀏覽器設置不一樣的outline 值,爲了這麼一點破需求費那麼大工夫?!算了,省事點的方式仍是直接摒棄瀏覽器的默認outline樣式,統一將outline設置爲一種樣式好了。函數

二、避開 outline,選擇 border

但我發現了新問題,經過設置outline樣式爲輸入框添加外邊框,效果並很差。由於 outline 沒有相似 border-radius的屬性來改變邊角的弧度。這樣就致使了一個問題:當輸入框設置了border顏色,同時border-radius3px以上時,能明顯的看到outline 外邊框並無和border 重合。看來設置 outline 來達到邊框變藍效果並非最好的選擇,爲何不選用設置 border 來達到一樣的效果呢?只要將border再設置下 border-shadow,那麼看起來也是和outline效果同樣的,並且border還能設置border-radius,顯示效果更知足需求。firefox

三、如何讓任何一個元素都能 focusable

經過設置 border 解決了大多數輸入框,但發現又有了新問題。設計

網頁中有些輸入框其實並非單一使用 input/textarea來實現的,這類「輸入框」看起來和通常輸入框並沒有兩樣,但其實 HTML 結構是一個 div 裏面包含着一個 input/textarea 來實現的。並且輸入框的邊框設置在了父元素 div 上,全部當輸入框得到焦點時,看到的應該是父元素 div 上的邊框變藍,而不是裏面的input/textarea 的邊框變藍。code

要想得到焦點時父元素 div的邊框變藍,確定可行的方法是經過 JS 來實現:給input/textarea 綁定一個 focus 和 一個blur事件,在focus 事件處理函數中將父元素div的邊框置藍,在blur事件處理函數中將父元素div的邊框恢復原樣。這種方法時絕對可行的,可是我總以爲應該有更簡單的,純粹使用 css 實現的方法。orm

若是想單純經過css 實現,首先想到的是用選擇器div:focus。可是發現div上沒法使用:focus僞類。因而我就猜測:可能並非全部的元素都是 focusable的,那麼得找一份說明哪些元素 focusable的規範。事件

哪些元素是 focusable的?

搜索結果:

根據 DOM Level 2 HTML規範,focusable 的DOM元素都會有一個原生的focus()方法,只有 focusable 的DOM 元素纔有 focus 事件,才能使用:focus僞類。擁有原生的focus()方法的DOM元素包括幾種:HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement and HTMLAnchorElement。很明顯,規範中遺漏了HTMLButtonElement and HTMLAreaElement。

雖然規範這麼定義,但瀏覽器在實現時倒是另一套。瀏覽器給任何一個 HTMLElement 都定義focus()方法,但並非任何一個HTMLElement 都能得到焦點(得到焦點術語叫 active, 具體請參考:http://help.dottoro.com/ljqmdirr.php)。通常來講,任何一個時刻HTML 文檔中只會有一個active元素,但並非任何一個元素都能成爲active元素。能成爲active 的元素包括:

  1. 表單元素(form controllers):input/option/textarea/button

  2. 連接元素(links):a標籤、area標籤(必需要帶 href 屬性,包括 href 屬性爲空)

  3. 能夠被編輯的元素(包括經過添加 contenteditable = "true"屬性變成可編輯的狀況)

  4. 設置了 tabindex 屬性(tabindex 值非-1)的元素

  5. window:當頁面窗口從隱藏變成前置可見時,focus 事件就會觸發

根據搜索結果,要想將父元素div變成focusable,只須要在元素上設置 tabindex 屬性,而後經過:focus僞類設置父元素div 得到焦點時的border樣式。但我發現當鼠標點擊裏面的 input 元素時,父元素div並無得到焦點,得到焦點的是子元素input

因此最後仍是沒能經過純 css 的方法來解決這個問題,無奈之下我仍是經過js去解決了。。。。。。

相關文章
相關標籤/搜索