摘要:若你想在諸如元素的組件上應用高級樣式或者想定制組件的行為,你就只能選擇創建自己的表單組件。我們將通過本文學習如何構建一個表單組件。
系列文章說明
原文
在許多情況下,[可用的HTML表單組件]()是不夠的。若你想在諸如元素的組件上[應用高級樣式]()、或者想定制組件的行為,你就只能選擇創建自己的表單組件。
我們將通過本文學習如何構建一個表單組件。為達到目的,我們選擇重構元素作為例子。
設計,結構和語義注意:我們會專注于構建組件,但不會關注如何保證代碼的通用和可重用。構建組件時會涉及到一些特殊的JavaScript代碼和未知上下文中的DOM操作,而這些內容已經超出了本文的討論范圍。
在構建一個定制組件前,應先從明確你想要達到的效果開始,這會節省你寶貴的時間。具體來講,清晰地定義組件的所有狀態是很重要的。要做到這點,最好從一個已經存在的、狀態和行為已經為人所熟知的組件開始,這樣你就只需盡可能地模仿該組件即可。
在我們的例子中,我們會重構元素。下面是我們期望達到的結果:
上面的截屏展示了我們組件的三個主要狀態:普通狀態(左)、激活狀態(中)和打開狀態(右)。
至于組件的行為,我們希望可以像其他原生組件一樣,通過鼠標和鍵盤來操控它。先從定義組件如何到達各個狀態開始:
組件變為普通狀態:
頁面加載
組件激活且用戶點擊了組件外任意地方
組件激活且用戶用鍵盤把焦點移動到別的組件
注意:在頁面上移動焦點通常是通過敲tab鍵來實現的,但不是所有地方都遵循這個慣例。比如Safari上默認是用Option+Tab組合鍵來實現在頁面上移動焦點。
組件變為激活狀態:
用戶點擊了組件
用戶按tab鍵且組件獲得了焦點
組件處于打開狀態且用戶點擊了組件
組件變為打開狀態:
組件處于其他非打開狀態且用戶點擊了它
在知道如何改變狀態后,定義組件的值如何被改變也是很重要的:
組件的值改變:
在組件處于打開狀態時,用戶點擊了一個選項
在組件處于激活狀態時,用戶按了上下方向鍵
最后我們來定義下組件選項的行為:
當組件處于打開狀態時,被選中的選項會高亮
當鼠標移到一個選項上,該選項會高亮且原先高亮狀態的選項會恢復到普通狀態
考慮例子的演示目的,我們的分析就到此為止;然而如果你認真讀過上文,會發現我們漏了一些效果。比如,當組件處于打開狀態時,如果用戶按了tab鍵會發生什么呢?答案是--什么都不會發生。正確的效果雖然顯而易見(譯注:參考select原生組件,也是什么都不會發生),但事實是我們沒有在上述說明中定義它,這個效果很容易就會被忽視。在團隊協作中,如果設計組件的人和實現它的人不同,這是特別容易出現的問題。
另一個有趣的問題是:組件處于打開狀態時,用戶按上下方向鍵會發生什么?要回答它,需要一點技巧。若考慮激活狀態和打開狀態是完全不相干的,那答案就還是“什么都不會發生”,因為我們并未給打開狀態定義任何鍵盤交互。另一方面,如果考慮激活狀態和打開狀態有部分重疊,那答案就是:值可能會改變但選項也因此不會被高亮(譯注:大概因為組件已經處于激活狀態了吧),這也是因為當組件處于打開狀態時,我們并未給選項未定義任何鍵盤交互(只是定義了組件打開時應該發生什么,卻沒定義打開后要干嘛)。
在我們的例子中,缺失的特性還是比較明顯的,所以我們還能處理得了它;但當面對來自外部的新組件時,由于沒人知道正確的行為是什么,這時就會造成真正的麻煩。因此,花些時間在設計階段是很有必要的,如果你此時定義了一個不佳的交互,或忘記了去定義,后續在用戶使用了該交互時再去重定義是很困難的。若(處理交互時)你有疑問,應積極尋求他人的幫助;而若你心中有數,則應毫不猶豫地進行用戶測試。上面討論的過程,可稱之為UX(譯注:用戶體驗)設計。如果你想了解更多這方面的內容,可以參考下面這些資源:
UXMatters.com
UXDesign.com
The UX Design section of SmashingMagazine
定義HTML結構和語義注意:在多數系統中,還有有一種方法可以打開元素以查看所有可用的選項(這和用鼠標點擊元素是一樣的)。這個方法在Windows下是用Alt+下方向鍵來實現的,我們的例子中并未實現它--但要這樣做也很簡單,因為整個操作的機制已經被用于實現click事件了。
上面我們確定了組建的基本功能,現在可以來構建我們的組件了。第一步我們要定義其HMLT結構,并為其添加基本的語義。下面是我們重構元素所需的代碼:
Cherry
- Cherry
- Lemon
- Banana
- Strawberry
- Apple
要注意此處class名的使用;這些class標記了每個相關的元素,而不需要依賴其實際使用的HTML元素。這么做能確保我們不會把CSS和JavaScript與HTML結構作強關聯,從而做到改變后續的組件代碼實現時,不破壞使用該組件的代碼。比如你想實現一個同樣的元素時,可用直接用相同的代碼來調用。
用CSS創建樣式和交互現在我們已經有了組件的結構了,接下來要來設計組件了。創建這個自定義組件的目的,是為了用我們想要的形式來給該組件添加樣式。要做到這點,我們要把CSS的編碼工作拆為兩部分:第一部分是讓我們組件和元素看起來一致的必要CSS規則,第二部分是用來讓組件變成我們想要的樣子的樣式。
必要的樣式必要的樣式是用來處理我們組件的三個狀態的。
.select { /* 給選項列表創建一個定位上下文 */ position: relative; /* 讓我們的組件成為文本流的一部分,并使之可伸縮 */ display : inline-block; }
我們需要一個額外類名active,來定義組件處于激活狀態時的外觀。因為我們的組件是可以獲得操作焦點的,所以還要將相同的樣式用于:focus偽類,保證激活和獲得焦點時的行為一致。
.select.active, .select:focus { outline: none; /* box-shadow 屬性不是必要的,但它可以作為默認值保證激活狀態可見,去掉它也是可以的。 */ box-shadow: 0 0 3px 1px #227755; }
接下來處理選項列表:
/* 這里的 .select 選擇器,用來確保后面選擇器匹配的元素就是我們組件中那個 */ .select .optList { /* 下面樣式確保選項列表會展示在當前值下面、并在HTML文檔流之外 */ position : absolute; top : 100%; left : 0; }
我們需要一個額外的class來處理選項列表的隱藏狀態。為了管理激活和展開兩個不同的狀態,這么做是很有必要的。
.select .optList.hidden { /* 下面是一個以無障礙方式來隱藏列表的簡單方法,我們會在文末討論更多關于無障礙訪問的內容。 */ max-height: 0; visibility: hidden; }美化
在有了基本的功能之后,有趣的部分開始了。下面是一個可選的例子,效果和本文開頭的那個截圖一致。但是你也可以自由探索、看看你能實現怎樣的效果。
.select { /* 所有的大小值都會采用em值來保證無障礙訪問 (保證組件在用戶使用瀏覽器純文字模式下的縮放時,還保留自適應的能力)。 在計算時,假設1em == 16px,這也是大多數瀏覽器的默認值。 如果你對px到em的轉換感到困惑,可以訪問:http://riddle.pl/emcalc/ */ font-size : 0.625em; /* this (10px) is the new font size context for em value in this context */ font-family : Verdana, Arial, sans-serif; -moz-box-sizing : border-box; box-sizing : border-box; /* 需要額外的空間來添加向下箭頭 */ padding : .1em 2.5em .2em .5em; /* 1px 25px 2px 5px */ width : 10em; /* 100px */ border : .2em solid #000; /* 2px */ border-radius : .4em; /* 4px */ box-shadow : 0 .1em .2em rgba(0,0,0,.45); /* 0 1px 2px */ /* 第一句聲明用于不支持線性漸變的瀏覽器。 第二句聲明是因為基于Webkit的瀏覽器對線性漸變屬性還要加個前綴。 若你還想支持老舊瀏覽器,可參考http://www.colorzilla.com/gradient-editor/ */ background : #F0F0F0; background : -webkit-linear-gradient(90deg, #E3E3E3, #fcfcfc 50%, #f0f0f0); background : linear-gradient(0deg, #E3E3E3, #fcfcfc 50%, #f0f0f0); } .select .value { /* 因為value元素可能會比組件還寬,所以我們得保障這不會改變組件的寬度 */ display : inline-block; width : 100%; overflow : hidden; vertical-align: top; /* 如果內容溢出了,最好能有省略號來替代。 */ white-space : nowrap; text-overflow: ellipsis; }
我們不需要額外的元素來設計向下箭頭,而是使用:after偽元素。但其實這也能在select類上用一個簡單的背景圖片來實現。
.select:after { content : "▼"; /* 使用 unicode 字符 U+25BC;參見 http://www.utf8-chartable.de */ position: absolute; z-index : 1; /* 用來保證箭頭會疊在選項列表上面 */ top : 0; right : 0; -moz-box-sizing : border-box; box-sizing : border-box; height : 100%; width : 2em; /* 20px */ padding-top : .1em; /* 1px */ border-left : .2em solid #000; /* 2px */ border-radius: 0 .1em .1em 0; /* 0 1px 1px 0 */ background-color : #000; color : #FFF; text-align : center; }
接下來,給選項列表添加樣式:
.select .optList { z-index : 2; /* 表明選項列表會始終疊在向下箭頭之上 */ /* 重置ul元素的默認樣式 */ list-style: none; margin : 0; padding: 0; -moz-box-sizing : border-box; box-sizing : border-box; /* 確保即使值太少讓選項列表小于組件主體,也能讓選項列表會和組件主體一樣大 */ min-width : 100%; /* 如果列表太長了,其內容會在垂直方向上溢出(默認會自動添加一個垂直方向的滾動條), 但不會在水平方向上也這樣(因為我們沒有設置寬度,列表會有個自適應寬度,如果不能自適應, 內容就會被截斷) */ max-height: 10em; /* 100px */ overflow-y: auto; overflow-x: hidden; border: .2em solid #000; /* 2px */ border-top-width : .1em; /* 1px */ border-radius: 0 0 .4em .4em; /* 0 0 4px 4px */ box-shadow: 0 .2em .4em rgba(0,0,0,.4); /* 0 2px 4px */ background: #f0f0f0; }
對于選項,我們需要添加一個highlight類來標明用戶會選取(或已經選取)的值。
.select .option { padding: .2em .3em; /* 2px 3px */ } .select .highlight { background: #000; color: #FFFFFF; }
下面就是我們三個狀態的實現效果了:
效果
現在我們組件的結構和設計都已經做好,可以來寫JavaScript代碼讓組件真正能運行起來了。
為什么不起作用?警告:下面的代碼是教學代碼,在實際編碼時不能直接像下面一樣使用。其中許多部分,并沒有未來使用的保障、而且也不能在老舊瀏覽器上使用。此外,這些代碼也有在生產環境中應該被優化掉的冗余部分。
注意:創建可復用的組件是很有技巧性的。W3C Web Component 草案是這個特定問題的一個解決方案。X-tag project是這一規范的實驗性實現;我們鼓勵你好好了解下它。
在開始之前,我們需要知道JavaScript的一個嚴重問題:在瀏覽器里,它是一個不可靠的技術。當你在創建自定義組件的時候,你不得不依賴JavaScript,因為它是把所有東西維系在一起的繩索。但是,在許多情況下JavaScript并不能在瀏覽器中運行:
用戶禁用了JavaScript:這已經是個最不常見的情況了,現在很少有人會禁用JavaScript。
腳本沒有加載:這是最普遍的情況,特別是在網絡不太可靠的移動端。
腳本有bug:你要經常考慮這一可能性。
腳本和第三方腳本沖突了:使用了追蹤腳本或用戶自用的書簽時會發生這種情況。
腳本和瀏覽器拓展(如火狐的NoScript拓展或Chrome的NoScripts拓展)發生沖突、或受到干擾。
用戶使用了老舊瀏覽器,并且你需要的一種特性不被支持:這通常發生在你用了很新的API時。
由于有這些風險,我們需要認真考慮下JavaScript不起作用時會發生什么。深入處理這個問題已經超出了本文的論述范圍,因為這和你希望如何讓腳本通用和可復用密切相關,我們不會在例子中考慮這點。
在本文的例子中,若JavaScript代碼不能運行,我們會回退到展示標準的元素。要做到這點,得先來做兩件事。
首先,我們要在使用自定義組件之前,添加一個普通的元素。而為了能讓自定義組件的數據和剩下的表單數據一起發送,這一步也是很有必要的。后邊我們還會詳細介紹。
第二,我們還得添加兩個新的類名,實現隱藏不需要的元素(即在腳本能運行時的元素、或腳本不能運行時的自定義組件)。要注意的是在默認情況下,此處的HTML代碼會隱藏自定義組件。
.widget select, .no-widget .select { /* 這個CSS選擇器意思是: - 要么body的類名被設為"widget",此處就要隱藏`
至此,我們只需要一個JavaScript開關來決定腳本是否能運行了。這個開關很簡單:若頁面加載了腳本并運行,就會移除no-widget類并添加widget類,實現對元素和自定義組件可見與否的切換。
window.addEventListener("load", function () { document.body.classList.remove("no-widget"); document.body.classList.add("widget"); });
效果
讓工作輕松些注意:若你真的想讓你的組件變得通用和可復用,除了作類名的切換,更好的方法是(在腳本能執行時)只添加widget類名隱藏元素,并在頁面中的每個元素后面指定自定義的組件、動態添加到DOM樹中。
在將要創建的代碼中,我們會使用標準的DOM API來完成工作。然而,盡管瀏覽器對DOM API的支持已經越來越好,但在老舊瀏覽器上仍存在一些問題(特別在很老的IE上)。
若你想避免老舊瀏覽器上的麻煩,有兩種方法可以做到:使用諸如jQuery, $dom, prototype, Dojo, YUI之類的穩定框架;或者補充那些缺失的但你要用的特性(通過條件加載可以很容易做到這點,比如可以使用yepnope庫)。
我們計劃使用的特性如下(從風險最大到最安全排列):
classList
addEventListener
forEach(不屬于DOM但是現代JavaScript的特性)
querySelector和querySelectorAll
除了上述特性的可用性,在開發之前仍存在一個問題。querySelector()方法返回的是一個NodeList而不是數組。Array對象支持forEach方法、但NodeList不支持。因為NodeList看起來像數組、也因為forEach方法用起來很方便,所以我們可以很簡單地就給NodeList添加forEach支持、讓我們的工作輕松些,就像下面這樣:
NodeList.prototype.forEach = function (callback) { Array.prototype.forEach.call(this, callback); }
我們說這很簡單可不是瞎說的哦。
建立事件回調前期工作已經做好了,我們現在可以來定義用戶和我們的組件交互時要用到的所有函數了。
/* 這個函數會在取消激活自定義組件時被使用 需要一個參數: select: 類名為`select`且要被取消激活的DOM節點 */ function deactivateSelect(select) { /* 若組件未被激活,則什么都不做 */ if (!select.classList.contains("active")) return; /* 獲取自定義組件的選項列表 */ var optList = select.querySelector(".optList"); /* 關閉選項列表 */ optList.classList.add("hidden"); /* 取消自定義組件的激活狀態 */ select.classList.remove("active"); } /* 該函數用于讓用戶(取消)激活組件 需要兩個參數: select:類名為`select`且要被激活的DOM節點 selectList:類名為`select`的所有DOM節點的列表 */ function activeSelect(select, selectList) { /* 若組件已經激活,則什么都不做 */ if (select.classList.contains("active")) return; /* 所有自定義組件的激活狀態都得取消, 因為deactivateSelect函數滿足了作為forEach回調函數的要求, 所以我們會直接使用它而不是用一個中間的匿名函數 */ selectList.forEach(deactivateSelect); /* 開啟該組件的激活狀態 */ select.classList.add("active"); } /* 該函數用于讓用戶打開和關閉選項列表 需要一個參數: select:有一個列表要切換狀態的DOM節點 */ function toggleOptList(select) { /* 選項列表可以從組件那獲得 */ var optList = select.querySelector(".optList"); /* 改變列表的類名來展示和隱藏它 */ optList.classList.toggle("hidden"); } /* 該函數用于高亮一個選項 需要兩個參數: select:類名為`select`且包含要被高亮選項的DOM節點 option:類名為`option`且要被高亮的DOM節點 */ function highlightOption(select, option) { /* 獲得自定義select元素的所有可用選項 */ var optionList = select.querySelectorAll(".option"); /* 移除所有選項的高亮 */ optionList.forEach(function (other) { other.classList.remove("highlight"); }); /* 高亮正確的選項 */ option.classList.add("highlight"); };
上面就是處理自定義組件的多個狀態所需的所有函數。
接下來,我們把這些函數綁到合適的事件上:
/* 在文檔加載出來后處理下事件綁定 */ window.addEventListener("load", function () { var selectList = document.querySelectorAll(".select"); /* 每個自定義組件都要被初始化 */ selectList.forEach(function (select) { /* 所有的`select`元素也要被初始化 */ var optionList = select.querySelectorAll(".option"); /* 用戶把鼠標放到一個選項上時,高亮該選項 */ optionList.forEach(function (option) { option.addEventListener("mouseover", function () { /* 注意:在我們的函數調用內,`select`和`option`變量都是局部的 */ highlightOption(select, option); }); }); /* 用戶點擊了自定義的select元素 */ select.addEventListener("click", function (event) { /* 注意:在我們的函數調用內,`select`變量是局部的 */ /* 改變選項列表的可見狀態 */ toggleOptList(select); }); /* 組件獲得焦點時 /* 用戶點擊組件或用tab鍵訪問組件時,組件會獲得焦點 */ select.addEventListener("focus", function (event) { /* 注意:在我們的函數調用內,`select`和`selectList`變量都是局部的 */ /* 激活該組件 */ activeSelect(select, selectList); }); /* 組件失去焦點時 */ select.addEventListener("blur", function (event) { /* 注意:在我們的函數調用內,`select`變量是局部的 */ /* 取消激活該組件 */ deactivateSelect(select); }); }); });
至此,組件已經能根據我們的設計來改變其狀態了,但它的值目前還不會更新,接下來我們就會處理這點。
效果
處理組件的值現在組件已經能用了,但我們還得加點代碼,根據用戶的輸入更新它的值、并讓其能隨著表單數據一起發送它的值。
要做到這點,最簡單的方式就是在私底下用一個原生組件。這樣一來,自定義組件就會跟蹤瀏覽器提供的內置控件的值,并和平時一樣在表單提交時發送它的值。在瀏覽器已經為我們做好這一切時,沒有必要來重新發明輪子了。
如前所示,出于可訪問性的原因,我們已經用了一個原生的select組件來作為回退;同步這個組件的值和自定義組件的值是很容易的:
// 該函數用于更新展示的值,并和原生組件作同步 // 需要兩個參數: // select:類名為`select`且值要更新的DOM節點 // index:選定的值的索引 function updateValue(select, index) { // 我們得為給定的自定義組件獲取原生組件 // 本例中,原生組件是自定義組件的兄弟節點 var nativeWidget = select.previousElementSibling; // 獲得自定義組件的值容器 var value = select.querySelector(".value"); // 獲得完整的選項列表 var optionList = select.querySelectorAll(".option"); // 設置選中索引為我們選擇的選項的索引 nativeWidget.selectedIndex = index; // 更新對應的值容器 value.innerHTML = optionList[index].innerHTML; // 高亮自定義組件中關聯的選項 highlightOption(select, optionList[index]); }; // 該函數返回原生組件當前選中的索引 // 需要一個參數: // select:類名為`select`且和原生組件關聯的DOM節點 function getIndex(select) { // 我們得為給定的自定義組件獲取原生組件 // 本例中,原生組件是自定義組件的兄弟節點 var nativeWidget = select.previousElementSibling; return nativeWidget.selectedIndex; };
我們可以用上面這兩個函數來綁定原生組件和自定義組件:
// 在文檔加載出來后處理下事件綁定 window.addEventListener("load", function () { var selectList = document.querySelectorAll(".select"); // 每個自定義組件都要被初始化 selectList.forEach(function (select) { var optionList = select.querySelectorAll(".option"), selectedIndex = getIndex(select); // 讓自定義組件能聚焦 select.tabIndex = 0; // 讓原生組件不可聚焦 select.previousElementSibling.tabIndex = -1; // 確保默認選擇的值被正確展示 updateValue(select, selectedIndex); // 用戶點擊選項時,更新對應的值 optionList.forEach(function (option, index) { option.addEventListener("click", function (event) { updateValue(select, index); }); }); // 用戶在聚焦的組件上按鍵盤時,更新對應的值 select.addEventListener("keyup", function (event) { var length = optionList.length, index = getIndex(select); // 當用戶按下箭頭時,跳到后一選項 if (event.keyCode === 40 && index < length - 1) { index++; } // 當用戶按上箭頭時,跳到前一選項 if (event.keyCode === 38 && index > 0) { index--; } updateValue(select, index); }); }); });
上面的代碼里,要注意tabIndex屬性的使用。該屬性用來確保原生組件不會獲得焦點,并確保自定義組件能在用戶用鍵盤或鼠標訪問時獲得焦點。
通過上面的工作,我們已經完成任務了!下面就是結果:
效果
等等,我們真的完成了嗎?
讓組件變得無障礙我們已經構建了一個可以運行的組件,雖然距離得到一個具有完整特性的選擇框還很遠,但它運行得還不錯。然而,我們之前所做的只是在處理DOM而已,這個組件并不是真正語義化的,而且雖然它看起來像個選擇框,但在瀏覽器的角度它卻并不是這樣,因此無障礙技術也不會認為它是個選擇框。簡而言之,它就是個無障礙性很差的漂亮選擇框!
幸運的是,我們有個解決方案叫ARIA。ARIA表示“無障礙的富Internet應用”,它是個W3C規范,用來讓web應用和自定義組件變得無障礙。基本上這個規范就是一系列拓展了HTML的特性,用這些特性,我們可以更好地描述角色、狀態和屬性,讓我們剛才設計的元素變得像其盡力模仿的原生元素一樣。使用這些特性很簡單,下面我們來試試。
role特性ARIA使用的關鍵特性是role。該特性會接收一個定義了元素用途的值,每個值都代表了元素的特點和行為。在本例中,我們會使用一個listbox作為role值,這個值是個“復合的role”,指定的元素可以包含多個特定role的子元素(本例中,至少有一個元素role值為option)。
值得注意的是,ARIA定義的role默認會自動用于標準的HTML標簽中。比如說, 要使用listbox這個role值,得像下面一樣修改HTML: 注意:如果你想兼容那些不支持CSS特性選擇器的老舊瀏覽器,同時使用role特性和class特性這種做法是必須的。 僅使用role特性是不夠的,ARIA本身也提供了很多許多狀態和屬性特性。對這些特性用得越多和越恰當,網頁就越能被無障礙技術所理解。在我們的例子中,只會用到一個特性:aria-selected。 aria-selected特性用于標記當前選中的選項,這樣無障礙技術就能提示用戶當前選中項是什么。我們會在JavaScript中動態地使用它,在用戶選中一個選項時能標記該選中項。為此,得修改下updateValue()函數: 上述修改的最終效果如下(訪問該組件時使用無障礙技術,譬如NVDA或VoiceOver,會有更好的體驗): 效果 至此我們已經了解了創建定制表單組件的所有基本知識,但如你所見,這么做并不簡單,如果使用第三方庫的話會比自己從頭寫起更好、更簡單(當然除非你是想構建這樣一個庫)。 下面是你在自己開發之前應該參考下的庫: jQuery UI msDropDown Nice Forms 更多的庫 若你想更進一步使用本例,為讓其中的代碼變得通用和可復用,還要對代碼做一些改進。這個練習你可以自己嘗試下,這里有兩個提示:首先,所有函數的第一個參數都相同,這就意味著這些函數需要有同一個執行上下文,使用一個對象來共享執行上下文是很明智的。此外,代碼還得保證兼容,即代碼最好能在兼容不同Web標準的多種瀏覽器下運行。 文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。 轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/50903.html 摘要:示例多選框和單選框給多選框和單選框添加樣式是很讓人凌亂的。通向漂亮表單之路一些有用的庫和拓展工具盡管在復選框和單選框上的表現力已經夠用了,但離其支持高級表單組件仍然遙遙無期。其表單部分挺有用的。
系列文章說明
原文
在本文中,我們將了解如何在HTML表單上使用CSS,為那些難于自定義的表單組件加以樣式。如前文所述,文本框和按鈕很適合使用CSS,而現在我們得來探索HTML表單樣式的那... 摘要:示例多選框和單選框給多選框和單選框添加樣式是很讓人凌亂的。通向漂亮表單之路一些有用的庫和拓展工具盡管在復選框和單選框上的表現力已經夠用了,但離其支持高級表單組件仍然遙遙無期。其表單部分挺有用的。
系列文章說明
原文
在本文中,我們將了解如何在HTML表單上使用CSS,為那些難于自定義的表單組件加以樣式。如前文所述,文本框和按鈕很適合使用CSS,而現在我們得來探索HTML表單樣式的那... 摘要:若你想在諸如元素的組件上應用高級樣式或者想定制組件的行為,你就只能選擇創建自己的表單組件。我們將通過本文學習如何構建一個表單組件。
系列文章說明
原文
在許多情況下,[可用的HTML表單組件]()是不夠的。若你想在諸如元素的組件上[應用高級樣式]()、或者想定制組件的行為,你就只能選擇創建自己的表單組件。
我們將通過本文學習如何構建一個表單組件。為達到目的,我們選擇重構元素作為例子... 摘要:若你想在諸如元素的組件上應用高級樣式或者想定制組件的行為,你就只能選擇創建自己的表單組件。我們將通過本文學習如何構建一個表單組件。
系列文章說明
原文
在許多情況下,[可用的HTML表單組件]()是不夠的。若你想在諸如元素的組件上[應用高級樣式]()、或者想定制組件的行為,你就只能選擇創建自己的表單組件。
我們將通過本文學習如何構建一個表單組件。為達到目的,我們選擇重構元素作為例子... 摘要:當你構建表單時,可以試著聽一下屏幕閱讀器如何讀取它,若聽起來很奇怪,那就有必要改進你的表單結構了。該規則必須在表單頭部以保證在用戶找到必填元素之前,屏幕閱讀器等無障礙設備能將其展示或讀給用戶。
系列文章說明
原文
在建立HTML表單時,最重要的一件事就是如何用正確的方式構建它。而之所以重要,原因有二:一是保證表單能被正確使用、二是這能保證你的表單是無障礙的(可以被能力不同的人使用)... 閱讀 1905·2021-11-25 09:43 閱讀 1405·2021-11-22 14:56 閱讀 3280·2021-11-22 09:34 閱讀 2010·2021-11-15 11:37 閱讀 2256·2021-09-01 10:46 閱讀 1396·2019-08-30 15:44 閱讀 2294·2019-08-30 13:15 閱讀 2393·2019-08-29 13:07元素對應grid,
元素對應list。因為我們的組件使用了
元素,所以得確保組件的listbox role能覆蓋掉
元素的list值。為此,可以使用presentation這個role值,該值用來指明一個沒有特殊含義的元素,而且該元素只用來展示信息而已。這里我們會給
應用presentation值。
aria-selected特性
function updateValue(select, index) {
var nativeWidget = select.previousElementSibling;
var value = select.querySelector(".value");
var optionList = select.querySelectorAll(".option");
// 確保所有的選項未被選中
optionList.forEach(function (other) {
other.setAttribute("aria-selected", "false");
});
// 確保選擇的那個選項被選中
optionList[index].setAttribute("aria-selected", "true");
nativeWidget.selectedIndex = index;
value.innerHTML = optionList[index].innerHTML;
highlightOption(select, optionList[index]);
};
相關文章
【譯】HTML表單高級樣式
【譯】HTML表單高級樣式
【譯】怎樣創建定制表單組件
【譯】怎樣創建定制表單組件
【譯】怎么樣構建HTML表單
發表評論
0條評論
wanghui
男|高級講師
TA的文章
閱讀更多
代理模式C++實現
Hadoop 入門筆記—核心組件 YARN
【C++】list詳解
Python爬蟲案例50篇-第8篇- 抓取某訊招聘的北京工作崗位
WPTao淘寶客插件配置淘寶聯盟和京東聯盟API信息
react知識點整理50問(未完待續)
CSS背景與邊框
使用原生js實現輪播圖效果