WCAG 2.0 / JIS X 8341-3:2016の達成基準「4.1.1 構文解析」を楽にするbookmarklet

## 達成基準「4.1.1 構文解析」の実施

新しいWCAGでは「廃止・削除」の扱いになっている達成基準「4.1.1 構文解析」ですが、JIS X 8341-3:2016では健在です。

その4.1.1の求める内容を見てみます。

> 要素には完全な開始タグ及び終了タグがあり、要素は仕様に準じて入れ子になっていて、要素には重複した属性がなく、どの ID も一意的である。

このチェックを行う際に便利なのがW3Cが提供している[nu HTML Checker](https://validator.w3.org/nu/)です。HTMLの構文チェックを行ってくれます。

## nu HTML Checkerによる多岐にわたるエラーの内容

実際に使ってみると、いかのようなエラーが出てきます。

- Warning: The type attribute is unnecessary for JavaScript resources.
- Info: Trailing slash on void elements has no effect and interacts badly with unquoted attribute values.
- Error: Bad value origin-trial for attribute http-equiv on element meta.
- Error: Element style not allowed as child of element body in this context.
- Warning: The charset attribute on the script element is obsolete.

まあ、こういったエラーをちくちく潰していくのも楽しいのですが、アクセシビリティの試験の際、4.1.1の求める内容を確認する上では、たくさんのエラーはノイズになります。

## エラーをフィルタリング

[WCAG Parsing Validation Filter bookmarklet](https://dotjay.github.io/wcag-parsing-filter/bookmarklet/)というものがあります。そのまま持ってくると以下のとおりなんですが、要は、4.1.1の求めるエラーだけ、フィルタしてくれるブックマークレットなのです。

```JavaScript
javascript:(function(){javascript:(function(){var filters=["tag seen","Stray end tag","Bad start tag","violates nesting rules","Duplicate ID","Unclosed element","not allowed as child of element","unclosed elements","unquoted attribute value","Duplicate attribute","descendant of an element with the attribute"].join("|"),groups={"Duplicate ID":true},e,g,i,m,nT=0,nP1=0,r,rt,res=document.getElementById("results"),rP1={};if(!res){return;}res=res.getElementsByTagName("li");for(i=res.length-1;i>=0;i--){r=res[i];if(r.id.substr(0,3)==="vnu"){if(r.className!=="info"){nT=nT+1;}rt=""+r.textContent;rt=rt.substring(0,rt.indexOf('.'));m=rt.match(filters);if(m==null){r.style.display="none";r.className=r.className+"a11y-ignore";}else{e=rt.substr(7);g=m[0];if(groups.hasOwnProperty(g)){rP1[g]=rP1[g]||{};e=e.substr(g.length+1);rP1[g][e]=true;}else{rP1[e]=true;}nP1=nP1+1;}}}rt="";for(i in rP1){if(rP1.hasOwnProperty(i)){e=rP1[i];if(e===true){rt=rt+"- "+i+"\n";}else{rt=rt+"- "+i+"\n";for(m in e){if(e.hasOwnProperty(m)){rt=rt+"  + "+m+"\n";}}}}}alert(nT+" validation errors and warnings.\n"+nP1+" instances of errors known to create accessibility issues:\n"+rt);})();})();
```

nu HTML Checkerのチェック結果の画面で使うと、4.1.1が対象とするエラー以外を非表示にしてくれます。

## あわせて一本

上記ブックマークレットは、このブックマークレットと一緒に使うと便利です。このブックマークレットは、いま見ているページをnu HTML Checkerにかけてくれるものです。

```JavaScript
javascript:(function()%7Bfunction%20c(a,b)%7Bvar%20c%3Ddocument.createElement(%22textarea%22)%3Bc.name%3Da%3Bc.value%3Db%3Bd.appendChild(c)%7Dvar%20e%3Dfunction(a)%7Bfor(var%20b%3D%22%22,a%3Da.firstChild%3Ba%3B)%7Bswitch(a.nodeType)%7Bcase%20Node.ELEMENT_NODE:b%2B%3Da.outerHTML%3Bbreak%3Bcase%20Node.TEXT_NODE:b%2B%3Da.nodeValue%3Bbreak%3Bcase%20Node.CDATA_SECTION_NODE:b%2B%3D%22%3C!%5BCDATA%5B%22%2Ba.nodeValue%2B%22%5D%5D%5C%3E%22%3Bbreak%3Bcase%20Node.COMMENT_NODE:b%2B%3D%22%3C%5C!--%22%2Ba.nodeValue%2B%22--%5C%3E%22%3Bbreak%3Bcase%20Node.DOCUMENT_TYPE_NODE:b%2B%3D%22%3C!DOCTYPE%20%22%2Ba.name%2B%22%3E%5Cn%22%7Da%3Da.nextSibling%7Dreturn%20b%7D(document),d%3Ddocument.createElement(%22form%22)%3Bd.method%3D%22POST%22%3Bd.action%3D%22https://validator.w3.org/nu/%22%3Bd.enctype%3D%22multipart/form-data%22%3Bd.target%3D%22_blank%22%3Bd.acceptCharset%3D%22utf-8%22%3Bc(%22showsource%22,%22yes%22)%3Bc(%22content%22,e)%3Bdocument.body.appendChild(d)%3Bd.submit()%7D)()%3B
```

## 加えてもう一つ

id属性の重複は4.1.1での不適合要件なのですが、試験をしているとしばしばと出てくるのが`Duplicate ID <code></code>.`——つまり、「空文字のidが複数あって、これが重複だ」というエラーです。

「[H93: ウェブページの id 属性値が一意的 (ユニーク) であるようにする](https://waic.jp/translations/WCAG21/Techniques/html/H93)」では次のように書かれています。

> 異なる要素に同一の id 属性値があることによって、支援技術がコンテンツを解析しようとする際に問題が生じるエラーを回避することである。

たとえばアクセシビリティを確保するために依存しているJavaScriptがうまく動かなくなったり、`id`によって、`label`や`aria`との機械可読性が確保されなくなったりすることがあるんじゃないかというのが問題なんでしょうね。

でも、空の`id`はそういった問題とは原則無縁なので、これも非表示にします……ということをしてくれるのが、つぎのブックマークレット。

```JavaScript
javascript:(function(){ var errors = document.querySelectorAll('li.error'); var count = 0; errors.forEach(function(li){ if (li.textContent.includes('Duplicate ID .')) { li.style.display = 'none'; count++; } }); var errors = document.querySelectorAll('li.warning'); errors.forEach(function(li){ if (li.textContent.includes('The first occurrence of ID')) { li.style.display = 'none'; } }); alert(count + ' Duplicate ID <code></code> errors have been hidden'); })();
```

じつは、nu HTML Checker自体にもエラーのフィルタ機能はあるので、そこで空の`id`の重複は非表示にできるのですが、まあ、いちいちフィルタかけるのも面倒なので。