としあきのWEB実装Tips

としあきが2023年に自身のサイトを成長させている中で得られた気づきと実装のtipを書き残しています。
ときおり、新たな気づきがあれば、既存の記述を書き換えることもあります。


レスポンシブ対応では、ブラウザの大きさによって、時にはブラウザの動的な大きさの変更に追従して、中のコンテンツを合わせていくことが求められることが原則だ。
しかし、ページの中のコンテンツの種類などにも依存するとは思うが、PCのブラウザでブラウザのウィンドウをユーザが横に拡げたとき、そのとおりどこまでも横にコンテンツやコンテンツの並びが拡がり続けるのって、実はページが見にくく(醜く)なることもあろう。
例えば、文章が横に長すぎるとかえって読みにくいこともある。
そこで、最大幅を設定することとする。

さて、その最大幅は、どの要素に設定すべきであろうか。
<body>に設定するより、その直子に<div>を一つ設けて、その<div>に設定するほうがすっきりする。特に、<body>や<div>に背景色または背景画像を設定する場合には以下の違いが出てくるためである。

<body>の背景は、実は<body>の幅(設定した最大幅)を超えてブラウザのウィンドウの幅まで拡がって描かれる。(期待する描画ではないよね)
なので、<body>の直子として<div id="maincontainer">といったものを設け、そのmaincontainerに背景を設定すると期待する描画に近い。

ただし、その背景を fixed かつ 100%としているとき、maincontainerの幅を100%としているのではなく、実はウィンドウの幅を100%として計算されてmaincontainerの部分だけが描画される動きとなることに注意。(これが現CSSの仕様のようだ。このページをPCのブラウザでかつ1200px以上の幅で拡げたり縮めたりすると実感できる)

iOS(iPhoneやiPadのOS)版のchrome, safari, edgeでは、背景画像のfixed(ページをスクロールするときに背景画像は固定されて前面のテキストなどだけがスクロールする)が効かないようだ。

(これ、もう少し調査が必要。自分の書いているCSSのバグによりそうなってしまっているのかも)

簡単なアコーディオンであれば、HTMLの<details>だけでも実装できる。その際、<summay>内に別の要素を書かず、装飾は直接<summary>に対しておこなった方が良い。(つぶやきのバックナンバーのページはこちらで実装してある)

別の実装方法として、HTMLとCSSとの組み合わせでも実装できる。(このページはこちらで実装してある)

いずれもJavaScriptは不要となっている。より複雑な実装(複数の一括開閉など)をしたいときは、JavaScriptも使うことになる。

あちこちのページで良く見かける三本の水平線で表現されたアイコン(あるいはアイコン風に表示されているもの)のことを、「ハンバーガーメニュー」と呼ぶようだ。

ページ内にどこかへのリンクを置いて、そのリンクが「外部サイトへ出ていく」ことを表現するのに、何らかのマークを付加してあることってあるよね。
この実装にはいくつかの方法があるように思う。どれが良いのかは人それぞれに思うことがあろうが、としあきとしては・・・迷いが残っている。

なお、マークを画像として用意するか、適当と思える文字(Unicodeにある'↗'や'⤴'とか)にするかもある。

  • HTML内にマークを直接書いておく
    
    <a href="https://example.com/">例へのリンク<img src="extenallinkmark.png"></a>
          
    とか(下記の例における &#8599; は、文字'↗'のことである)
    
    <a href="https://exmaple.com/">例へのリンク&#8599;</a>
          
  • HTML内にはマークを直接書かず、CSSにて外部リンクだと何らかの判断をした上で、そのリンク要素にマークを付加する
    (付加の仕方もいろいろあるが、↓の例は背景に画像(externallinkmark.png)を置いている。また、画像を置く幅をpadding-rightにて確保している。)
    
    <a href="https://example.com/">例へのリンク</a>
          
    
    a[href*="http"] { /*外部リンク(httpを含むURLを外部リンクとみなす)にアイコンを追加する*/
        background:      url("externallinkmark.png") no-repeat 100% 0;
        background-size: 16px 16px;
        padding-right:   19px;
    }
          

ページを縦にスクロールしたときに、ページの先頭に戻るボタン(のようなもの)があり、そこをクリック(タップ)するとページの先頭に戻ってくれる機能は流行りでもあり便利でもある。ただし、その実装にはいろいろな方法がある。

まず、ボタン(風)のものは、HTMLの要素としては何で用意するか。クリック(タップ)して何らかの動きをするのであるから、<button>が実は適切なのかも知れない。しかし、クリックして反応する要素であれば、<a>であろうが、単なる<p>であろうが何だって構わないという事実がある。(としあきとしては・・・迷っている)
ただし、使用する要素に従ってクリックされたときの動作設定をJavaScriptで適切に記述することが必要になる。

ボタン(風)のものの見た目の装飾、マウスホバーしたときに色を変えるなどの装飾の変更などは、CSSにて設定する。

押されたときの動作には注意点があった。
良くネットで紹介されているのは、以下のような記述。


<a href="#">GoTop</a>
  

これ、確かに見た目はページのトップ("#")に戻ることにはなるのだが、リンクを進めたことになるのでブラウザの履歴に1つ記録されることになる。(ボタンを操作した画面と位置[Aの状態とする]を記憶し、次の表示として同一画面の先頭を表示した[Bの状態とする]ということになるのだ。)
すると、そのあと、ブラウザの「←」といったものやページ内に用意した「(一つ前のページに)戻る」を操作すると、通常その操作ではブラウザの履歴を1つ巻き戻す動作となるので、Aの状態に戻ることになる。これって、期待する動作ではないよね。(ホントは一つ前のページに戻って欲しい)

回避するには、ブラウザの履歴に追加されない手法でページ先頭にスクロールさせなきゃいけない。<a>を使うならば、次のようにする。 (JavaScriptによってwindow(ブラウザ)が持つscrollTo()メソッドを使ってスクロールさせているものの、return flaseによって"#"へリンクを進めさせない=即ち履歴には記録されないことを実現している)


<a href="#" onclick="window.scrollTo(0, 0); return false;">GoTop</a>
  

MDNのリファレンスの<a>の説明の中に以下の記述を見つけた。やはり<button>での実装を選択すべきだ。<a>を使った上記テクニックは邪道であるとの結論に至った。

onclick イベント
よく見られる誤った使い方として、擬似的なボタンを作成するためにアンカー要素を使用し、href を # または javascript:void(0) に設定してページの再読み込みを防ぎ、click を待ち受けするようにするというものがあります。
これらの偽の href 値は、リンクをコピーまたはドラッグしたり、新しいやウィンドウでリンクを開いたり、ブックマークしたり、JavaScript の読み込み中、エラー状態、無効状態の場合などに予期しない動作を引き起こします。また、読み上げソフトなどの支援技術に対して誤った意味を伝えることもあります。
代わりに <button> を使用してください。通常、アンカーは適切な URL を使用して移動するためだけに使用するべきです。

ページトップに戻るボタン、ページ先頭を見ているときは表示されずにある程度スクロールしたら登場してくるのってかっこ良い。これどうしてもJavaScriptの力を借りねばできない。(と思っている)

おおよその実装は以下となる。

  • ボタンはCSSにて最初非表示としておく。(display:none 、 visibility:hidden 、 opacity:0 など)
  • スクロールイベントに対するイベントリスナー(JavaScriptの関数)を画面表示初期にブラウザに登録しておく。
  • イベントリスナーの中で、現在のスクロール位置を取得し、表示条件(ある程度のスクロール位置にあること)を満たせば、上記ボタンのCSS部分を「表示するよう」書き換える。たまた、表示条件を満たさなければ「非表示とするよう」書き換える。

ここでいうのは、HTMLの各要素に指定して、そしてCSSにてそのクラス個別の設定を書くための「class」のことである。JavaScriptなどのオフジェクト指向プログラミング言語におけるclassや、ましてや学校のクラスのことではない。(笑)

HTML, CSSでは、HTML要素やidにスタイルを当てるのではなくclassにスタイルを当てるようにすることが、よく言われている。
さて、それはどういった背景・理由からだろう?

HTML要素は、すべてのHTML文書で共通なものだ。それにスタイルを設定すると、すべてのHTML文書のHTML要素に適用されることになるから、別のHTML文書に別じスタイルをつけたいときには一度書いたCSSは使えないことになる。
idは一つのHTML文書の中で文書内の各要素にユニークにつけるものである。(そりゃそうだ。identifierなのだから)すると、idにスタイルを設定していると、同じスタイルを設定したい他のモノが出てきたときに、同じスタイル設定は使いまわせず、他のモノのidに対して同じスタイル指定をCSSに書かねばならない。
一方で、共通と思えるスタイルは、あるclassを定義して、classにスタイルを設定したCSSは使いまわせる。
ということを言っているのだと解釈している。

しかし、使いまわせるスタイル設定というものはどういったものなのだろう・・・というところで自分なりの答えが見いだせていない
この後の鍛錬の中で、このことを意識しながら、進めていきたい。

JavaScriptを埋め込んだテスト用ページを作成し、としあき手持ちのデバイスで値 (document.documentElement.clientWidth の値) を実際に取得してみた。
chrome, safari, edgeでの違いは見受けられなかった。(実際に取得するためのコードはこのページには埋め込んでいない)

デバイス 観測されたclientWidth
ipad (第9世代) 縦持ち 810 px
ipad (第9世代) 横持ち 1080 px
iPhone 6s 縦持ち 320 px
iPhone 6s 横持ち 568 px
iPhone SE (第3世代) 縦持ち 375 px
iPhone SE (第3世代) 横持ち 667 px
Rakuten Mini 縦持ち 320 px
Rakuten Mini 横持ち - (横向きにならない)

スマホの横持ちにしたとき、CSSで指定しているフォントサイズより文字が大きく表示される動作が存在する。
スマホ用のブラウザの親切機能なのだそうだ。

しかし、レスポンシブ対応とかしているときに、この機能が「余計なお世話」だったりする。
そこで、この機能を抑止するCSSの設定がある。


body { 
    text-size-adjust:         100%; /* standard, but experimental specification right now. */
    -webkit-text-size-adjust: 100%; /* これが効くようだ */
    -moz-text-size-adjust:    100%; /* 一部のサイトで紹介されているが・・・ */
    -ms-text-size-adjust:     100%; /* 一部のサイトで紹介されているが・・・ */
}

でよい。なお、none; は、「抑止」のはずだが一部のブラウザにはバグあり抑止が効かないそうだ。そこで、(バグのない)100% を指定して抑止することになる。

ちなみに、標準仕様としては text-size-adjust ではあるものの、現時点では実験(experimental)の位置づけのままであり、ブラウザによってサポートされているかどうかが異なる。そのため、ベンダープレフィックス付きのものを並べて、それぞれのブラウザにて有効なものが適用されるよう書いている。

pre要素とcode要素について考えてみる。
<pre>は、「整形済テキスト要素」(The Preformatted Text Element)とある。一般的にプログラムコードなどを記述するときによく用いられる。
ただし、ここにおいても、HTMLの予約文字をそのまま表示したいときには、HTMLエンティティ(&で始まり;で終わる文字列)でエスケープしなければならない。
<code>は、「インラインコード要素」(The Inline Code Element)とある。こちらは「コンピュータコードの短い断片の文字列」と定義されている。
特に、「インライン」であることから、前後に改行などはされない。また、HTMLの予約文字の扱いは<pre>と同じである。
とすると、行を変えて、また、複数行のプログラムコードを表現するには、どういった書き方がHTMLの仕様に沿った書き方であろうか?

MDNのリファレンスにおいて<code>の説明の中にある補足には、「複数行のコードを表すには、 <code>要素を<pre>要素の中に入れてください」と書かれている。
ふ~ん、なるほど。ではない。意味論的にコードを<code>で囲むことはそうであろう。しかし、それを「整形済」で(複数行まとめて)書きたい、という風に考えたときには、実は<code>の内側に<pre>があるべきではないのか?

2023/10時点では、<pre>の内側に<code>を書いた例と<code>の内側に<pre>を書いた例を掲載し、両者に大差がなく、おいらとしてはどちらを自身のルールとすべきかまだ悩んでいる旨を書いた。
しかし、validatorが以下のエラーを指摘したので、仕様の解釈を今一度考察してみた。

Error: Element pre not allowed as child of element code in this context.
...<code><pre>...
Contexts in which element pre may be used:
Where flow content is expected.
Content model for element code:
Phrasing content.

code要素は「インライン」であるから、その中に改行などを含むpre要素を含めることは、仕様には不適合である。したがって、両者を組み合わせる場合には、pre要素の中で「コード」を示すcode要素で書くことが適切(仕様に適合)である。
おいらがちょっとへそ曲がりに考え込んでいたようだ。

HTMLでは意味論的な目的でタグ(要素)にてマークアップする。装飾はCSSの役割だ。という。
それはある程度理解しつつも、インラインにて結果的に文字列の装飾が変わる<b>(通常太字で表示される)や<i>(通常斜体で表示される)などは、現代のHTMLにおいても「非推奨」とはなっていない。ということは、意味論的にマークアップするに足るものである、ということなのだろう。(その意味を表現するためのブラウザの選択結果が、太字なり斜体にて識別した表示にしている、という解釈をすべきなのであろう。)

以下、すこし整理してみた。

タグ名 意味 英語でのタイトル / ブラウザでの表示例など
<b> 注目づけ The Bring Attention To element
太字になる (過去は bold からとった b であった)
<i> 慣用句、技術用語、呼称など The Idiomatic Text element
イタリック体(斜字体)になる (過去は italic からとった i であった)
<u> 非言語的注釈 The Unarticulated Annotation element
実線の下線を引く (過去は underline からとった u であった)
<em> 強調表示 The Emphasis element
イタリック体(斜字体)になる (i とは異なり、意味的に強調したいモノに適用する)
<strong> 強い重要性 The Strong Importance element
太字になる
<mark> テキストマーク The Mark Text element
黄色の背景になる
<abbr> 略語、頭字語... The Abbreviation element
等幅フォントになる (同様のacronymは非推奨となっている)
<dfn> 定義した用語 The Definition element
イタリック体(斜字体)になる
<cite> 引用元 The Citation element
イタリック体(斜字体)になる
<code> コンピュータコード The Inline Code element
ちょっと小さい等幅フォントになる。例: c = a + b;
<kbd> キーボード入力 The Keyboard Input element
ちょっと小さい等幅フォントになる。例:Ctrl + S
<samp> コンピュータ出力サンプル The Sample Output element
ちょっと小さい等幅フォントになる。例:Result: 567
<time> 日付、時刻 The (Date) Time element
特に見た目の変化はない (datetime属性に規定の書式で記述したものが機械可読となる)
<var> 変数名 The Variable element
イタリック体(斜字体)になる。例:S = a + b
<q> 引用 The Inline Quotation element
ブラウザが前後に引用符を付加する (なお、引用符はHTMLのlangの設定に合うものが選択されて付加される模様)
例:ここからここまでを<q></q>で囲んでいる
<s> 取り消し The Strikethrough element
取り消し線つきとなる
<del> 削除済 The Deleted Text element
取り消し線つきとなる
<ins> 追加、挿入 The Inserted Text element
下線つきとなる (明示的に追加されたことを表現。delとの組み合わせなど)
<sup> 上付き文字 The Superscript element
小さめの文字でベースラインより高い位置に表示される (数学のべき乗、序数などに用いる)
例:a2 + b2 = c2
<sub> 下付き文字 The Subscript element
小さめの文字でベースラインより低い位置に表示される (化学式における原子数などに用いる)
例:C8H10N4O2

何年も前からGoogleがフリーで配布している。あの世界のGoogleが作成し、かつ商用利用をも許している素材であり、世界中で使われているものだ。
そして、そうだからこそ、あるものを表現するアイコンとしては、デファクトスタンダードになっているとも言える。わざわざ別のイメージを作成するなんて馬鹿げている。

Google Material Symbols and Iconsへ

ただし、注意点がある。
フォント(Webフォント)は、日本語などのフォントの場合はデータ量としてはかなり大きく、ページのロード性能に悪影響がある。そのため、なんでもかんでも常にWebフォントとすることは得策ではなく、慎重に考えた方が良い。ほんとにWebフォントにしたい場合だけに限定すべきと思う。
一方で、アイコンひとつひとつはそれほどのデータ量ではないため、都度Web参照して取り込むか、あるいは自身のサイトにあらかじめダウンロードしておいたものを使うことで良いと思う。

クリックしたら何かアクションがあるモノ(例えば、ボタン風なものやリンクなど)にマウスカーソルが乗っかったら、それとわかるマウスカーソルになって欲しい。
リンク(<a>)ならば、ブラウザがデフォルトでそうしている。ブラウザがそうしてくれないものに対しては、自身でCSSにて設定することによって実現できる。
以下の例は<summary>(アコーディオンのタイトル部分)と<button>に対して設定している。


summary,
button  { cursor: pointer; }

レスポンシブ対応しているのだから、<pre>(整形済)とはしていても、画面幅を超えて横に拡がってしまってはカッコ悪い。CSSに以下の設定をすることによって、折り返してくれるようになる。


pre { 
    white-space: pre-wrap;
    overflow-x:  auto;
}

ページで使用するフォントって、こだわりがなければ指定することなくOSとブラウザに任せておく、という選択肢もある。
どんな環境でも同一のフォントで表示させたければ、Webフォント(表示させているデイバス、OS、ブラウザに依存せず、Web上で公開されているフォント)を使用するとの選択肢もある。ただし、日本語の場合はWebフォントは(データ量が大きいために)重いため、その使用は慎重であるべきである。

すると、大抵はOSにインストールされている(であろう)ローカルフォントを指定することになる。
とは言っても、実際のところよくわからないまま指定していたりすることが多いのが実態であろう。(参考としたページの設定やWebで検索した情報をもとに意味を理解せずにコピペしてるだけとか。)そう、おいらもそうであった。そもそもそれほどフォントにこだわっていないし、フォントの違いといっても細かいところは気にならない

以下のページは、調査と経験および洞察に基づいた具体的な指定を提案してくれているので、理解の促進とともにとても参考になる。

2022年に最適なfont-familyの書き方


body { 
    font-family: "Helvetica Neue",            /* macOS/iOS/iPadOS 欧文 */
                 "Arial",                     /* Windows 欧文 */
                 "Hiragino Kaku Gothic ProN", /* macOS/iOS/iPadOS 和文 */
                 "Hiragino Sans",             /* macOS/iOS/iPadOS 和文 フォールバック */
                 "BIZ UDPGothic",             /* Windows 和文 */
                 "Meiryo",                    /* Windows 和文 フォールバック*/
                 sans-serif;                  /* 総称フォント Note that the generic name should not be quoted. */
}

フォントファミリー名に空白が含まれていない場合は引用符で囲まなくても良いことにはなっているが、フォントファミリー名は引用符付き、総称フォントファミリー名は引用符無しで明示的にしておいた方が解りよいかとの考えで、ArialMeiryo も引用符で囲っている。一方で san-sefifは引用符で囲ってはいけない。

(以下、余談)
日本語では、明朝体(線の太さが一定ではく縦より横が細い)と、ゴシック体(線の太さが一定)との分類がある。ただし、欧文でGothicというのは以下とは別の意味になる。
欧文では、serif(文字にヒゲがあり、また、縦より横が細い)と、sans serif(文字にヒゲがなく、また、線の太さが一定)との分類がある。ちなみにsansはフランス語の「ない」から来ている。
上記との組み合わせで、等幅フォント(各文字の幅がどの文字も一定)とプロポーショナルフォント(文字ごとに幅が異なる)という違いもある。フォント名に大抵PやProをつけて明示していたりする

これは賛否両論あるかも知れない。
ページが縦に長いものであった場合にセクションや段落に区切ってコンテンツが書かれていて、ページ先頭やメニューなどでそれらセクションの先頭などにジャンプする機能を持たせたりする。このとき、昔ながらの実装では、アンカー要素(<a>)を使って次のようにしたりする。


 <a href="#idToGo">ほげほげへ</a>

しかし、これだと、idToGo と名付けた要素のところへジャンプしてくれるものの、ブラウザの履歴(history)に現在の場所を記録した上でのリンクの移動となる。
これは、そのあとブラウザの「戻る」操作をしたときに、先の記録した場所へ戻ることにつながる。
この動作をどう考えるか?
おいらとしては、ブラウザの「戻る」操作では、前見ていたページに戻って欲しい。

そこで、ブラウザの履歴に残さないような方法で、ページ内の移動(ジャンプ)を実装することができる。以下が例である。scrollIntoView()を使っている。


<button type="button" onclick="myScrollIntoView('idToGo');">ほげほげへ</button>
...
<h2 id="idToGo">ほげほげのはじまり</h2>
...
<script>
function myScrollIntoView(id) {
    document.getElementById(id).scrollIntoView();
    return;
}
</script>

myScrollIntoView()をある一つの要素だけで使うのではなく、いろんなidに対して一つの関数を使いまわせるように、関数の引数にidをとるようにしてある。
もちろん、HTML内でJavaScript関数を直接かかずに、jsファイルを別に用意してHTMLファイルから読み込む実装でも構わない。

リンク(<a>)において、target="_blank"を指定しているにも係わらず、別ウインドウ(別タブ)でリンク先が開かず、元のウインドウ(タブ)内でリンク先のページが書き変わって表示されるという事象を観測した。iOSのMicrosoft Edgeである。PCのEdgeや、iOSのchromeでは起きていなかった。
結局は、iOSのEdgeをアップデートして最新バージョン(119)にしたら解消したので、ブラウザEdgeのバグだったのだろう。

調べているときに、rel="noopener"を学んだ。
この属性指定がないと、リンク先のページ(サイト)の悪意のコードから元のウインドウの操作が出来てしまうというセキュリティリスクがあるという。詳細はここには書かないのでネットとかで仕組みと理屈を理解されたし。
おいらは納得できたので、おいらのサイト内の各ページにある外部サイトへのリンクは一律以下の記述に改めた。


 <a href="https://example.com/" target="_blank" rel="noopener">exampleへ</a>

なお、最新のブラウザは、この noopener 指定をしなくても指定しているかのように動作するとのことではあるが、念のために明示的に指定することとしている。

上記のリンク(<a>)における target="_blank" rel="noopener" を調べているときに、rel="nofollow" も併せて学んだ。
こちらは、SEO (Search Engine Optimization) 対策に関するモノである。

Googleなどの検索エンジンは世の中のWebサイトをクロールして、そして個々のWebサイトの出来を評価しており、その評価点が高いページを検索結果の上位に表示するといった動きをしている。これはGoogleが発表していることである。
なので、企業などのサイトではかなりSEO対策には懸念と対処をしている。だって、皆、検索結果の上位に表示してもらいたいから。

さて、自分のサイトの各ページに外部サイトのリンクを置くこともあろう。その際、検索エンジンのクロールによって外部サイトへも行き、そしてその外部サイトのSEO的な評価が悪いものだったとき、自身の元のページ(サイト)の評価も下がってしまうことが起きる。これは本意ではないよね。
そこで、以下の記述によって、検索エンジンに対して「このリンク先はクロールしなくて良いよ」を知らせる。ただし、これ、指示ではなくてヒントということになっているので、検索エンジン会社任せであることには変わりない。ホントに嫌だったら、外部サイトへのリンクを自分のサイトのページに置かないことだ。


 <a href="https://example.com/" target="_blank" rel="noopener nofollow">exampleへ</a>

rel属性について網羅的に知識を得たい場合には、HTML Living Standard のリンクタイプの説明(日本語訳)が役に立つかもしれない。

ブラウザのキャッシュを制御したい。特に、自身がサーバ側のファイル(html, css, etc.)を更新したのに、ブラウザ側がキャッシュしていた古いファイルを表示していることを何とかできないものか。ましてや、ページを見てくれる人は「実は更新されている」なんてことを認識する術(すべ)はなく、ページの更新操作やスーパーリロード操作してみなきゃ更新されていることに気が付かない。が、そのトリガーが無い。

cache-control というキーワードでネットで検索するといろいろ出てくる。
http (hypertext transfer protocol) の仕様では、サーバ側からブラウザに返すレスポンスにおいて当該キャッシュに対する指示を返すことができるようになっている。では、サーバ側にファイルを作成している者としては、どうやったらこのレスポンスの指示を返すようにできるのか?
サーバを独自に運営していて、サーバ側のWebサーバプログラム(例えば、IIS:Internet Information Services や apache httpd など)を自身で構成しているならば、サーバプログラムの設定ファイル(またはリッチな画面)で設定することができる。
しかし、レンタルサーバなどだとWebサーバプログラムの設定まではさせてくれないことが多いであろう。すると、apache httpd 限定とはなるが、自身のホームページを置くために与えられたフォルダに .htaccess というファイルを配置することで、サーバプログラムの振る舞いを設定することができる。(これも、レンタルサーバ側がそれを許可している場合に限られるけれども。)

設定の詳細の解説は割愛する。ネットで調べてみて欲しい。
以下の .htaccess の例は、html、css、js の拡張子を持つファイルに対して、no-cache (キャッシュしても良いけど、最新かどうかをサーバに確認してから使ってね)をレスポンスに設定するようにしている。


<Files ~ "\.(html|css|js)$">
Header set Cache-Control no-cache
</Files>

注意すべき点がある。

  • .htaccessは配置したフォルダおよびサブフォルダ内への全てのファイルに対するリクエストに対して apache httpd は常に検証して振る舞いを決定するようになる。即ち、サーバの応答性能が悪化するという影響があるということである。
  • そもそも、上記理由から、apache君は .htaccess による設定は推奨していない。(でも、それができない事情があるから .htaccess にしているのだけどね。)
  • ブラウザ側もキャッシュされたファイルを使う前に、常に最新かどうかをサーバに問い合わせる通信をすることになる。旧版を使うことはなくなるが、キャッシュ内が最新版であった場合にも表示性能は悪化するという影響があるということである。

なお、仕様を厳密に正しく実装していないブラウザも存在するようである。それらのややこしい事態を踏まえると、MDNのサイトに紹介されているベストプラクティスは、更新前後でファイル名を維持せず、(バージョンなどを含めた)ファイル名も変えることだという。
一理あるね。しかし、ホントのトップファイルである index.html なんかはファイル名を変えるわけにはいかないし、その先のファイルたちもファイル名を変えたら、それをリンクしている記述も一斉に書き換えなきゃいけないよね。ん~、どーだろう?
ということで、おいらとしては、画像ファイルはファイル名にタイムスタンプなどをつけて内容だけを差し替えることはしないという自身のルールを設定して、ファイル名を変えずに内容だけを更新する可能性のある html, css, js ファイルに対して no-cache とするようにしてみた。

最後に、本件は最初にページを公開するときから考察とルールを決めておいたほうが良い。
おいらのように途中で上記設定としたものの、すでに処置前のファイルがキャッシュされているユーザに対しては、何らかのきっかけでページのリロードやスーパーリロードをしてもらうまでは、キャッシュを使い続けることを訂正する術(すべ)はないままである。

P.S. ネットでは下記の記載をhtmlファイルにすることも紹介されてはいたが、記載したhtmlファイルだけなのかhtmlからリンクしているcss,jsファイルにも効くのかが認識できなかったこと、上記のように画像ファイルに対しては効かなくても良いことから、.htaccessでの設定を選択した。


<meta http-equiv="cache-control" content="no-cache">

画像ファイル(写真や図など)をページに置こうとしたら<img>を使う。スタイルで幅に何も指定しなければ、画像ファイルのオリジナルのサイズで置かれる(表示される)ことになる。
しかし、画面(ウインドウ)の幅や画面を縦に区切っているときの区切ったエリアの幅で表示させたいということはあろう。
下記はその例(HTMLと(内部)CSS)である。


...
<img src="example1200x900.jpg"> <!--何も指定しないのでオリジナルのサイズで。結果、横にはみ出て表示される-->
<img class="w100" src="example1200x900.jpg"> <!--下記のCSSが適用されて画面幅に画像が調整される-->
<img class="maxw100" src="example400x300.jpg"> <!--下記のCSSが適用されてオリジナルのサイズが画面幅を超えていたら画面幅に調整される-->
...
<style>
  .w100    { width: 100%; }     /* 幅を包含ブロックの幅の100%に調整する */
  .maxw100 { max-width: 100%; } /* 最大幅を包含ブロックの幅の100%に調整する */
</style>
...

小さい画像は width:100% だと拡大されて汚くなる。かといって、オリジナルの画像ファイルに対しては「大は小を兼ねる」という考えは良くない。大きなファイルはデータサイズも大きく、ページの表示性能に悪い影響があるからだ。
自身の目的とする表示サイズ以上の巨大な画像ファイルは無用の長物だ。(というより、悪だ)
よくよく考えて、ページにおく画像ファイルはあらかじめサイズを調整しておこう。
なお、大きな画面のPCで表示した場合に想定される表示幅とスマホなどの表示幅はかなり異なる。ここには書かないが、表示デバイスに「無駄にならないサイズの」画像ファイルをそれぞれ用意しておき、表示の際に選択させる技術的な解もある。別途機会があったら紹介することとしたい。

レスポンシブ対応としていると、例えば、縦に区切った区画の幅を親区画の幅からの%で指定することが多いであろう。
下記のような場合だ。


...
<div id="parent">
  <div id="leftchild">
    ...
  </div>
  <div id="rightchild">
    ...
  </div>
</div>
...
<style>
#leftchild {
  float: left;
  width: 30%;
}
#rightchild {
  float: right;
  width: 70%;
}
</style>

コレ、leftchild にも rightchild にも padding や border を指定していないうちは問題ない。
30% と 70% を足した値と、parentの幅が一致するからだ。

しかし、下記のように borderを描かせると、その分が 100% に納まらなくなって、ずれてしまう。(同じ高さの位置に描画できなくなる)


  ...
  <div id="parent">
    <div id="leftchild">
      ...
    </div>
    <div id="rightchild">
      ...
    </div>
  </div>
  ...
  <style>
  #leftchild {
    float: left;
    width: 30%;
    border: 2px solid black; /* 30%に加えて左2pxと右2pzを加えた値がこのボックスの幅である */
  }
  #rightchild {
    float: right;
    width: 70%;
    border: 2px dotted red; /* 70%に加えた左2pxと右2pxを加えた値がこのボックスの幅である +/
  }
  </style>

このからくりは、box-sizing にある。
box-sizing のデフォルト(既定値)は、content-box (中身のサイズをボックスのサイズとする。paddingやborderはそれに加えたものがホントのボックスのサイズとなる)である。
境界線も含めてサイズを計算してもらうには、border-box を指定する。


  ...
  <div id="parent">
    <div id="leftchild">
      ...
    </div>
    <div id="rightchild">
      ...
    </div>
  </div>
  ...
  <style>
  #leftchild {
    float: left;
    width: 30%;
    border: 2px solid black;
    box-sizing: border-box; /* 境界線も含めてボックスの幅として、それらを含めて親の30%とする  */
  }
  #rightchild {
    float: right;
    width: 70%;
    border: 2px dotted red;
    box-sizing: border-box; /* 境界線も含めてボックスの幅として、それらを含めて親の70%とする */
  }
  </style>
  

特にスマホのブラウザでは、メールアドレスや電話番号と思しき箇所を勝手にリンクされているかのごとく表示し(色変えて、下線引くなどし)、タップするとメールアプリや電話アプリが起動するといった便利機能がある。
コレって、ページを書いている側からは、「勝手にそんな風に動かないでよ(プンプン)」である。

HTMLに書いているのは次のような単純なテキストだけなのだから・・・


...
<p>例えばメールアドレスというのは、example@tamamori.com の形をしている。</p>
...

一方で、メールアドレスからメールアプリを起動させたい意図がある場合は、次のように意図を持ってリンクで書くものだ。


...
<p>連絡先:<a href="mailto:example@tamamori.com">example@tamaori.com</a> にメールしてください。</p>
...

さて、このブラウザの勝手な動作はある程度「抑止」させることができそうだ。しかし、この記述は標準仕様ではないことに加え、何せブラウザが勝手にやっていることだから完全に抑止できるとは限らない。(2023/12/22時点で、iOS chrome (バージョン119)では、メールアドレスに対する抑止は効かないようだ)


<meta name="format-detection" content="telephone=no,address=no,email=no,date=no">

完全に抑止したければ・・・答えはない模様・・・HTMLで文字参照にしてみたり、スタイルにて文字挿入としてみたりしても、労力とHMTLの可読性を落としている割には効果はいまひとつ。(WEB実験のページに用意して各種ブラウザで表示させてみた)
あとは、ホントに抑止したければブラウザに文字列と認識させないモノ(つまり、画像)を貼り付けるくらいか。


...
<p>例えばメールアドレスというのは、example&#064;tamamori.com の形をしている。</p>
<p>例えば電話番号というのは、010&#045;1234&#045;5678 の形をしている。</p>
...
<p>例えばメールアドレスというのは、example<span class="at"></span>tamamori.com の形をしている。</p>
<p>例えば電話番号というのは、010<span class="hyphen"></span>1234<span class="hyphen"></span>5678 の形をしている。</p>>
<style>
  .at::before     { content: "@"; }
  .hyphen::before { content: "-"; }
</style>
...
<p>例えばメールアドレスというのは、<img src="mailaddress.jpg"> の形をしている。</p>
<p>例えば電話番号というのは、<img src="telnumber.jpg"> の形をしている。</p>

ホームページに連絡用のメールアドレスを直接記述することは、スパムメールの餌食になる可能性が高いということから、よろしくないということは良く言われている。
確かに、HTMLの中にメールアドレスらしき部分があると、ロボットが「メールアドレスらしき」を抽出するということはやっているんだと思う。
この対策のベストプラクティスは、メールアドレスを一切公開せず、ページ上にフォームを用意してサーバサイドでメールを作成してメール送信することだと言う。これも正しい。

しかし、これにはサーバサイドにプログラムを配置できる仕組みと、当該プログラムを受けつける仕組み、そして当該プログラムからメールを送信する仕組みも必要だ。この仕組みの構築にはちょっとした知識とその実装できる環境が必要になるため、少し複雑になる。

そこで、HTML, CSS, JavaScriptだけでできる簡易的な対策としては、以下がある。

  • メールアドレスを画像にしてテキストとしては記載しない
  • メールアドレスの一部(例えば@マーク)を数値文字参照(&#64;)にして、少しごまかす
  • メールアドレスの一部(例えば@マーク)を全角文字にして、かつ、メールアドレスとして使うときには半角の@に置き換えるようガイドしておく
  • HTMLには完全なメールアドレスを書かず、CSSを使って一部を補完して、メールアドレスの文字列とする
  • HTMLにはメールアドレスを書かず、JavaScriptの関数によってメールアドレス文字列を生成して、当該文字列をブラウザに表示させる

いずれも、一長一短あり、そしてベストプラクティスよりは強度は弱い。
その中でも若干強度があると思われるJavaScript関数を使う例を紹介しよう。


...
<span id="exampleeml">ここがメールアドレスに置換される</span>
...
<sctipt>
  const eml = String.fromCharCode(101, 120, 97, 109, 112, 108, 101, 32*2, 101, 120, 97, 109, 112, 108, 101, 23*2, 99, 111, 109);
  document.getElementById('exampleeml').textContent = eml;
</script>

HTML内には、メールアドレス文字列は直接書いていない。scriptが動作するとメールアドレス文字列を生成しHTMLの該当箇所にその文字列を設定している。
script内でもメールアドレス文字列そのものは書いていない。さらに、@や.(ドット)に相当するASCIIコード値もその値を直接書かずに計算式(掛け算)で指定している。
そのため、これをメールアドレスだと解釈するには、ロボットも相当賢く作っておかなければならなくなっている。逆に、ロボットがここまで深堀って解析する能力を持てば、効果のない対策であるとも言える。
もちろん、scriptをHTML内に書かずに外部ファイルにすると、さらに強度は上がるとも考えられる。

🔝