HTMLに書き込まれる文字数
「Draw The Line ⭐」の制作時に少し気になっていたのは、HTMLに書き込まれる文字数が、一般的な文字修飾のタグコードに対してかなり多いという点です。
下の様な Ameba Pick のアフィリエイト商品表示枠は、1個で2500文字程度の文字数があり、それに比べたらずっと少ないのですが。(注:下は画像化したものです)
実際の装飾線の文字数をカウント
実際の文字数を調べてみました。 カラー設定は下の様なものです。
この「単線」のアンダーラインを記入すると下の様なコードになり、下線付けで追加される文字数は「150文字」です。
ちなみに、編集アイコンの下線付けをすれば「48文字」です。
2重線のアンダーラインの場合は更にコードが複雑になり、文字数も増えます。
この「2重線」のコードは以下で、追加文字数は「262文字」です。
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」で利用できません。
しかし少し考えると、変換コードはそう難しくはなさそうで、自分で書いてみました。 案外とネット上にはないコードで、必要な方が居るかも知れません。
どの様に求めるか
「#+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」も同じ理由です。
「HEX8桁→4桁」短縮変換コード
以下は少し変え、アルファ値付きの HEX8桁(color9)を HEX4桁(color5)に短縮するコードです。
テストツール と操作の方法
以上の「短縮カラーコード」を生成するテストツールです。 実装は手を抜いているので、操作の仕様が少し変わっています。
❶ ショートカットが同じ他のテストツールや「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桁 }