ようやくここ数年日本企業でもレガシーブラウザをサポート対象から外してくれるようになってきた昨今、retinaディスプレイも増えsvgファイルを使用する機会も増えてきました。今、作業しているプロジェクトでもsvgファイルを結構使用しているのですが、svgファイルをImage()関数で読み込んで画像のサイズを取得してごにょごにょしていたところ、IE11においてサイズが取得できない問題に直面したので、その解決方法を備忘録も兼ねて紹介したいと思います。
環境
なお、今回紹介するコードの中にはjQuery版もありますが、jQueryのバージョンに関しては下記バージョンを使用しています。
今回の環境
- jQuery3.2.1
よくあるプリロード方法
まずは、よくあるImage()関数を使用したオーソドックスなプリロード(読み込み)方法がこちら。なお、このケースでは「preload」というクラス名が付与されているimgタグのsvgデータを読み込むことを想定しています。
jQuery
var image = new Image();
image.onload = function(){
console.log(this.width); // 読み込み画像の横幅取得
console.log(this.height); // 読み込み画像の縦幅取得
}
image.src = $('.preload').attr('src');
js
var image = new Image();
image.onload = function(){
console.log(this.width); // 読み込み画像の横幅取得
console.log(this.height); // 読み込み画像の縦幅取得
}
image.src = document.querySelector('.preload').getAttribute('src');
こんな感じでオリジナル縦横サイズを取得することができます。
IE11のバグ
上記の方法で、基本的には大丈夫なのですが、ここで問題になるのがやはりIEです。IE11(IE10以下は未検証)で上記のコードを実行した結果、縦幅も横幅もどちらも「0」が返ってきます。
画像の読み込み完了だけを知りたいのであれば、別にサイズが分からなくても困ることはありませんが、オリジナルのサイズを元に拡大縮小したり、アニメーションを当てたいときにはクリティカルな問題になります。
解決方法
そんな、いまだに僕らを困らせるIEですが、IE11でもImage()関数を使ってsvgファイルのオリジナルサイズを取得する方法がこちらになります。
jQuery
var image = new Image();
image.onload = function(){
$('body').append(this);
console.log(this.offsetWidth); // 読み込み画像の横幅取得
console.log(this.offsetHeight); // 読み込み画像の縦幅取得
$(this).remove();
}
image.src = $('.preload').attr('src');
js
var image = new Image();
image.onload = function(){
document.body.appendChild(this);
console.log(this.offsetWidth); // 読み込み画像の横幅取得
console.log(this.offsetHeight); // 読み込み画像の縦幅取得
document.body.removeChild(this);
}
image.src = document.querySelector('.preloadImg').getAttribute('src');
ご覧の通りですが、読み込みが完了したタイミングで、bodyに該当のデータを挿入し「offsetWidth」と「offsetHeight」を使って取得しています。
offsetWidth(Height)プロパティはborderやpaddingの幅も含めた全体の幅を取得するプロパティとして知られていますが、svgファイルのサイズ取得に関してもこのプロパティで取得できます。
まとめ
ということで、今回は備忘録も兼ねて、javascriptのImage()関数を使用してsvgファイルのオリジナルサイズを取得する方法を紹介しました。
この記事のまとめ
- IE11の場合、Image()関数のwidthプロパティではsvgデータのオリジナルサイズが取得できない
- offsetWidth(Height)を使えばIE11でもサイズ取得可能
- offsetWidth(Height)で取得する前にbodyに一時的に読み込みデータを挿入
こんな感じですかね。それでは今回はここまで!また!