こんにちは、ryohei(@ityryohei)です!

本記事では、JavaScriptでimg要素の画像サイズを取得してwidth・height属性を自動で追加する方法をご紹介しています。

img要素のsrcから画像のサイズを取得してwidth・height属性を自動で指定したいんだけど、良い方法ないかな?

上記の疑問にお答えします。

では、解説していきます。

画像サイズを取得してimg要素に設定する方法

画像サイズを取得する方法は複数ありますが、本記事ではImageオブジェクトで取得する方法で解説します。Imageオブジェクトに画像を設定して、設定した画像のサイズ(widthheight)を取得するには下記のように記述します。

const image = new Image();

image.src = '画像のパス';
image.width; //画像の横幅を取得
image.height; //画像の高さを取得

実際にページ内のimg要素を全て取得してwidthheightの設定までを組んだスクリプトがこちら。

//ページ内のimg要素をすべて取得
const imgs = document.getElementsByTagName('img');
//Imageオブジェクトをインスタンス化
const image = new Image();

//img要素の数だけ繰り返し処理
for (const img of imgs) {

    //img要素からsrc属性の値を取得
    //Imageオブジェクトのsrcプロパティに代入    
    image.src = img.getAttribute('src');
    

    //画像の横幅をimg要素のwidth属性の値に設定
    img.setAttribute('width', image.width);

    //画像の高さをimg要素のheight属性の値に設定
    img.setAttribute('height', image.height);
}

一応上記のスクリプトでページ内のimg要素から画像を取得し、widthheightを自動で追加するところまで実現できます。

試しにPicsumさんからダミーの画像をお借りして、動作を確認してみます。

HTML

<div id="app">
    <img src="https://picsum.photos/id/1008/1920/1080" alt="">
    <img src="https://picsum.photos/id/656/1280/720" alt="">
    <img src="https://picsum.photos/id/646/1366/768" alt="">
</div>

JavaScriptは先ほどご紹介したものをそのまま使いまして……。

完成したデモがこちら!

See the Pen yLgrJGa by ryohei (@intotheprogram) on CodePen.31883

環境によってはちゃんとwidthheightが設定されている方もいらっしゃると思いますが、何度か再読み込みをすると下記のように値が設定されます。

<div id="app">
    <img src="https://picsum.photos/id/1008/1920/1080" alt="" width="0" height="0">
    <img src="https://picsum.photos/id/656/1280/720" alt="" width="0" height="0">
    <img src="https://picsum.photos/id/646/1366/768" alt="" width="0" height="0">
</div>

widthheightが0に設定されています。これでは自動で追加する意味がないどころか、デメリットしかないですね。

なぜこのようなことが起こるのでしょうか。

調べたところ、原因はすごく単純でした。

画像が読み込まれる前にサイズを取得するから

img要素が指定された画像パスから実際に画像を読み込む前に、画像サイズを取得していたため、値が0になっていました。読み込まれていない画像のサイズを参照しているわけですから、当然結果は0になります。なので、画像が読み込まれた後にサイズを取得するように処理を改善する必要があります。

Promiseで画像を非同期に読み込む

Promiseは非同期処理の最終的な結果を表すオブジェクトです。Promiseで画像の読み込みが完了した後に画像サイズを取得してimg要素に設定することで前項のような結果を回避することができます。

実際にPromiseで作り直した処理がこちら!(HTMLに変更はないので割愛します。)

//関数定義
const myFunc = function(src){

    //Promiseオブジェクトを生成して返す
    return new Promise(function(resolve, reject){
        //Imageオブジェクトを生成
        const image = new Image();

        //読み込む画像を設定(関数の引数で取得した画像パスを代入)
        image.src = src;

        //onloadで画像読み込み完了後に処理
        image.onload = function(){
            //成功時にthenの処理へ
            resolve(image);
        }

        //onerrorで画像読み込みエラー時に処理
        image.onerror = function(error){
            //失敗時にcatchの処理へ
            reject(error);
        }
    });
}

//ページ内のimg要素を取得
const imgs = document.getElementsByTagName('img');

//img要素の数だけ繰り返し処理
for (const img of imgs) {

    //img要素のsrc属性の値を取得
    const src = img.getAttribute('src');

    //関数実行
    myFunc(src)

    //読み込みが完了した(画像が設定された)Imageオブジェクトを受け取って処理
    .then(function(res){

        //img要素のwidth属性に値を設定
        img.setAttribute('width', res.width);

        //img要素のheight属性に値を設定
        img.setAttribute('height', res.height);
    })

    //読み込みエラー時の処理
    .catch(function(error){
        console.log(error);
    });
}

下記デモにおいてもきちんとwidthheight属性に値が設定されています。

See the Pen Img width height auto2|JavaScript by ryohei (@intotheprogram) on CodePen.31883

これでimg要素にwidthheight属性を自動で追加することができます。

最後に

JavaScriptのレンダリング結果がHTMLと同様にSEOにおいて評価されるようになったことからわかるように、JavaScriptにおける処理結果も考慮されるようになりました。もちろん静的に記述しておいた方が無難ですが、昔のサイトであったり数が多い場合などはJavaScriptのレンダリングに委ねるのも良いかもしれないですね。

以上、JavaScriptでimg要素の画像サイズを取得してwidth・heightを自動追加する方法のご紹介でした!