【改良版】コピペでOK!画像や動画を親要素にフィットさせて中央に表示する

【改良版】コピペでOK!画像や動画を親要素にフィットさせて中央に

以前、「【jQuery】コピペでOK!画像や動画を全画面にフィットさせて中央に表示する」という記事を書きました。
しかし実際に使っていると、なんだかと痒いころに手が届かない、使い勝手の悪いコードだなと気付きました。

ですので、バージョンアップしたコードを作成したので、こちらで解説していきます。

前回のjQueryコードの改良したいところ

ボックスのサイズ限定じゃなくて、色々なサイズのボックスにフィットさせたい

前回まではブラウザ全画面に広がったボックスにサイズが限定されていました。サイズ限定のコードでは柔軟性がありませんので、フィットさせたい要素をラップする親要素のサイズを取得してフィットさせるよう改良します。

これで全画面のメインビジュアルでも、記事サムネイルみたいな小さなイメージでも、1つのコードで対応できるようにします。

jQueryだけで完結したい

これも使ってて気づいたのですが、jQueryのコード内でCSSの「top」とかは設定してるのに、「position:absolute」はスタイルシートで設定していました。しかも「position:absolute」を設定し忘れると意図した表示にならずバグります。。。

また、ラップする親要素も「position:relative」と「overflow:hidden」の設定が必須ですが、それもスタイルシートで設定していたので、同様にスタイルを設定し忘れるとバグります。。。

ですので、CSSをいじらずjQueryのみで完結するようにします。

ベースのHTML・CSS

まずはベースのHTML・CSSをご確認ください。

HTML

<div class="parentbox">
    <img class="fitimg" src="sample.jpg">
</div>

フィットさせたい要素「.fitimg」を、ラップしている親要素「.parentbox」にフィットさせます。

CSS

.parentbox{
    height: 400px;
}

また親要素「.parentbox」は必ず高さが指定してあることが前提となります。高さの指定がないと、内包する「.fitimg」が「position:absolute」になるため何も表示されなくなってしまいます。

サンプル

では一度サンプルをご確認ください。

サイト上部にメインビジュアルがあり、画像がフィットしています。また、記事サムネイルも同様に画像がフィットしています。ブラウザのサイズを変えても常にフィットします。

全ての画像はサイズが違います。メインビジュアルと記事サムネイルのボックスサイズも違います。このように色々なサイズのボックスサイズに対応できるよう、柔軟な仕様になっています。

HTML

ではそれぞれのコードを説明していきます。

<div class="hero">
    <img class="js-fit-hero" src="images/hero.jpg" alt="">
</div><!--hero-->
<main class="main">
    <article class="post">
        <figure class="post__img">
            <img class="js-fit-post-img" src="images/thumbnail.jpg" alt="">
        </figure>
        <div class="post__content">
            <h2 class="post__content__title">section title1</h2>
            <p>記事の抜粋文など記事の抜粋文など記事の抜粋文など<br>記事の抜粋文など記事の抜粋文など</p>
        </div><!--post__content-->
    </article>
    <article class="post">
        <figure class="post__img">
            <img class="js-fit-post-img" src="images/thumbnail2.jpg" alt="">
        </figure>
        <div class="post__content">
            <h2 class="post__content__title">section title1</h2>
            <p>記事の抜粋文など記事の抜粋文など記事の抜粋文など<br>記事の抜粋文など記事の抜粋文など</p>
        </div><!--post__content-->
    </article>
</main>
<footer class="footer">
    <p class="copyright">@2017 WEBDESIGNDAY</p>
</footer>

2行目

メインビジュアル部分、「.js-fit-hero」をラップする親要素の「.hero」にフィットさせます。

7・16行目

記事サムネイル部分、「.js-fit-post-img」をラップする親要素の「.post__img」にフィットさせます。

CSS

*{
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}
.hero{
    margin-bottom: 100px;
    height: 400px;
}
.main{
    margin: 0 auto 100px;
    width: 80%;
}
.post{
    display: flex;
    justify-content: space-between;
    margin-top: 40px;
}
.post__img{
    height: 300px;
    width: 30%;
}
.post__content{
    width: 65%;
}
.post__content__title{
    margin-bottom: 40px;
}
.footer{
    background: #222;
    color: #fff;
    padding: 40px 0;
    text-align: center;
}

8・20行目

メインビジュアル「.hero」と記事サムネイル「. post__img」に高さを設定しています。

前回までは、CSSでフィットさせたい要素に「position:absolute」、ラップする親要素に「position:relative」と「overflow:hidden」を設定しないとjQueryのコードが正しくてもバグっていました。(汗)

今回は見てもらえばわかるように、CSS側では親要素もフィットさせたい要素もCSSは設定しません。この後のjQueryで完結させます。

jQuery

$(window).on('load',function(){
    fitImg( $('.js-fit-hero') );
     
    $('.js-fit-post-img').each(function(){
        fitImg( $(this) );
    });
});
 
$(window).on('resize',function(){
    fitImg( $('.js-fit-hero') );
     
    $('.js-fit-post-img').each(function(){
        fitImg( $(this) );
    });
});
     
function fitImg(object){        
    //親要素取得
    var parent = object.parent();
 
    //画像サイズ取得
    var imgW = object.width();
    var imgH = object.height();
 
    //フィットさせる親要素のサイズ取得
    var parentW = parent.width();
    var parentH = parent.height();  
 
    //幅・高さの拡大率取得
    var scaleW = parentW / imgW;
    var scaleH = parentH / imgH;
 
    //幅・高さの拡大率の大きいものを取得
    var fixScale = Math.max(scaleW, scaleH);
 
    //画像の幅高さを設定
    var setW = imgW * fixScale;
    var setH = imgH * fixScale;
 
    //画像の位置を設定
    var moveX = Math.floor((parentW - setW) / 2);
    var moveY = Math.floor((parentH - setH) / 2);
 
    //設定した数値でスタイルを適用
    //親要素のスタイル
    parent.css({
        'overflow': 'hidden',
        'position' : 'relative'
    });
    //フィットさせる要素のスタイル
    object.css({
        'position': 'absolute',
        'width': setW,
        'height': setH,
        'left' : moveX,
        'top' : moveY
    });
}

2・5行目

この後説明しますが、作成した関数で「fitImg(‘フィットさせたい要素’)」とするだけで親要素にフィットさせます。

5行目は記事サムネイルの部分ですが、同じ要素が複数ある場合は、それぞれのサイズを正しく取得するため、「each」内に「this」で要素を指定しましょう。

また、画像は読み込み完了を待ってから処理しないと意図しない表示になるので「load」内で処理を記載しています。

9行目

ウィンドウがリサイズされてもフィットするように「resize」内にも同じ処理を記載します。

17行目

関数「fitImg」を作成しました。こちらの中の処理を改良しました。

19行目

一番の改良点です。フィットさせたい要素の親要素をjQueryで取得するようにしました。前回まではwindowのサイズ限定でしたが、柔軟に対応できるようになりました。

47・48・52行目

ここが前回まではスタイルシートで設定していたスタイルです。設定し忘れると表示がバグるというひどいことになっていた部分です。jQuery内で親要素もフィットさせたい要素もスタイルを設定するので、スタイルシートをいじる必要はなくなりました。なぜこれに気づかないのか。。。反省です。

要素をフィットさせているロジックをざっくり説明します。

30・31行目

親要素の幅と高さそれぞれを、フィットさせたい要素の幅と高さで割って拡大率を出します。

34行目

幅と高さの拡大率の大きい方を取得します。これによって、親要素に対してフィットさせたい要素の方が必ず大きくなり、見切れることがなく全体にフィットします。

41・42行目

次にセンターに配置する処理です。フィットさせたい要素が親要素よりはみ出した数値の半分を取得します。

55・56行目

先ほどの数値の分、top・leftそれぞれマイナスに指導させることでセンター配置になります。

これでCSSの「background-size: cover」と同じ処理になります。

動画もフィット

動画も全く同じですがサンプル作成しましたので見てみてください。ただ「img」タグが「video」タグになっただけです。

もちろん前回記事のように親要素が全画面であれば全画面にフィットします。

jQuery本体はCDNで設置してますが本記事では割愛します。CDNでの設置方法は下記をチェックしてみてください。

画像は動画は下記のサイトからダウンロードしました。素敵な素材がたくさんあります。

まとめ

まだまだ至らないところばかりなので、今回の記事のように、以前書いたしょーもないコードなどは気づいたら即アップデートしていきます。

今回はバグ修正みたいな感じでしたが、CSSやjQueryはきっとこれからさらに進化していくので、それを使うこちらも、情報・テクニックをアップデートしていく必要があります。今まで当たり前になっていたことも、もっといい方法があるならやってみるべし!というチャレンジ精神は常に持っていたいものです。

Category&Tag