HTMLに書き込まれる文字数

「Draw The Line ⭐」の制作時に少し気になっていたのは、HTMLに書き込まれる文字数が、一般的な文字修飾のタグコードに対してかなり多いという点です。

 

下の様な Ameba Pick のアフィリエイト商品表示枠は、1個で2500文字程度の文字数があり、それに比べたらずっと少ないのですが。(注:下は画像化したものです)

 

 

 

 

実際の装飾線の文字数をカウント 

実際の文字数を調べてみました。 カラー設定は下の様なものです。

 

 

この「単線」のアンダーラインを記入すると下の様なコードになり、下線付けで追加される文字数は「150文字」です。

 

<span style="background: linear-gradient(transparent 1.23em, rgb(143, 105, 255) 0px, rgb(143, 105, 255) calc(1.23em + 2px), transparent 0px);">単線</span>

 

ちなみに、編集アイコンの下線付けをすれば「48文字」です。

 

2重線のアンダーラインの場合は更にコードが複雑になり、文字数も増えます。

この「2重線」のコードは以下で、追加文字数は「262文字」です。

 

<span style="background: linear-gradient(transparent 1.23em, rgb(143, 105, 255) 0px, rgb(143, 105, 255) calc(1.23em + 1px), transparent 0px, transparent calc(1.23em + 2px), rgb(143, 105, 255) 0px, rgb(143, 105, 255) calc(1.23em + 3px), transparent 0px);">2重線</span>

 

10箇所や20箇所では平気ですが、不必要に装飾線を多用すると、かえって散漫で何が重要か判らない記事になります。 装飾線は適度に有効に使うべきでしょう。

 

 

カラー名の指定は文字数の節約になる 

ただ、上の「線色」は意図的に「rgb値(3桁,3桁,3桁)」となる色を選んでいます。透過設定で少し増えますが、逆に「10~20文字」程度少なくなる色も多くあります。

 

また、「red」「blue」等のカラー名で線色を指定すると、ブラウザの仕様のためか「rgb値」に変換されず、そのままHTMLに書き込まれます。「red」を使った場合は、単線「120文字」、2重線「202文字」となり、ずいぶん文字数が節約されます。

 

アメブロは文字数の上限が少ないので、文字数制限がきわどい場合は、カラー名指定の工夫を覚えておくと良いと思います。

 

 

 

文字数を減らす試み(実は全くの失敗) 

上の実際のHTMLコードを見ると「#8F69FF」が自動的に「rgb(143, 105, 255)」に変換されてHTMLに記入されています。 この変換は「編集画面」のシステムではなく、ブラウザによる変換だと私は思っています。

 

この「HEX値」→「RGB値」の変換を見逃していたので、「HEXカラーコードの短縮で文字数節約が出来る」という勘違いをしていました。 例えば「#FF0000」(赤)を「#F00」の様に指定するのがHEXカラーの短縮表記です。 しかし、カラー値入力枠に短縮表記で入力しても、HTMLには「rgb(255, 0, 0)」が書込まれ、短縮した意味がありません。

 

というわけで、この案は無意味でしたが、これが有効と思って作った自動変換のコードがもったいないので、以下に載せておきます。

 

 

 

「00」「11」…「EE」「FF」に近い値を探す 

「#+16進6桁」を「#+16進3桁」に変換するのは、近似のカラー値を求める操作になります。 最初、この様なコードを探したのですが、以下に興味深いコンペティション記事がありました。 いかに簡単にそのコードを書くかを競っている様ですが、残念ながらJavaScriptのコードは「Node.js」で利用できません。

 

   最も近い3桁の16進数の色を見つける 

 

しかし少し考えると、変換コードはそう難しくはなさそうで、自分で書いてみました。 案外とネット上にはないコードで、必要な方が居るかも知れません。

 

 

どの様に求めるか 

「#+16進6桁」は「#+16進2桁+16進2桁+16進2桁」で3原色の値を表示しています。 これを「#+16進1桁+16進1桁+16進1桁」に短縮するには、16進2桁に近い16進1桁を、3原色のひとつずつで探すことになります。

 

下の下段は16進2桁の数の「10~24」の間を並べたものですが、16進2桁は「00」~「FF」まで、10進で「255」の値のどれかを指します。 これが、ひとつの原色に対して与えられる数値です。

 

                                 
10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24

 

この中で、「00」「11」「22」…「EE」「FF」の場合(●の値)に、区切り良く「0」「1」「2」…「E」「F」の16進1桁に置き換える事が出来ます。 上の範囲で「●」と「●」の間は「17」あり、これは他の場所でも同じです。

 

今、与えられた値が「11」~「22」の間とすると、値が「19」以下の場合は「1」、値が「1A」以上の場合は「2」に変換すれば、2桁のコードを1桁のコードに短縮できます。

 

これをコードにすれば、「#+16進6桁」を「#+16進3桁」に近似的に短縮するコードになります。

 

 

「HEX6桁→3桁」短縮変換コード 

下は、HEX6桁(color7)を HEX3桁(color4)に短縮するコードです。

変換対象を「color7」としているのは「#」を1文字と数えているからで、結果の「color4」も同じ理由です。

 

function reduce(color7){
    let ch=color7.split('');

    let color4='#' + avc(1, 2) + avc(3, 4) + avc(5, 6);
    return color4;

    function avc(x, y){
        let str=ch[x]+ch[y];
        let d=parseInt(str, 16);
        let chr=Math.floor(d/17);
        if(d%17>8){
            chr=chr+1; }
        return chr.toString(16); }} // 16進1桁の平均カラー値 

 

 

 「HEX8桁→4桁」短縮変換コード 

以下は少し変え、アルファ値付きの HEX8桁(color9)を HEX4桁(color5)に短縮するコードです。

 

function reduce(color9){
    let ch=color9.split('');

    let color5='#' + avc(1, 2) + avc(3, 4) + avc(5, 6) + avc(7, 8);
    return color5;

    function avc(x, y){
        let str=ch[x]+ch[y];
        let d=parseInt( str, 16);
        let chr=Math.floor(d/17);
        if(d%17>8){
            chr=chr+1; }
        return chr.toString(16); }} // 16進1桁の平均カラー値

 

 

 

テストツール と操作の方法

以上の「短縮カラーコード」を生成するテストツールです。 実装は手を抜いているので、操作の仕様が少し変わっています。

 

❶ ショートカットが同じ他のテストツールや「Drew The Line⭐」をOFFにしておきます。「Ctrl + F3」でコントロールパネルが表示されます。 扱いは以前のテストツールと同じです。

 

❷「カラー値入力枠」に手入力か「Ctrl + 左クリック」でカラー設定パレットを表示して、「#+16進6桁」または「#+16進8桁」のカラーコードを入力します。

 

❸「透過度」の初期値「1」を変更します。 この操作で、近似色の短縮コードに変更されます。

 

❹「透過度」を操作しているので、その間の短縮コードは「#+4桁」になりますが、「透過度」を「1」に戻すと「#+3桁」の短縮コードが得られます。

 

 

短縮コードの色の検証 

得られた短縮コードと元のカラー値の違いを確認したい場合は、カラー設定パレットを使ってカラー値を入力し、❷~❹の操作で短縮コードを得て、もういちどカラー設定パレットを表示し短縮前の色を表示させます。 これで、処理結果の入力枠の色と処理前の元の色との比較が出来ます。

 

 

 

 

テストツール のコード

このコードは Chrome / 新Edge / Firefox の「Tampermonkey」上で動作します。 

 

このコードを実行して試すには、各ブラウザの「Tampermonkey」の「新規スクリプト」の編集画面で、最初から登録されているテンプレートを削除して完全に空白にした上で、以下のコードをコピー&ペーストして「保存」してください。

 

〔コピー方法〕 軽量シンプルなツール「PreBox Button   」を使うと

  コード枠内を「Ctrl+左Click」➔「Copy code 」を「左Click」

  の操作で、掲載コードのコピーが可能になります。

 

 

〔 Color Code Test ◪ 〕ver. 0.3

 

// ==UserScript==
// @name         Color Code Test ◪ 短縮カラーコードの生成
// @namespace  http://tampermonkey.net/
// @version      0.3
// @description  HEXカラー値の短縮カラーコードを生成するテストコード
// @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){
        clearInterval(interval);
        main(); }}


function main(){
    let editor_iframe;
    let iframe_doc;
    let selection;
    let range;
    let task=0; // アンダーライン・マーカー線・消し線・終了
    let add_padd; //「MS Pゴシック」のために padding-bottom追加フラグ

    let read_json;
    let setting; // 入力枠の設定とユーザー設定値登録

    let ua=0; // Chromeの場合のフラグ
    let agent=window.navigator.userAgent.toLowerCase();
    if(agent.indexOf('firefox') > -1){ ua=1; } // Firefoxの場合のフラグ



    read_json=localStorage.getItem('Draw_Line'); // ローカルストレージ 保存名
    setting=JSON.parse(read_json);
    if(setting==null){
        setting=[['DrawTheLine','0','0','0'],['1','1.23','#333','0'],['1','1.23','#333','0'],
                 ['0.6','0.7','#ccc','0'],['1','0.66','#333','0'],['1','0.54','#333','0']]; }
    let write_json=JSON.stringify(setting);
    localStorage.setItem('Draw_Line', write_json); // ローカルストレージ 保存


    let target=document.getElementById('cke_1_contents'); // 監視 target
    let monitor=new MutationObserver(catch_key);
    monitor.observe(target, {childList: true}); // ショートカット待受け開始

    catch_key();

    function catch_key(){
        if(document.querySelector('.cke_wysiwyg_frame') !=null){ //「通常表示」から実行開始
            editor_iframe=document.querySelector('.cke_wysiwyg_frame');
            iframe_doc=editor_iframe.contentWindow.document;
            selection=iframe_doc.getSelection();

            iframe_doc.addEventListener('keydown', check_key);
            document.addEventListener('keydown', check_key);

            function check_key(event){
                let gate=-1;
                if(event.ctrlKey==true){
                    if(event.keyCode==114){
                        event.preventDefault(); gate=1; }
                    if(gate==1){
                        event.stopImmediatePropagation();
                        do_task(); }}}

            function do_task(){
                if(task==0){
                    task=1; // スタート時のモード切替 💢
                    panel_disp();
                    set_panel();
                    draw_line(); }
                else if(task==1 || task==2){
                    task=0;
                    panel_remove(); }}
        }} // catch_key()



    function draw_line(){
        show_color();
        pick_color();

        let l_type=document.querySelector('#l_type');
        let single=document.querySelector('#single');
        let double=document.querySelector('#double');
        let l_trance=document.querySelector('#l_trance');
        let l_color=document.querySelector('#l_color');
        let ms=document.querySelector('#ms');

        single.checked=true;
        // double.checked=true; // スタート時のモード切替 💢
        l_color.value=setting[1][2];
        test_colorE(l_color.value); // test_colorEを実行 ⏹

        double.onclick=function(){
            double.checked=true;
            if(task==1){
                task=2; }}

        single.onclick=function(){
            single.checked=true;
            if(task==2){
                task=1; }}


        l_trance.addEventListener('input', function(event){
            event.preventDefault();

            if(!test_color(l_color.value) && l_color.value.length==9){ // 不適合な #付き9桁コードの場合
                if(test_color(l_color.value.slice(0, -2))){ // アルファ―値のみ不適合なら修正
                    l_color.value=l_color.value.slice(0, -2); }}
            if(!test_color(l_color.value) && l_color.value.length==8){ // 不適合な #付き8桁コードの場合
                if(test_color(l_color.value.slice(0, -1))){ // アルファ―値のみ不適合なら修正
                    l_color.value=l_color.value.slice(0, -1); }}

            if((test_color(l_color.value))){
                trance();
                l_color.style.boxShadow='inset -20px 0 ' + l_color.value; }
            else{
                l_trance.value=1; } // 変換不能なコード, カラー名などは「1」を変更できない

            setting[1][2]=l_color.value;
            let write_json=JSON.stringify(setting);
            localStorage.setItem('Draw_Line', write_json); }); // ローカルストレージ 保存

    } // draw_line()



    function set_panel(){
        let l_type=document.querySelector('#l_type');
        let l_trance=document.querySelector('#l_trance');
        let l_color=document.querySelector('#l_color');

        l_type.value="カラー値チェック";

        l_trance.value='1'; // 初期値
        l_trance.setAttribute('min', '0.1');
        l_trance.setAttribute('max', '1');
        l_trance.setAttribute('step', '0.1');

        l_color.value=setting[1][2]; }



    function panel_disp(){
        let panel=document.createElement('div');
        panel.setAttribute('id', 'l_panel');

        panel.innerHTML=
            '<input id="l_type" type="submit">'+
            '<div id="type_wrap">'+
            '<div id="type_1">'+
            '<input id="single" type="radio" name="s_d"><span class="l_label">アラート非表示</span>'+
            '<input id="double" type="radio" name="s_d"><span class="l_label">アラート表示</span>'+
            '</div>'+
            '<div id="type_2">'+
            '<span class="l_label">透過度</span>'+
            '<div class="wtr"><input id="l_trance" type="number"></div>'+
            '</div>'+
            '</div>'+
            '<span class="l_label">線色</span>'+
            '<input id="l_color" type="text" autocomplete="off">'+
            '<div id="test">◪</div>';
        //        '<div id="test"></div>';


        let css=
            '#l_panel { position: fixed; top: 15px; left: calc(50% - 490px); padding: 6px 15px; '+
            'font-size: 14px; border: 1px solid #ccc; border-radius: 4px; background: #eff5f6; z-index: 10; }'+
            '#type_wrap { display: inline-block; text-align: right; width: 370px; }'+
            '#type_1 { display: inline-block; margin-right: 20px; } #type_2 { display: inline-block; }'+
            '#l_panel input { position: relative; margin-right: 10px; padding-top: 2px; }'+
            '#l_panel input:hover { z-index: 1; }'+
            '#l_panel input[type="radio"] { margin: 0 2px 0 8px; vertical-align: -2px; box-shadow: none; }'+
            '.l_label { margin: 0 4px 0 0; }'+
            '#l_type { width: 130px; margin-right: 4px !important; }'+
            '.wtr { position: relative; display: inline-block; }'+
            '#l_trance { width: 40px; text-align: center; padding: 2px 0 0 4px; }'+
            '#l_color { width: 90px; padding: 2px 24px 0 6px; border: thin solid #aaa; height: 23px; }'+
            '#test { display: inline-block; padding: 4px 7px 3px; border: thin solid #aaa; background: #fff; }'+
            //            '#test { display: inline-block; }'+
            '#cke_42 { top: 60px !important; left: calc( 50% - 45px) !important; }';

        if(ua==1){
            css=css +
                '#l_trance, #l_color { height: 24px; border: thin solid #aaa; }'+
                '.wtr::after { content: " "; position: absolute; right: 11px; top: 5px; '+
                'background: #fff; width: 1.2em; }'; }

        let style=document.createElement('style');
        style.innerHTML=css;
        panel.appendChild(style);

        let l_panel=document.querySelector('#l_panel');
        if(!l_panel){
            document.querySelector('.l-body').appendChild(panel); }} // panel_disp()



    function panel_remove(){
        let l_panel=document.querySelector('#l_panel');
        l_panel.remove(); }



    function test_color(color){
        return color.match(
            /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{8}|[A-Fa-f0-9]{3}|[A-Fa-f0-9]{4})$/)!==null; }



    function test_colorE(color){
        let test=document.querySelector('#test');
        test.style.color='#000001';

        if(color!=''){
            test.style.color=color; } // 引数の入力がない場合

        let colorR=window.getComputedStyle(test).color;
        if(colorR){
            if(colorR!='rgb(0, 0, 1)'){
                if(task==2){
                    alert(colorR + '  🟢 適正コード'); }
                return true; }
            else{
                if(color=='rgb(0, 0, 1)' || color=='#000001' || color=='#000001ff'){
                    if(task==2){
                        alert(colorR + '  🟢 適正コード'); }
                    return true; }
                else{
                    if(task==2){
                        alert(colorR +'  🔴 不適なカラーコード'); }
                    return false; }}}
        else{
            if(task==2){
                alert(colorR + '  🔴 メソッド戻り値無し'); } // 実際はこの状態にならない
            return false; }}



    function show_color(){
        let l_color=document.querySelector('#l_color');
        l_color.style.boxShadow='inset -20px 0 ' + l_color.value; }



    function pick_color(){
        let set_color;
        let color_input_selector;
        let color_label;
        let icon_button;

        editor_iframe=document.querySelector('.cke_wysiwyg_frame');
        iframe_doc=editor_iframe.contentWindow.document;
        selection=iframe_doc.getSelection();

        if(ua==0){
            color_label=document.querySelector('#cke_16_label');
            icon_button=document.querySelector('#cke_17'); }
        else if(ua==1){
            color_label=document.querySelector('#cke_15_label');
            icon_button=document.querySelector('#cke_16'); }

        let target_p=color_label; // 監視 アイコンのカラーラベル
        let monitor_p=new MutationObserver( get_copy );

        let l_color=document.querySelector('#l_color');


        l_color.onclick=function(event){
            if(event.ctrlKey==true){
                event.preventDefault();
                icon_button.click();
                selection.removeAllRanges(); // 反転選択がある場合に背景指定を防止する
                monitor_p.observe(target_p, {attributes: true}); }} // アイコンカラー取得開始

        l_color.addEventListener('input', function(event){
            event.preventDefault();
            let l_trance=document.querySelector('#l_trance');
            if(l_trance){
                l_trance.value=1; } // 透過度をリセットする

            if(test_colorE(l_color.value)){ // test_colorEを実行 ⏹
                l_color.style.boxShadow='inset -20px 0 ' + l_color.value; }
            else{
                if(l_color.value==''){
                    l_color.style.boxShadow='inset 0 0 0 1px black'; }
                else{
                    l_color.style.boxShadow='inset 0 0 0 1px black'; // 担保コード
                    l_color.style.boxShadow=
                        'inset 0 0 0 1px black, inset -20px 0 ' + l_color.value; }}

            if(test_colorE(l_color.value)){
                setting[1][2]=l_color.value;
                let write_json=JSON.stringify(setting);
                localStorage.setItem('Draw_Line', write_json); }}); // ローカルストレージ 保存


        document.addEventListener('mousedown', function(){
            monitor_p.disconnect(); }); // アイコンカラー取得終了

        if(document.querySelector('.cke_wysiwyg_frame') !=null){
            let editor_iframe=document.querySelector('.cke_wysiwyg_frame');
            let iframe_doc=editor_iframe.contentWindow.document;
            iframe_doc.addEventListener('mousedown', function(){
                monitor_p.disconnect(); }); } // アイコンカラー取得終了

        function get_copy(){
            let l_trance=document.querySelector('#l_trance');
            if(l_trance){
                l_trance.value=1; } // 透過度をリセットする
            set_color=color_label.getAttribute('data-color');
            l_color.value='#'+ set_color;
            l_color.style.boxShadow=
                'inset -20px 0 ' + l_color.value;
            monitor_p.disconnect(); // アイコンカラー取得終了

            test_colorE(l_color.value ); // test_colorEを実行 ⏹
            setting[1][2]=l_color.value;
            let write_json=JSON.stringify(setting);
            localStorage.setItem('Draw_Line', write_json); } // ローカルストレージ 保存


        let target_body=document.querySelector('.l-body'); // 監視 target
        let monitor_generator=new MutationObserver(stealth);
        monitor_generator.observe(target_body, {childList: true, subtree: true});

        function stealth(){
            let color_generator=document.querySelector('.ck-l-colorGenerator');
            if(color_generator){
                color_generator.addEventListener('mousedown', function(event){
                    event.stopImmediatePropagation(); }); }}
    } // pick_color()



    function trance(){
        let l_color_code;
        let l_color=document.querySelector('#l_color');
        let l_trance=document.querySelector('#l_trance');

        if(l_trance.value){
            if(test_color(l_color.value)){ // #カラーコードは全て#+16進8桁に変更
                if(l_color.value.length==4){
                    let ch=l_color.value.split("");
                    l_color_code='#'+ch[1]+ch[1]+ch[2]+ch[2]+ch[3]+ch[3]+'90'; }
                if(l_color.value.length==5){
                    let ch=l_color.value.split("");
                    l_color_code='#'+ch[1]+ch[1]+ch[2]+ch[2]+ch[3]+ch[3]+ch[4]+ch[4]; }
                if(l_color.value.length==7){
                    l_color_code=l_color.value+'90'; }
                if(l_color.value.length==9){
                    l_color_code=l_color.value; }

                if(l_trance.value!=1){
                    let ch=l_color_code.split('');
                    if(ch[7].match(/[A-Fa-f]/)){ // アルファ値の初桁が「9」を超える場合は「9」に
                        ch[7]='9'; }
                    if(Number(ch[7])<10*l_trance.value-1){ // 初桁とl_tranceの差が「2」以上は手入力
                        l_trance.value=Number(ch[7])/10; } // この場合はl_trance値を入力値に合わせる
                    else{
                        ch[7]=10*l_trance.value.toString(); } // l_tranceの入力に合わせて増減操作
                    ch[8]='0';

                    //                    l_color.value=ch.join('');

                    l_color.value=reduce(ch.join('')); }

                else if(l_trance.value==1){

                    //                    l_color.value=l_color_code.slice(0, -2); }

                    l_color.value=reduce(l_color_code).slice(0, -1); }
            }}}


    function reduce(color9){
        let ch=color9.split('');

        let color4='#' + avc(1, 2) + avc(3, 4) + avc(5, 6) + avc(7, 8);
        return color4;

        function avc(x, y){
            let str=ch[x]+ch[y];
            let d=parseInt( str, 16);
            let chr=Math.floor(d/17);
            if(d%17>8){
                chr=chr+1; }
            return chr.toString(16); }} // 平均カラー値 第1桁


}