image_tagで画像を表示させる際の話。
ディスプレイがretinaの場合、画像のサイズによっては画像がぼやけて表示されます。
その時に登場するのがsrcset
です。
retinaに対応させた画像表示の方法はcssやjsを使った方法もありますが、今回はhtml側で呼び出す画像を選別できるようにします。
今回はその中でも2パターン詳解します。
一つ目は、carrierwaveによる画像投稿をしていて、app/public/uploads 配下に画像が配置されている場合
二つ目は、ハードコーディングで画像リンクを明記し、app/assets/images 配下に画像が配置されている場合
carrierwaveを使って画像の投稿をしているパターン
例えば縦100px横200pxの画像を表示するとします。
まず、carrierwaveのimage_uploader.rbにversionを追加します。
versionの名前は適当でも良いですが、画像サイズが明記されていたほうが管理しやすいです。
require 'carrierwave/processing/mime_types'
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
include CarrierWave::MimeTypes
process :set_content_type
version :size_100_200 do
process resize_to_fill: [100, 200]
end
version :size_100_200_for_retina do
process resize_to_fill: [200, 400]
end
// 省略
end
resize_to_fillやresize_to_fillとはなんぞや!?という方はこちらの記事を参考にしてください。
これにより画像が2種類生成されるようになります。
呼び出し時は区別するために、画像のリンクの末尾に画面サイズを表す2x
を付与します。
retinaのときは
srcset="hogehoge.jpg 2x"
と記述します。
呼び出し時に毎回書くのは面倒なのでhelperメソッドを呼び出すことにします。
def img_2x(url)
"#{url} 2x"
end
呼び出しの記述に移りましょう。
= image_tag(product.image_url(:size_100_200), srcset: img_2x(product.image_url(:size_100_200_for_retina), alt: product.title)
これで自動的にブラウザが判別してくれるようになります。
どちらも呼び出してその分ダウンロードに時間がかかる、ということは起きないです。
ありがたいですね〜〜
ファイル名を指定して呼び出すパターン
あまり考えずに書くと、下のようになりますね。
= image_tag('japan.jpg', srcset: "japan@2x.jpg 2x", alt: 'japan')
先程のパターンだとsrcsetを記述すれば、簡単に実現できそうですが、うまく行きませんでした。
調べた所、この記事が参考になりました。
https://gist.github.com/mrreynolds/4fc71c8d09646567111f
これを先程のimage_helper.rbに追記します。
def img_2x(url)
"#{url} 2x"
end
def image_set_tag(source, srcset = {}, options = {})
srcset = srcset.map { |src, size| "#{path_to_image(src)} #{size}" }.join(', ')
image_tag(source, options.merge(srcset: srcset))
end
呼び出しの記述に移ります。
= image_set_tag('japan.jpg', "japan@2x.jpg" => "2x", alt: 'japan')
これですっきり書けました。
まとめ
retinaが普及して以来、実装側も画像サイズを複数枚用意することも増えました。
ユーザーは美しい画像が表示されるのを当り前のように期待しているので、期待に添うような画像表示ができると良いですね!