自サーバーに置いたWebフォントを読み込めない時の対処法

Google Fontsなどのサービスとして公開されているのではなく、独自にサーバーに置いたWebフォントをCSSで指定しても反映されない場合の対処方法です。独自ドメインで使っているサーバーとは別にFC2やSeesaaブログなどをやっていて、そちらで自サーバーのWebフォントが読み込めないという場合、クロスドメイン制約でアクセス制限がかかっている事があります。

Google Fontsなどのサービスとして公開されているのではなく、独自にサーバーに置いたWebフォントをCSSで指定しても反映されない場合の対処方法です。

独自ドメインで使っているサーバーとは別にFC2やSeesaaブログなどをやっていて、そちらで自サーバーのWebフォントが読み込めないという場合、クロスドメイン制約でアクセス制限がかかっている事があります。

ていうか、私自身が今使っているバリューサーバーに置いたフォントを、別のサイトで読み込ませて使っていたんですが、気がついたら使えなくなっていました。以前は使えていたんですけど、どこかの段階でバリューサーバーの設定が変わったようです。

その時にやった事のまとめです。

Webフォントが読み込めないドメインのアクセス制限を解除する

先に公開したページ「Google Feed APIを使わずXMLHttpRequestでクロスドメインのRSSを取得する方法 まとめ」に書いたんですが、.htaccess に Access-Control-Allow-Origin の設定をするとアクセス制限を解除できます。

.htaccess に次のように書くと全てのドメインからのアクセスが許可されます。

Header append Access-Control-Allow-Origin: *

* はワイルドカードで、この場合は全てのドメインを指します。

全てのドメインにではなく、自分の使っているドメインだけ許可したい時は、そのドメインを指定します。許可したいドメインが http://example.com なら下の通りです。

Header append Access-Control-Allow-Origin: http://example.com

ただし、ドメインを複数指定するには工夫が必要なようです。
参考「Access-Control-Allow-Originヘッダで複数のオリジンドメインを許可する方法 – ぷれすとぶろぐ

Internet ExplorerだけWebフォントが反映されない時の対処法

上の設定で、Webフォントは読み込まれるようになったんですが、IEだけ反映されませんでした。

そこで調べたら、次のページを発見。Truetype embedding-enabler

このページにあるembed.exeをダウンロードしてコマンドプロンプトで以下のように実行。そのフォントを再アップロードしただけでIEにも反映させることが出来ました。

embed font_name.ttf

私の場合は上のツールで解決したんですが、下のページで他の使いやすいツールとかを詳しく説明してくれています。

IEにも対応したWebフォントの使い方について | memocarilog

このページによると、IE以外のブラウザでは拡張子が .ttf のTrueTypeフォントや .otf のOpenTypeフォントが使えるんですが、IEだけは拡張子が .eot のEmbedded Open Typeしか使えないというのが原因のようです。

Google Feed APIを使わずXMLHttpRequestでクロスドメインのRSSを取得する方法 まとめ

Google Feed APIを使わずにXMLHttpRequestでクロスドメインのRSSを取得してデータを抽出した際に作った自作サーバーの立て方とJavaScriptでの取得方法です。JavaScriptに関して言うとjQueryを使わなくても大した行数にはならないです。

「Google Feed API」を使わず、XMLHttpRequestでクロスドメインのRSSを取得して最新記事一覧を表示させるスクリプトを書いたんですが、その際にわからなかったことをまとめておきます。JavaScriptに関しては下に書きますが、jQueryは使っていません。

RSS取得後のネームスペース付きXMLからデータを抽出する方法はクロスドメインとは別の問題なので、他のページ「querySelectorでIEでもそれ以外でもネームスペース付のXMLからデータを取得する方法」にまとめています。

クロスドメインのRSSを取得するサーバー構築

需要があるかどうかは別にして、単純に自ドメインのRSSを取り込むだけなら通常通りのやり方で問題ないんですが、クロスドメインになるとアクセス拒否されます。そういった問題に対する手段として「Google Feed API」がありますけど、先日一時的に「Google Feed API」が使えないという騒動になりました。外部サービスに頼るとそのサービスが止まった時に困るという事で、自前で外部RSSを中継するサーバーを立てました。

中継サーバーは数行のスクリプトで出来るんですが、PHPの場合なら次のようになると思います。

<?php
// GETで ?rss=URL という形でリクエストされる場合

// GETのパラメーターにrssがなかったら
// エラーステータスを返して終了
if(!isset($_GET['rss'])){
    header('HTTP/1.0 400 Bad Request');
    exit();
}

$url = rawurldecode($_GET['rss']);

// $_GET['rss']の文字列がURLのパターンにマッチしてなかったら
// エラーステータスを返して終了
if(!preg_match('|^(\S+?:/)?/\S+?\.\S+?/\S+$|', $url)){
    header('HTTP/1.0 400 Bad Request');
    exit();
}

$host = parse_url($url, PHP_URL_HOST);

// 指定のアドレスが存在しない場合
// エラーステータスを返して終了
if(@gethostbyname($host) == $host){
    header('HTTP/1.0 400 Bad Request');
    exit();
}

// 指定されたアドレスのデータを取得
$rss = @file_get_contents($url);

// 注)
// file_get_contents自体のトラブルで通信不能でも
// 通信出来てて200以外の場合でもfalseが返る。
// なので下はレスポンスヘッダを調べている

// レスポンスヘッダがなかったら通信できていない
// エラーステータス(500)を返して終了
if(!isset($http_response_header)){
    header('HTTP/1.0 500 Internal Server Error');
    exit();
}

$response = array_shift($http_response_header);

// レスポンスヘッダが200 OKでないなら
// そのステータス(おそらく500以外)を返して終了
if(false === strpos($response, '200')){
    header($response);
    exit();
}

$content_type = null;

// レスポンスヘッダのContent-Typeを調べる
foreach($http_response_header as $line){
    if(false !== strpos(strtolower($line), 'content-type:')){
        if(false !== strpos($line, 'xml')){
            $content_type = $line;
        }
        break;
    }
}

// 取得したファイルがxmlでない(RSSでない)なら
// エラーステータスを返して終了
if(!$content_type){
    header('HTTP/1.0 400 Bad Request');
    exit();
}

// 取得したRSS(と思われるxml)をそのまま送信
header('HTTP/1.0 200 OK');
header($content_type);
header('Access-Control-Allow-Origin: *');  
header('Access-Control-Allow-Methods: GET');
print($rss);

/*
 PHPのみの単体ファイルなので終了タグ ?> は不要
 PHPマニュアル http://php.net/manual/ja/language.basic-syntax.phptags.php より
 「ファイル全体が純粋な PHP コードである場合は、ファイルの最後の終了タグは省略するのがおすすめです。」
*/

もし特定ドメインからのアクセスしか許可しないなら、file_get_contents の結果がxmlなのかどうかをチェックせずにそのまま返してもいいのかも知れませんが、今回はアクセス制限をしないので悪用防止でxml以外は返さないようにしています。

ここで重要なのは赤文字の2行です。これがないとクロスドメイン問題が解消されません。

注)このスクリプトを置くURLと同じドメインからのアクセスなら赤文字2行がなくても通信できます。そうではなく、他のドメインとも通信する場合には必要です。例えばこのスクリプトにアクセスして特定サイトの最新記事一覧を取得するブログパーツを配布する場合などは、どのURLのブログからアクセスが来るかわかりません。そういう時には赤文字の2行が必要です。

HTTP access control

HTTP access control (CORS) | MDN

上のサイトに詳しく書いてあるんですが、XMLHttpRequestでクロスドメイン間通信を行うには、サーバー側でそれを許可する旨のヘッダーを送信しないといけません。そのための仕様が「Cross-Origin Resource Sharing (CORS) 」というらしくて、XMLHttpRequest以外にもWebフォントなどを特定ドメインだけに限定して許可したりできます。

今回は説明を簡単にするためにPHPのheader関数で送信していますが、.htaccessに書くことができます。

上の2行を.htaccessに書く場合はこうなります。

Header append Access-Control-Allow-Origin: *
Header append Access-Control-Allow-Methods: GET

Access-Control-Allow-Origin

Access-Control-Allow-Originには、アクセスを許可するURIを指定します。

たとえば、http://example.com にだけアクセスを許すのであれば、次のように書きます。

Access-Control-Allow-Origin: http://example.com

アクセスを許可するサイトを複数指定することも出来なくはないのですが、工夫が必要みたいです。
参考ページ「Access-Control-Allow-Originヘッダで複数のオリジンドメインを許可する方法 – ぷれすとぶろぐ

アドレスを指定せず、すべてのURIに解放するのであれば、上のようにワイルドカード * を使います。次の場合は、すべてのURIからのアクセスを許可することになります

Access-Control-Allow-Origin: *

Access-Control-Allow-Methods

Access-Control-Allow-Methodsには、アクセスに許可するメソッドを指定します。

GET通信のみ許可する場合は次のようになります。

Access-Control-Allow-Methods: GET

Access-Control- で始まるヘッダは他にもあるんですが、この2つの指定だけでもXMLHttpRequestでの通信は出来るようになります。

JavaScript側の対応

サーバー側で上記の設定をしていれば、JavaScript側では普通にXMLHttpRequest通信をするだけです。

WindowsのInternetExplorerだけは、XMLHttpRequest ではなく XDomainRequest でないとクロスドメイン間通信は出来ないと書いてあるサイトが多かったのですが今は大丈夫みたいです。

というかInternetExplorer11(バージョン: 11.0.9600.18124)では window.XDomainRequest が見つかりませんでした。次のようにして試してみたらIE11でもそれ以外でも2が表示されます。

if(window.XDomainRequest){
    alert(1);
}else if(window.XMLHttpRequest){
    alert(2);
}

InternetExplorer11でも window.XMLHttpRequest が返ってくるんですがクロスドメイン間通信は出来ました。ただ、古いバージョンのIEではダメでしょうから、結論としてJavaScriptのXMLHttpRequestでRSSを取得するには下のようになります。

ただし、XMLHttpRequest Level2に対応していないブラウザ(クロスドメイン間通信自体が出来ないブラウザ)ではcallback関数は呼ばれませし、エラーメッセージも表示しません。

私は「サイドバーに最新記事一覧を表示させるブログパーツ」に使ったので、未対応ブラウザではエラー表示をするよりも、パーツのタイトルも含めて一切何も表示させない方がユーザーが混乱しないと思ったので。

jQueryを使わずXMLHttpRequestでRSSを取得するサンプル

/*
取得したいRSSが   http://example.com/index.rdf で
先ほどのサーバーが http://hoge.dwm.me/ の場合
*/

function callback(){
  /* ここに取得したRSSの処理を記述 */
}

var rss_url = 'http://example.com/index.rdf';
var url = 'http://hoge.dwm.me/?rss=' + encodeURIComponent(rss_url);

if(window.XDomainRequest){
    var xhr = new XDomainRequest();
    xhr.onload  = function(){callback();};
    xhr.onerror = function(){}
    xhr.open('GET', url, true);
    xhr.send('');
}else if(window.XMLHttpRequest){
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function(){
        if(this.readyState == 4 && this.status == 200){
            callback();
        }
    };
    xhr.open('GET', url, true);
    xhr.send('');
}

これでRSSのxml自体は取得できます。後は取得したデータを処理するcallback関数の中身を書くだけです。

RSSはネームスペース付きXMLなのでquerySelectorでうまくデータが取得できなかったんですが、JavaScriptでネームスペース付きXMLからデータを取得する方法がわかれば解決します。

それに関してはXMLHttpRequestでのクロスドメイン通信とは違う話なので別のページ「querySelectorでIEでもそれ以外でもネームスペース付のXMLからデータを取得する方法」にまとめました。必要ならそちらをご覧ください。取得したRSSから各ページの最初の画像も抽出して一覧表示するサンプルを掲載しています。

取得するURLが同ドメインかクロスドメインか判断して取得先を振り分けるJavaScript

取得するRSSのURLが固定なら問題ないですが、場合によって同じドメインのRSSを取りに行ったり別ドメインのRSSを取りに行ったりする場合、同じドメインなのに上の自作サーバーを経由するのはムダです。

取得するURLに自ドメインと別ドメインが混在する場合は、JavaScript側でアクセスする先を切り替えるようにします。次はその一例です。

function callback(rss){
  /* ここに取得したRSSの処理を記述 */
}

function get_rss(url){
    var rss_server = 'ここに自作RSS中継サーバーのURL';

    var pattern       = /^(\S+?:\/)?\/([^\/\s]+).*$/;
    var server_domain = rss_server.replace(pattern, '$2');
    var location      = window.location.href.replace(pattern, '$2');

    /*
     指定されたRSSのドメインが閲覧中のページのドメインと
   同じならそのままRSSが取得できるので
   違う場合のみ中継サーバーを使う。
    */
    if(server_domain != location){
        url = rss_server + '?rss=' + encodeURIComponent(url);
    }

    if(window.XDomainRequest){
        var xhr = new XDomainRequest();
        xhr.onload  = function(){callback(this.responseXML);};
        xhr.onerror = function(){}
        xhr.open('GET', url, true);
        xhr.send('');
    }else if(window.XMLHttpRequest){
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function(){
            if(this.readyState == 4 && this.status == 200){
                callback(this.responseXML);
            }
        };
        xhr.open('GET', url, true);
        xhr.send('');
    }
}

get_rss('http://example.com/index.rdf');

取得したデータのContent-Typeを調べるにはgetResponseHeaderを使う

今回のスクリプトでは使っていませんが、もし取得したデータのレスポンスヘッダを見るにはgetResponseHeaderメソッドを使います。Content-Typeを取得したい場合は次のようにします。

var content_type = xhr.getResponseHeader('Content-Type');

特定のサブドメインだけを別サーバーで運用するDNSの設定

こないだツイッターで「特定のサブドメインだけ〇〇サーバーで運用したいのに、〇〇サーバーはサブドメインだけを指定できないから公開できない」という内容のツイートを見かけまして、それ根本的な間違いをしてるんじゃなかろうか?などと思ったんですが、多分公開できると思います。

こないだツイッターで「特定のサブドメインだけ〇〇サーバーで運用したいのに、〇〇サーバーはサブドメインだけを指定できないから公開できない」という内容のツイートを見かけまして、それ根本的な間違いをしてるんじゃなかろうか?などと思ったんですが、多分公開できると思います。

考えられる方法は2通りあります。

  1. サブドメインなしのメインドメインごと登録して設定する
  2. 特定のサブドメインをメインドメインとして登録し設定する

サブドメインなしのメインドメインごと登録して設定する

状況として次の場合を想定します。

  • ドメイン管理は株式会社Aドメイン
  • サブドメインなしの example.com はレンタルサーバーB
  • サブドメインありの hoge.example.com はレンタルサーバーC

株式会社AドメインのDNS(ネームサーバー)で example.com の設定が正しく出来ている場合、ブラウザに http://example.com と打ち込むと、水面下では次のような攻防が繰り広げられます。

イメージ:
.comのネームサーバーに聞く
ブラウザ「example.com さんのIPアドレスを教えてください」
ネームサーバー「example.com さんなら株式会社Aドメインに聞けば分かりますよ」
株式会社Aドメインのネームサーバーに聞く
ブラウザ「example.com さんのIPアドレスを教えてください」
ネームサーバー「example.com さんならレンタルサーバーBに聞けば分かりますよ」
レンタルサーバーBのネームサーバーに聞く
ブラウザ「example.com さんのIPアドレスを教えてください」
ネームサーバー「それなら 127.0.0.1ですよ」
127.0.0.1にアクセス » ページ読み込み

結論として、DNSとは即ち「たらいまわし」と言えます。

ここで、hoge.example.com だけは、レンタルサーバーCで運用する事にした場合、ブラウザに http://hoge.example.com と打ち込むと、株式会社Aドメインのネームサーバーはこう答えます。

「hoge.example.com さんならレンタルサーバーCに聞けば分かりますよ」

株式会社Aドメインのネームサーバーに問い合わせた段階で
サブドメインなしの example.com は レンタルサーバーB へ
サブドメインありの hoge.example.com はレンタルサーバーC へ
と振り分けられます。

ということは、こういう事になります。

レンタルサーバーB と レンタルサーバーC の両方で、example.com の設定をしていて支障はない。

わかるでしょうか?冒頭のツイート「〇〇サーバーはサブドメインだけを指定できないから公開できない」これは、何も問題がないという事です。

おそらく、ツイートした人は「◯◯サーバーではサブドメインだけの指定しかしてはいけない」と思っているのではないでしょうか。何故なら、サブドメインなしの example.com はレンタルサーバーBで使うから。でも、それは間違いです。

ちょっと、ややこしいですが、株式会社Aドメインのネームサーバーが正確にレンタルサーバーB と レンタルサーバーC への振り分けを行なってくれるなら、レンタルサーバーC へはサブドメインなしのexample.com の問い合わせは絶対に行われません。だから、レンタルサーバーC で example.com の設定をしても使われないだけです。使われないだけなので設定しても問題ないんです。

具体的には、レンタルサーバーCでサブドメインなしの example.com を登録してその中で、hoge.example.com の設定を次のようにすれば、レンタルサーバーCで hoge.example.com のサイトは運用できます。

a hoge xxx.xxx.xxx.xxx

特定のサブドメインをメインドメインとして登録し設定する

通常は、上の設定で問題ありません。

ただし、イレギュラーな方法としてレンタルサーバーCの登録ドメインを、サブドメインなしの hoge.example.com にしてしまうという方法も考えられます。サブドメインなしの hoge.example.com です。

example.com は .com のサブドメインです。なのに、example.com をサブドメインなしのメインドメインとして登録できるなら、hoge.example.com もサブドメインなしのメインドメインとして登録できるという事になります。

その場合、設定は次のようになります。

a @ xxx.xxx.xxx.xxx

ただこの方法だと後々、example.com の全てのサイトをマルっとレンタルサーバーCで運用するとなった場合、設定をやり直さなくては面倒なので、最初の「サブドメインなしのメインドメインごと登録して設定する」方法でやっておいた方が面倒なことにならないのではないかと思います。

gmailのパスワードは記号も使って複雑にした方がいいと思う話。WordPressもね

gmailやWordPressのログインパスワードは、アルファベットと数字以外に「記号」も使えます。そして、この記号を使うとパスワードが破られる確率がもの凄く上がります。実際に、検証してみます。

gmailのパスワードは、アルファベットと数字以外に「記号」も使えます。

記号というのは !”#$%&'()~=|\ みたいな文字です。

gmail以外にも、ブログソフトで有名なWordPressのログインパスワードも、これらの記号が使えます。そして、この記号を使うとパスワードが破られる確率がもの凄く上がります。実際に、検証してみます。

記号を使うと、不正ログインを防ぐ確率がもの凄く上がる

実際に、どのくらい防げる確率が上がるのかを計算してみます。

パスワードは長ければ長いほど安全

アルファベットは大文字、小文字がそれぞれ26文字あります。

ABCDEFGHIJKLMNOPQRSTUVWXYZ

アルファベットの大文字は26字だけなので、1文字を選ぶとすると確率は26分の1です。ですから、パスワードがアルファベットの大文字で、かつ1文字だけだという条件だと、適当に打ち込んで一致する確率は26分の1です。

では、このアルファベットで2文字のパスワードを作るとどうなるでしょう?

26 × 26 なので、答えは 676通りです。適当に文字を打ち込んでも一致しない確率が跳ね上がりました。

パスワードを10文字にすると、どうなるでしょうか?

26×26×26×26×26×26×26×26×26×26=141167095653376

とても沢山ですね(⌒-⌒;).

パスワードに単語は使うな

アルファベット26文字を10個並べれば、141167095653376種類のパスワードが出来るなら、それだけで充分安全だと思ったら考えが甘いです。

ターミネーターを英数字で打ち込むと、 TERMINATOR と10文字になります。スターウオーズ STARWARS でも8文字あります。アルファベットは26文字しか無いから、単語を作る時は文字数が多くなります。なので誰もが思いつく英単語を安易にパスワードにすると、破られる確率がグッと上がります。辞書に載っている単語を総当りで打ち込んでパスワードを破ろうとするアタックは実際にあります。推測できる単語をパスワードにするのは危険です。

これは人の名前でも同じで豊臣秀吉さんが、そのまま自分の名前をパスワードにしても TOYOTOMIHIDEYOSHI と17文字にしかなりません。

パスワードは使える文字が多いほど安全

TOYOTOMIHIDEYOSHIで17文字しか無いと書くと、「17文字あれば十分でしょ」と思うかも知れませんが、実際のところ、あんまり文字数を増やすのも大変です。

では、どうするか?基底となる数字を増やせばいいんです。ここまでは、アルファベットの大文字26文字限定で考えてきました。この基底の26をもっと増やせば、より安全になります。

英数字を含めると10種類文字が増える

0123456789の英数字をパスワードに含めるだけで基底の数が10増えます。アルファベットの大文字26字に数字10文字を足すと36です。ここから2文字を選ぶと確率は、36×36 = 1296 です。アルファベットだけの 26×26 では 676通りでした。非常に増えているのがわかると思います。アルファベット大文字、小文字、英数字を使うと、ベースの文字数は 26×2+10 で62通りになります。

記号を使えばもっと安全

Googleのパスワードや、ブログソフトWordPressのログインパスワードにはアルファベットと英数字以外に記号も使えます。だから、記号を含めたパスワードにすると破られる確率が激減します。

ひとつには基底の文字数の増大、そして、意味をなさない文字なので推測が不可能という理由です。

使える文字が多いと組み合わせをたくさん試さないと一致しない。だからパスワードを破りにくいのはわかった。でも、基底の文字が増えている時点でデタラメ打つ回数が増えるんだから、確率はアルファベットだけでも同じなんじゃない?と思うかも知れません。ただ、不正ログインのためにパスワードを破ろうとする輩もよく使う文字から打ち込み始めるという事を考えてください。

パスワードを顔文字に出来ますか?

わかりません。顔文字だと特殊な記号が多いので作れないかもしれません。ひらがなや漢字みたいな特定の国の文字まで使えるわけではないと思います。

どの文字が使えて、どの文字が使えないのかは、実際にパスワード変更でチャレンジしてみればわかります。パスワードの登録や変更に失敗したら、その中に使えない文字があるという事です。

記号を含めたパスワードが覚えられません。どうしたらいいですか?

難しい問題です。

ただ、自分でもパスワードを覚えていないという事は万が一、テロリストに誘拐されて「パスワード教えろ!吐けー」と拷問されても白状しないで済みます。死ぬかも知れませんが。

そんなあなたには、パスワード管理ソフトを探してみる事をおすすめします。管理アプリにログインするための、ひとつのパスワードだけ覚えていれば、後は覚えていなくても大丈夫というパスワード管理ソフトは、探せばいろいろあるみたいです。

画像が縦長か横長か調べて自動でクラス名をつけるJavaScript

画像が横長なのか、縦長なのか、正方形なのかで分けて、それぞれクラス名を追加するJavaScriptを書いてみました。よく読んでもらっているページに「絶対はみ出さない画像!自動でサイズ調節するスタイルシート」というのがあるんですが、これに関連したことで「スマホで見ても、すべての画像が横幅いっぱいになって、はみ出さなくなったんですが、縦長の写真だけサイズを変えられないか」という質問を受けました。

うちでよく読んでもらっているページに「絶対はみ出さない画像!自動でサイズ調節するスタイルシート」というのがあるんですが、これに関連したことで質問を受けました。

「スマホで見ても、すべての画像が横幅いっぱいになって、はみ出さなくなったんですが、縦長の写真だけサイズを変えられないか」という内容です。

画像が横長なのか、縦長なのか、正方形なのかで分けて、それぞれクラス名をつければいいんですが、もうすでに大量のページがある場合は全ページを修正しなくてはいけないし、そうでないとしても毎回画像毎にクラス名を割り当てるのは大変です。

そこで、自動でクラス名を追加するJavaScriptを書いてみました。

画像のサイズを調べてクラス名を割り当てるJavaScript

今回、参考になったのは次のページです。これが非常に素晴らしい内容で、作業がとても簡単になりました。ありがとうございます。

[JavaScript] 画像のオリジナル サイズを取得する 最もシンプルな方法 – こじょらぼ

で、実際に作ったソースはこんなカンジです。HTMLのどこに追加しても動きますが、<head> 部分の終わりにある「</head> の直前」につけるのがいいと思います。

<script>
(function(){
	function image_class(){
		var img = new Image();
		var images = document.querySelectorAll('img');

		for(var i=0;i<images.length;i++){
			img.src = images[i].src;

			if(img.width < img.height){
				images[i].className += ' vertically_long';
				images[i].parentNode.className += ' vertically_long_outer';
			}else if(img.width > img.height){
				images[i].className += ' horizontally_long';
				images[i].parentNode.className += ' horizontally_long_outer';
			}else{
				images[i].className += ' square';
				images[i].parentNode.className += ' square_outer';
			}
		}
	}

	if(window.addEventListener){
		window.addEventListener('load', image_class, false);
	}else if(window.attachEvent){
		window.attachEvent('onload', image_class);
	}
})();
</script>

これでページ読み込み完了後
縦長の画像には vertically_long というクラス名が
横長の画像には horizontally_long というクラス名が
正方形には square というクラス名が追加されます。

さらに
vertically_long の親ノードには vertically_long_outer
horizontally_long の親ノードには horizontally_long_outer
square の親ノードには square_outer
というクラス名が追加されます。

このクラス名毎にスマホ専用スタイルシートを書けば、好きなように表示を変えられます。

ただ、お気づきかと思いますが同じ親ノードの中に、縦長と横長の両方の画像があった場合、両方のクラス名が親ノードに追加されるので、その部分は思ったように表示されないと思います。

サンプルページ

このスクリプトを適用していない場合と、適用した場合のサンプルページを用意しました。2つのページの違いはスクリプトをつけているか、いないかだけです。

スマホで見ても絶対にはみ出しませんが、スクリプトを適用したページだけ、縦長と正方形の表示が変わります。

スクリプトを適用していない場合
http://dwm.me/download/vertical_and_horizontal_ratio_js_sample_1.html
スクリプトを適用した場合
http://dwm.me/download/vertical_and_horizontal_ratio_js_sample_2.html

サンプルページのスタイルシートは次のようになっています。

<style type="text/css">

/* これで画像は絶対にはみ出さない */
img {
	max-width: 100%;
	height: auto;
}

/* 縦長の画像を真ん中に配置する */
.vertically_long_outer {
	text-align: center;
}

/* 縦長の画像のサイズを横幅120ピクセルに固定 */
/* 高さは自動で調整 */
.vertically_long {
	width: 120px;
	height: auto;
}

/* 正方形の画像を右寄せで配置 */
.square_outer {
	text-align: right;
}

/* 正方形画像の高さを200ピクセル、幅も200ピクセルに固定 */
.square {
	width: 200px;
	height: 200px;
}

</style>

真ん中合わせにしたいのに、左寄せになってしまう場合は下のように変更してください。

変更前

.vertically_long {
	width: 120px;
	height: auto;
}

変更後

.vertically_long {
	width: 120px;
	height: auto;
	/*2行追加*/
	margin-left: auto;
	margin-right: auto;
}

2015年1月9日追記:今年になってSeesaaブログでの表示で縦の長さが固定されてしまい、表示がおかしくなったというご指摘がありました。その場合は width と height に !important を追加してください。


height: auto !important;

今後更に変更される場合があるので、width と height 以外もすべて !important を追加してもいいかもしれません。

これを、ページの本文にだけ適用させたくて、サイドバーなどそれ以外の部分には影響を与えたくない場合があると思います。

例えばSeesaaブログなら各ページの本文は #content .text の中にあるので、それをスタイルシートに追加してください。(同じSeesaaブログでも構成の違うテンプレートがあるようです。詳しくはコメント欄を参照してください。)

具体的に言うとこんなカンジになります。

<style type="text/css">

#content .text img {
	max-width: 100%;
	height: auto;
}

#content .text .vertically_long_outer {
	text-align: center;
}

〜〜以下省略〜〜