「h要素」に思う

検索ヒット率の向上には「h要素」が大事、いやいやコンテンツの方が大事などと、ひと昔前は盛んに書かれていたのが、今時は YouTube再生回数~億ビューなんぞと「注目される事が最優先」という、なんだかな世相。 でもこの流れは、本当に語られるべき事が「文字」に戻って来たとすれば、むしろ好機かも知れません。

 

本、小説、文書などには「題」「表題」「見出し」「目次」「あとがき」などがありますが、これは人が文字を扱う歴史で、長い内容を分かり易く纏めた結果でしょう。 この分類化は、デジタルの無い時代からあります。「HTML」が作られ、大規模な文書をネット上で扱う時代になり、分類化の技法が「HTML」の仕様に取り込まれて、「h要素」「heading」になったと考えて良いと思います。

 

これは、やはりデジタル文書をより読み易く、内容の流れを判り易くする機能です。 「h要素」など使わなくてもブログは書けますけどね。

 

 

深層から蘇った記事 

2092年のある日、スチューデントQは、半世紀以上前のインターネット文化を調べていて、興味深い発見をする。 骨董品のディスクからQが苦労して読み出したのは、とあるブログ記事のデータだった。

 

Qはデータの最初を調べ、記事が「snowman」による「アメーバブログの終焉」だと気付いた。 これは長く謎とされていた記事に違いないとQは思った。 同名の記事は、2031年に一旦公開されてすぐに削除され、そこにはブログ崩壊のきっかけとなった「snowman事件」の真相が、精細に書かれていると言われていたのだ。 世に知られた「事件」の真相に触れようとしている事に気付いて、Qは指が震えた。

 

<!doctype html><html lang="ja" id="no-js" class="columnB fixed" data-base-skin-code="uranus" data-skin-code="ur_std_pf_cssedit" lang="ja"><head><meta charset="UTF-8"><meta name="referrer" content="origin"><meta data-react-helmet="true" property="fb:app_id" content="811629842356842"/><meta data-react-helmet="true" property="og:locale" content="ja_JP"/><meta data-react-helmet="true" property="og:title" content="『アメーバブログの終焉』"/><meta data-react-helmet="true" property="og:type" content="article"/><meta data-react-helmet="true" property="og:url" content="https://ameblo.jp/snowman/entry-29838736166.html"/>…

 

このデータは、当時に「ブラウザ」と呼ばれたプログラムで再生できる。 Qはそれを知っていたが、研究用のマシンは文字を復元出来ても、そんなプログラムは動作しない。「多元エミュレーター」という装置を聞いた事があるが、大学にそんなものがあるとは思えなかった。

 

Qは1週間余りかかって、記事のテキストを全て取り出して読める様にした。 これまで世に出なかった事実に関する記述を見つける度に、解析はそっちのけになった。 そして、整理が一向に進まない。「このままではあかん。 これを公開するには、記事をもっと読み易くせな。」 そう思い立ったQは、ゼミの教授の部屋に出向いた。

 

Q:「先生、インターネット全盛の時代の文書データを見つけて、解析をしてるんです。 一応は読める様になったんですが、文章がみんなずらずらと繋がって、手がつけられなくて、困ってしまったんです」

 

教授:「ははあ、面白い事やってんねんな。 それはきっとHTMLというデータやと思うけど。」

 

Q:「そうなんです、80年位前に流行したブログの記事なんです。」

 

教授:「君は、タグ構造の事は知ってるか?」

 

Q: 「はい、判ってるつもりです。 読める様に、タグを全部外したんです。」

 

教授:「そんならね、もういっぺん元のデータで、h1とかh2とかというタグを探して、そこが文書の"見出し"と思って整理しなおしたら、うまく行くと思うな。」

 

Q: 「そんな裏技があるんですか! 知らんかったです。」

 

数日後、Qは記事の再構成を終わらせていた。 教授に教わった事を最初から知っていたら、倍ほど早く終わったんだなと思った。 整然とした記事が蘇ると、snowmanの気質が見えた気がした。 そして、Qは今回の発見を纏めた論文を書き始めた。 これは間違いなく、世に問うに値する発見だと確信していた。

 

そうだ、副題は「みだしはみだしなみ」にしよう。

 

 

まあ下手な例え話になりましたが、文章に「文節」「句読点」がある様に、「表題」「見出し」で、内容が一目で分かり易くなります。 敢えてそれを無視して効果を得るのも、表現の自由、醍醐味ですが、「高度なインプロビゼーションは、高度に定型が判っている人による」とは、私が信じるところです。

 

 

 

タグ種の変換方法は余り書かれていない 

ネット上を探しても、「h要素」の変換テクニックについて、適確な記事が見つけられません。 これは「outerHTML」を使わないと、大変手間で不完全な結果になります。

 

outerHTML」については以下のページを参照ください。

 

 

 

 「h2要素」を「h3要素」に変換する JavaScript

以下は、「h2要素」を「h3要素」に変換する JavaScriptコードの雛形です。 こういう作業コードを作りたいと思ったら、参考にしてください。

 

function replace_tag(element){
    let elem_text=element.outerHTML.toString();
    elem_text=elem_text.replace('<h2 ', '<h3 ');
    element.outerHTML=elem_text; }

 

◎ 2行目で、変換対象の「element」のタグの頭「<h2 ……」から「…</h2>」までの全てを文字列にして、変数「elem_text」に取得します。

 

◎ 3行目で、文字として「<h2」を「<h3」に書換えています。

 

◎ 4行目で、元の「element」を、書換えた内容の「HTML要素」にします。

 

〔注意1〕

この関数の処理によって、元の変改対象の要素は、新しく書換えた要素になります。 「h2要素」の中身は全て同じまま、HTML編集で「h3」に書換えたのと同じです。 ただし、JavaScriptからの参照は途切れた新要素になり、変換後に JavaScriptで扱うには、再取得が必要です。

 

〔注意2〕

この関数は、「h要素」という親戚のタグ種間の変更を前提にしています。「p要素」「div要素」の変換にも応用が可能ですが、「親戚のタグ種間」でない場合は、変換で生じる結果を良く検証する必要があります。 例えば、「a要素」を「span要素」に書き換えると、当然にリンク機能は失われます。

 

 

 「要素」変換コードの精密版 JavaScript

上記の雛形コードは、広範囲に利用されている文書エディター「ckeditor」上で制作したのですが、このエディターの「終了タグ(閉じタグ)の自動補完」が動作する事を前提としていました。

 

ただ、この自動補完機能は、様々な条件のタグ書換えでは危ういという事を、経験のある方はすぐに気付かれると思います。 実際、ここで紹介している「Rep Heading」というツールでは、「h要素」間の変換は問題なく利用できますが、「p要素」➔「h要素」の変換では、不明な空タグの「p要素」が生成されて混入しました。

 

やはり、編集補助機能に「終了タグ」の生成を期待するのは、不完全なコードと言えます。 以下の雛形コードは「終了タグ」を書換えるコードを追加したもので、正規表現を使っています。 このコードは、より確実にタグ種の変換が出来ます。

 

function replace_tag(element){
    let elem_text=element.outerHTML.toString();
    elem_text=elem_text.replace(/^<h2/, '<h3').replace(/h2>$/, 'h3>');
    element.outerHTML=elem_text; }

 

 

 

 「Rep Heading ⭐」の機能と操作

ツール名「Rep Heading ⭐」は、編集画面に関する起動強化コードを使う「⭐」を付けています。 このツールは常駐型で、「Tampermonkey」にインストールして常に「ON」にしておきます。 編集画面を開くと、このツールが自動で起動します。

 

 

「h要素」の種類と場所を表示 

通常はステルスですが、「h2」「h3」がページ上に作成されると、編集枠の左外に「h要素」の種類を表示します。「h2」は赤、「h3」は黒の文字色です。

(下図の編集枠色などは Ameblo Writer によるデザインです)

 

 

 

 「h要素」の範囲

下は、3個の「h要素」を作った例で、青枠は各要素の実際の範囲を示しています。

表示上は見えませんが、「h要素」は「ブロックレベル要素」なので、ページの両端まで達する範囲を占めます。

 

 

 

 「h要素」の種類変更

これが「Rep Heading ⭐」の主機能です。

 

●「h要素」の範囲を「Ctrl+左Click」すると、「h2」⇄「h3」が入れ替わります。

▪ この操作の結果は、常に枠外の表示に反映し、何度でも変更できます。

▪ 枠外の「h要素」の表示部も、クリックして変更操作ができます。

 

〔注〕

現在、対応する「h要素」は「h2」「h3」のみで、通常生成されない「h1」や「h4」は、対応していません。

 

 

 

「Rep Heading ⭐」を利用するには

このツールは Chrome / Edge / Firefox版の拡張機能「Tampermonkey」上で動作します。 以下に、このツールの導入手順を簡単に説明します。

 

❶「Tampermonkey」を導入します

◎ 使用しているブラウザに拡張機能「Tampermonkey」を導入する事が必要です。

既に「Tampermonkey」を導入している場合は、この手順 ❶ は不要です。 

拡張機能の導入については、以下のページに簡単な説明があるので参照ください。

 

 

❷「Tampermonkey」にスクリプトを登録します

◎「Tampermonkey」の「」マークの「新規スクリプト」タブを開きます。

 

 

◎「新規スクリプト」には、最初からテンプレートが記入されています。 これは全て削除して、完全に空白の編集枠に 下のコードをコピー&ペーストします。

 

〔コピー方法〕 右サイドバーの   マークのボタンを1度押してください。

 コード枠内の右クリック ➔ コード全体の選択 ➔ コピー操作 が可能になります。

 

◎ 最後に「ファイル」メニューの「保存」を押すと、ツールが使用可能になります。

 

 

〔 Rep Heading ⭐ 〕 ver. 0.1

 

// ==UserScript==
// @name         Rep Heading ⭐
// @namespace  http://tampermonkey.net/
// @version      0.1
// @description  記事デザインの「h2」「h3」を「Ctrl+左Click」で変換する
// @author       Ameba Blog User
// @match        https://blog.ameba.jp/ucs/entry/srventry*
// @exclude      https://blog.ameba.jp/ucs/entry/srventrylist.do*
// @grant        none
// ==/UserScript==


let retry=0;
let interval=setInterval(wait_target, 100);
function wait_target(){
    retry++;
    if(retry>10){ // リトライ制限 10回 1sec
        clearInterval(interval); }
    let target=document.getElementById('cke_1_contents'); // 監視 target
    if(target){
        main(); }}



function main(){
    let target=document.getElementById('cke_1_contents'); // 監視 target
    let monitor=new MutationObserver(insert_tag);
    monitor.observe(target, {childList: true});

    insert_tag();

} // main()



function insert_tag(){
    let style=
        '<style class="rep_head">h2::before { content: "h2"; position: absolute; left: -36px; '+
        'padding: 2px 4px 0; height: 18px; font: bold 16px/19px Meiryo; '+
        'border: 1px solid #aaa; background: #fff; color: red; } '+
        'h3::before { content: "h3"; position: absolute; left: -36px; '+
        'padding: 2px 4px 0; height: 18px; font: bold 16px/19px Meiryo; '+
        'border: 1px solid #aaa; background: #fff; color: #000; }</style>';

    let editor_iframe=document.querySelector('.cke_wysiwyg_frame');
    if(editor_iframe){
        let iframe_doc=editor_iframe.contentWindow.document;
        if(iframe_doc){
            if(!iframe_doc.querySelector('.rep_head')){
            iframe_doc.documentElement.insertAdjacentHTML('beforeend', style); }}}


    if(editor_iframe){
        let iframe_doc=editor_iframe.contentWindow.document;
        if(iframe_doc){
            let target=iframe_doc.body; // 監視 target
            if(target){
                let monitor=new MutationObserver(change_tag);
                monitor.observe(target, {childList: true}); }}}

    change_tag();

} // insert_tag()



function change_tag(){
    let editor_iframe=document.querySelector('.cke_wysiwyg_frame');
    if(editor_iframe){
        let iframe_doc=editor_iframe.contentWindow.document;
        if(iframe_doc){
            let h2_elem=iframe_doc.querySelectorAll('h2');
            for(let k=0; k<h2_elem.length; k++){
                h2_elem[k].onclick=function(event){
                    if(event.ctrlKey){
                        event.stopImmediatePropagation();
                        replace_tag(h2_elem[k]); }}}

            let h3_elem=iframe_doc.querySelectorAll('h3');
            for(let k=0; k<h3_elem.length; k++){
                h3_elem[k].onclick=function(event){
                    if(event.ctrlKey){
                        event.stopImmediatePropagation();
                        replace_tag(h3_elem[k]); }}}



            function replace_tag(element){
                let alt_elem=element.outerHTML.toString();

                if(witch_h(element)==2){
                    alt_elem=alt_elem.replace('<h2', '<h3'); }
                else if(witch_h(element)==3){
                    alt_elem=alt_elem.replace('<h3', '<h2'); }

                element.outerHTML=alt_elem; // h2⇄h3の書換


                function witch_h(elem){
                    if(elem.tagName=='H2'){
                        return 2; }
                    else if(elem.tagName=='H3'){
                        return 3; }
                    else return 0; }

            } // replace_tag()


        }}} // change_tag()


 

 

 

「Rep Heading ⭐」最新版について 

旧いバージョンの JavaScriptツールは、アメーバのページ構成の変更で動作しない場合があり、導入する場合は最新バージョンをお勧めします。

 

●「Rep Heading ⭐」の最新バージョンへのリンクは、以下のページのリンクリストから探せます。