· 7分で読了

急速な変化の中でのフロントエンドに対する考察

この記事は中国語から自動翻訳されたものです。翻訳によりニュアンスが失われている場合があります。

セマンティクス(意味論)について再考する

そう考えたきっかけは、instant article のHTML構造を目にしたことだった。彼らはInstant Articleの構造が仕様に準拠することを規定しており、構造の表現も非常に明確だった。その中で、僕が今まで気にも留めていなかったHTMLタグをたくさん見かけた。例えば addressfigurecaptionsummary などだ。

気になってドキュメントなどを調べてみた。すると、実は多くのセマンティックなタグがすでに現在の主要ブラウザでサポートされており、spec(仕様)にも明確に書かれていることが分かった。しかし、現在のメインサイトの多くは依然として div + class という方式で表現されている。一部で header が適用されている箇所はあるものの、もっと適切なセマンティックタグを取り入れられると僕は考えている。不要なクラスの命名を減らせるだけでなく、HTMLの可読性やSEOも向上させることができる。何より重要なのは、僕たちが標準に準拠したHTMLを書いているということだ。

さらにW3CはHTML5において、navheaderdddt などのセマンティックなタグの普及に力を入れており、bfontcenter といった意味を持たないタグを削除または非推奨としている。

セマンティクスの最大の利点はアクセシビリティ(accessibility)にある。大半のスクリーンリーダーは特定のタグに対して最適化を行っており、例えば <a> ならハイパーリンクと読み上げられ、li を使えば現在のリストとその項目番号が読み上げられ、<main> を使えばメインコンテンツと読み上げられるなどだ。これらはすべてセマンティックタグを使用することによって得られるメリットである。

しかし、UIのユースケースは多種多様であり、タブの切り替え、ダイアログ、ドロップダウンメニュー、ツールチップなど、既存のタグだけでは対応できないケースも数多く存在する。これらはセマンティックタグだけでは解決できない。そうした時は、aria-*role という2つの属性(attribute)を参照し、その要素が何をしているのかをスクリーンリーダーに伝えることができる。

クラスに対する考察

語義化 css

これまで長くクラスを使ってきたが、改めて仕様(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属性にはトークンに関する特別な制限はないものの、望ましい表示(見た目)を記述する値ではなく、コンテンツの本質を表現する値を使うことが推奨されている。つまり、col-md-* のようなプレゼンテーション(表現)のためのクラス名は、実のところW3Cの仕様では推奨されていないのだ。だがその論理に従うと、世の中のCSS-in-JSのアプローチはほぼすべて白紙に戻さなければならなくなる。CSS Modulesはクラスをすべてハッシュ化するし、styled-components も同様だ。ハッシュ化する利点は名前の衝突を回避できることであり、本番環境のビルド時に最小化できる点もある。HTML上の要素が多い場合、削減できるファイルサイズは侮れない。 

なぜ標準に準拠すべきなのか?

  1. 標準仕様は委員会による研究と膨大な議論を経て策定された規約であり、統一性を保つために誰もが従うべきものだからだ。
  2. ブラウザは通常、さまざまなデバイス上でのこれらの要素の表示をあらかじめ最適化してくれている。
  3. 通常、これらの規約はベストプラクティス(best practice)である。
  4. なぜ僕たちは開発時間を節約するためだけに、標準に準拠しないWebページを書いて本末転倒なことをしてしまうのだろうか?
<!-- 元素展現 -->
<div class="margin-b-10">

</div>

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

</div>

僕自身の理解はこうだ。

なぜこのような状況になったのかというと、Webの発展初期にはCSSのサポートが不十分で、セマンティクスと見た目の表現とのバランスを取るのが難しく、当時の純粋なスタイル用である centerwidth が登場したからかもしれない。しかし、現代はもはやそんな制約に縛られた時代ではない。僕たちはセマンティクスを重視する時代へと進むべきであり、それこそが W3C が推進していることでもある。

グリッドシステムは素晴らしいものだ!

グリッドシステムが非常に使い勝手の良いパターンであることは認めるし、実際のユースケースではレイアウトをセマンティクスだけで表現できない問題にも直面する。だがセマンティクスの定義に照らし合わせ、より美しく可読性の高いHTMLを書くためには、僕たちはおそらくいつかグリッドシステムを脱却しなければならないだろう。これは大掛かりな作業になるが、現在のメインサイトのように大きくも小さくもない規模のアーキテクチャであれば、早めに着手するに越したことはない。

  • Susyの使用
  • @include や @extend

Page Visibility API

現在のユーザーがこのページにフォーカスしているかどうかを知ることができる。 多くの状況において、ユーザーがこのWebページにフォーカスしていない時(他のアプリに切り替えたり、タブを切り替えたりした時)には、不要なリクエストや処理を極力減らしたい。Facebookも、Webページに戻った時に初めてメッセージの通知音が鳴るようになっているようだ。 よくあるシチュエーションとしては動画の再生時だ。ユーザーがページから離れたら自動で動画を一時停止し、ユーザーが戻ってきたら動画の再生を再開させることができる。

JSのイベント伝播を振り返る

最近、サイ本(JavaScript: The Definitive Guide)を引っ張り出して読み直してみた。主に、以前は曖昧だった概念を整理するためだ。Web上にはあまりにも多くのJSライブラリが溢れているが、僕たちはネイティブなJavaScriptを忘れてしまってはいないだろうか?高度な抽象化は技術の発展に伴って必然的に起こる現象ではあるものの、内部の仕組みを理解しておくことは有益だし、今後のコーディングにも役立つはずだ。

JSのイベント伝播

JSのイベント伝播には主に bubble(バブリング)と capture(キャプチャ)の2種類があり、大半の伝播は bubble で行われる。bubble とは何か?ターゲット要素に登録されたイベントハンドラが呼び出された後、イベントは上に向かって浮上し始め(一部の要素の特定のイベントを除く)、先祖要素に登録されたハンドラを順に呼び出していく。この現象は document まで上昇し、最後には window に到達する。

実際の開発現場では、よくこのようなコードを見かける:

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

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

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

あちこちに散らばって登録されたイベントは、メンテナンスが困難なだけでなく、コードを探す際にも統一されたエントリーポイントがないため、デバッグが極めて難しくなる。そこで、JSのイベントバブリングの特性を利用して、document にイベントを一元登録することができる。jQueryの on の第2引数はイベント委譲(Event Delegation)の機能を提供しており、以下のようになる:

$('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]
		}
	})

このようにしておけば、今後新しいイベントハンドラを追加したい場合も actionList に追加するだけでよく、さらには extend などを組み合わせることで、必ずしも actionList 内に直接書かなくても良くなる。拡張性が大幅に向上する。

では、なぜキャプチャを使う人がこれほど少ないのだろうか?最大の理由は、あの愛すべきIEがサポートしていなかったことにある。さらに、イベントキャプチャは addEventListener を使った方法でのみ機能する。 イベントキャプチャはいわば逆向きのようなもので、まず最上位の先祖から始まり、順番に下へと伝わっていき、対象要素の親要素のイベントハンドラが呼び出されるまで続く。ターゲット要素自身に登録されたイベントハンドラがこのフェーズで呼び出されることはない。

イベントのキャンセル

僕たちはよく e.preventDefault() のようなメソッドを目にする。実は古いブラウザではこれがサポートされておらず、少しトリッキーな方法を使ってキャンセルする必要があった。

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

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

関連記事

他のトピックを探索