最近のウェブ制作はスマホ、タブレット、多様化したブラウザやディスプレイへの画像対応が大変です。
画像やディスプレイの出し分けにpictureタグやsrcsetがだいぶ浸透してきましたが、属性が多くて記述がしんどい!のでEJSで関数化して少ないコードで出力できるようにしました。そのコードのご紹介です。
かみーゆ/フロントエンドエンジニア
EJSてそもそも何ぞ?
EJSは埋め込み型JavaScriptテンプレートで、Gulpなどを使ってHTMLに吐き出すことができます。
最初の設定等は少し面倒ですが、一度設定すると作業が効率化できます。
Gulpからの実装の方法はこちらにまとめています。
関数の書き方
まずは関数の書き方です。
関数は変数に格納し、戻り値を取り出して使います。
特殊な記述方法に関しては、【Gulp】EJSを使ってHTMLを量産するのおまけejsお役立ち情報こちらを参照してください。
<%
hello = function(){
return `<p>Hello, World!!</p>`;
}
%>
<%- hello()%>
出力結果。
<p>Hello, World!!</p>
引数
引数を渡すこともできます。
<%
hello = function(name){
return `<p>Hello, World!! I am ${name}.</p>`;
}
%>
<%- hello('Camille')%>
出力結果。
<p>Hello, World!! I am Camille.</p>
引数にはデフォルト値を入れておくこともできます。
<%
hello = function(name='Camille'){
return `<p>Hello, World!! I am ${name}.</p>`;
}
%>
<%- hello()%>
出力結果は一緒。
<p>Hello, World!! I am Camille.</p>
picture タグを毎度ガチで書くのはめんどくさい
pictureタグはブラウザやユーザーの環境(モバイルとかPC)に応じて出力したい画像を変えることができます。
例えば、以下のように画像をWebP対応してあるブラウザの場合はWebPを、それ以外はPNG画像を表示、さらにウィンドウ幅に合わせて画像サイズを変えます。
さらに、loading="lazy"
Lazy Loadやdecoding="async"
デコード処理を非同期したらたった一箇所に画像を出力するためにこれだけのコードを書かなければなりません。
<picture>
<source
type="image/webp"
sizes="(max-width: 480px) 440px,800px"
srcset="/assets/images/gazou@480.png.webp 480w,/assets/images/gazou.png.webp 800w"
>
<img
src="/assets/images/top/gazou.png"
sizes="(max-width: 480px) 440px,800px"
srcset="/assets/images/gazou@480.png 480w,/assets/images/gazou.png 800w"
alt="画像"
width="1200"
height="800"
loading="lazy"
decoding="async"
>
</picture>
カオス!!正気の沙汰じゃない!
関数でpicture タグの記述量を減らす
解決するためにEJSの関数の出番というわけです。
<%
//webp書き出し用の変数
imgTag = function(src, width, height, alt="", className="", loading=true){
const srcSp = src.replace('.','@480.')
const srcWebp = src.split('.')[0]
let prop = loading ? ` loading="lazy" decoding="async"` : ''
return `<picture class="${className}">
<source
sizes="(max-width: 480px) 440px,800px"
srcset="/assets/images/${srcSp}.webp 480w,/assets/images/${src}.webp 800w"
type="image/webp"
>
<img
sizes="(max-width: 480px) 440px,800px"
srcset="/assets/images/${src} 480w,/assets/images/${src} 800w"
src="assets/images/${srcSp}"
alt="${alt}"
width="${width}"
height="${height}"
${prop}
>
</picture>`;
}
%>
<%- imgTag("works-01.jpg", 1200, 1200, "画像", "img")%>
loading="lazy"
やdecoding="async"
は最初に表示される場所(ファーストビュー)では使えないので、属性を付与するか否かは引数でコントロールします。
出力結果。
<picture class="img">
<source sizes="(max-width: 480px) 440px,800px" srcset="/assets/images/works-01@480.jpg.webp 480w,/assets/images/works-01.jpg.webp 800w" type="image/webp">
<img src="/assets/images/top/works-01.png" sizes="(max-width: 480px) 440px,800px" srcset="/assets/images/works-01.jpg 480w,/assets/images/works-01.jpg 800w" alt="画像" width="1200" height="1200" loading="lazy" decoding="async">
</picture>
これはあくまで例なので、もしこの関数を使う場合は適宜引数などを調整してみてください。
おまけ・関数を連想配列に格納してまとめておく
関数は連想配列(オブジェクト)にまとめておくこともできます。
<%
functions = {
fnc01: function(){
return "fnc01"
},
fnc02: function(){
return "fnc02"
}
}
%>
<%- functions.fnc01() %>
インクルードすればどこからでも呼び出せます。
<% include("./_func.ejs")%>
まとめ・EJSを使うとブラウザや画像対応の複雑化したコードを簡略化できる
最近はスマホ、タブレット、多様化したブラウザやディスプレイへの画像対応が大変です。
環境に応じて最適化した画像を表示させるのは表示速度にも影響をあたえるのでこういうコードが書けなきゃいけませんよね。
いざコード書いてみたらすごく長いので正直嫌だな-と思ったのがきっかけ
pictureタグを関数化したらめっちゃ楽になりました。
おそらく、他の言語でも応用が効くと思います。
この記事がみなさんのコーディングライフの一助となれば幸いです。
最後までお読みいただきありがとうございました。