半熟前端

軟體工程師 / 台灣人 / 在前端的路上一邊探索其他領域的可能性

前端

快速變化下的前端思考

重新思考語義化這件事

會有這個想法,是看到 instant article 的 html 架構,他們規範 instant article 的架構必須符合他們的規範,而且結構的表達也很清楚。我在裡頭看到了好多我以前沒有注意過的 html tag。像是 address figure caption summary

好奇之下查了一下文件等等。發現其實有很多語義化的標籤都已經支持目前主流的瀏覽器,spec 也寫得很清楚,但是目前主站多還是以 div + class 的方式做表達,雖然有些地方會套用 header,但我認為有更多適合的語義化標籤可以加入使用。除了減少不必要的 class 命名,也能夠提高 html 的易讀性跟 SEO,重點是,我們寫的是符合標準的 html。

而且 w3c 在 html5 致力推廣語義化的標籤,諸如 nav header dd dt 等等,並且將一些沒有意義的 tag 刪除或是不推薦使用如 b font center 等等。

語意化最大的好處在於 accessibility,大部分的螢幕閱讀器都會對特定標籤做優化,例如在 <a> 在閱讀器上就會唸出超連結,用 li 會念出目前的清單跟現在是第幾項,用 <main> 會念出主要內容等等。這些都是使用語意化標籤帶來的好處。

不過 UI 使用場景百百種,不太可能每種情況都能透過既有的標籤處理,像是 tab 切換、dialog、下拉選單、tooltip 等等,這些都是沒辦法用語意化標籤解決的。這個時候可以參考 aria-* 以及 role 這兩個 attribute 來告訴閱讀器這個元素在做什麼。

對於 class 的思考

語義化 css

用了那麼久的 class,我回去找了找 spec,發現了 w3c 對 class 的描述。

There are no additional restrictions on the tokens authors can use in the class attribute, but authors are encouraged to use values that describe the nature of the content, rather than values that describe the desired presentation of the content. -w3c

雖然 class 並沒有使用上的規定,但是鼓勵盡量將 class 用於表達元素內容而非描述元素的展現。也就是說那些 col-md-* 等表現性的 class 名稱其實在 w3c 的 spec 裡面是不鼓勵的。不過如果按照這樣的說法,大概全部的 CSS-in-JS 的寫法都要砍掉重練了。css-module 會把 class 全部 hash 一遍、styled-component 也是,使用 hash 的好處是避免命名衝突,還有在 production 建構的時候可以最小化,當 HTML 上元素很多的時候省下的大小還是很驚人的。 

為什麼要符合標準?

  1. 標準規範是由委員會研究過、大量的討論過後所制定出來的規範,給大家遵守以便達到統一性。
  2. 瀏覽器通常已經幫你優化過這些元件在不同裝置上的顯示
  3. 通常這些規範是 best practice。
  4. 為什麼我們要為了節省開發時間而寫出不符標準的網頁本末倒置?
<!-- 元素展現 -->
<div class="margin-b-10">

</div>

<!-- 內容 -->
<div class="user_info">

</div>

自己的理解是這樣。

至於為什麼會造成這樣的原因,或許是因為在網頁發展初期,CSS 的支持性並不好,在語義化跟表現之間很難得到平衡,才會有當時純 style 的 center width 出現。但現在已經不是那個綁手綁腳的年代了。我們應該朝向語義化的年代前進,而且這也是w3c在推廣的事情。

grid system 是個很棒的東西耶!

我承認 grid system 的確是個非常好用的模式,在實際場景也會遇到 layout 無法用語義化來表示的問題,但根據語義化的定義,為了寫出更好看的 HTML 跟易讀性,我們或許總有一天還是要把 grid system 拔掉。這會是個大工程,但在目前主站說大不大,說小不小的架構上,還是越早開始越好吧!

  • 使用 susy
  • @include @extend

Page Visibility API

能夠知道目前 user 是否 focus 在這個 page 上。 在很多情境下,我們希望當使用者沒有聚焦在這個網頁上(可能跳去別的應用程式、切換分頁時),可以盡量減少不必的請求或操作。facebook 好像也是當你回到網頁時才會有訊息的提示聲音。 比較常見的情景是播放影片時,如果使用者跳出頁面,我們可以先自動讓影片停止,等使用者回來之後,影片在繼續播放。

回頭看看 js 的事件傳播

最近把犀牛書拿回來翻了翻,主要是為了釐清以前不是那麼明白的觀念。太多 js library 充斥在網路,我們是否已經忘記原生的 js 了?雖然高度的抽象化是科技趨於發達後一定會有的現象,但是了解一下內部的運作也是好的,對於之後寫 code 也會比較有概念!

js 事件傳播

js 的事件傳播主要分為兩大類型,bubblecapture,大部分的傳播方式是用 bubble。什麼是 bubble 呢?在註冊對象元素的事件處理器被調用之後,事件就會開始往上漂浮(不包含某些元素的特定事件),然後再調用註冊於祖父元素上的處理器。這種現象會上升到 document 最後到達 window

在實際應用上,我們時常看到:

$(".abc").on('click', e => {
	
});

$(".ass").on('click', e => {
	
});

$(".asass").on('click', e => {
	
});

散亂的事件註冊在角落,不僅維護上困難,在尋找 code 的時候也沒有統一入口,非常難以除錯。於是我們可以利用 js 事件的冒泡特性,為 document 統一註冊事件。jQuery 的 on 第二個函數便提供了事件委託的功能,如下:

$('document').on('click','.sass', e => {
 
});

這樣的好處不僅減少了散亂的事件註冊,還統一了入口。如果要新增事件,只要在 document 統一做擴充即可。我們還可以在 html 這樣寫:

	<a  class="js_action" data-action="foo">
	<a  class="js_action" data-action="bar">
  var actionList = {
  	foo: function(),
  	bar: function()
	}
	$('document').on('click','.js_action', e => {
		if(typeof e.target.dataset.action === 'function'){
			actionList[e.target.dataset.action]
		}
	})

像這樣,以後如果要增加新的 event handlder 只要在 acionList 新增就好,甚至搭配 extend 的方式,可以不用寫在 actionList 也沒關係。充分提高了擴充性

那麼,為什麼那麼少人使用 capture 呢?最大的原因在於因為可愛的 IE 無法使用。再來事件捕捉只適用於 addEventListener 的方式。 事件捕捉有點像是反過來,會先從祖父開始,依序向下船,直到事件父元素的事件處理被被調用為止,註冊於事件元素的事件處理器永遠不會被調用。

事件取消

我們也常常看到類似 e.preventDefault() 的方法。其實像是舊版的瀏覽器並不支援,我們可以用一些比較 tricky 的方式來做取消。

function cancelDefault(event) {
	var event = event || window.event;

	if(event.preventDefault) event.preventDefault()
	if(event.returnValue) event.returnValue = false
	return false
}