Rails 7.1 adds picture_tag helper to support HTML5 picture element
HTML5 introduced the
picture tag,
represented as <picture>
which allows developers to provide multiple sources of an image
and
specify different versions of the image for different scenarios,
such
as different screen sizes or resolutions.
The <picture>
HTML element contains zero
or
more <source>
elements
and
one <img>
element.
Each <source>
element specifies a different image source using
the srcset attribute,
which contains the image's URL
and,
optionally the image's width descriptor.
The browser selects the most appropriate image source based on the available options.
Here's an example of how the <picture>
element is typically used:
<picture>
<source srcset="large-image.jpg" media="(min-width: 900px)">
<source srcset="medium-image.jpg" media="(min-width: 600px)">
<source srcset="small-image.jpg">
<img src="fallback-image.jpg" alt="Description of the image">
</picture>
The browser will use the following image sources, depending on the width of the current viewport:
- large-image.jpg for viewport widths of 900 pixels or more
- medium-image.jpg for viewport widths of 600 pixels or more but less than 900 pixels,
- small-image.jpg for viewport widths of less than 600 pixels
If no sources are supported, or if there is an error loading the image, the fallback-image.jpg will be displayed instead.
The HTML <picture>
is a more robust version of the <img>
.
Rails ActionView has an image_tag
helper method that renders the <img>
,
but until Rails 7.1,
the support for picture tag was missing.
Before Rails 7.1,
there were gems like
next_gen_images
and
picture_tag,
that provided the picture_tag
helper method.
With Rails 7.1,
the picture_tag
helper method is included in ActionView.
picture_tag
can be added to the view file like the image_tag
.
<%= picture_tag("profile.webp") %>
The above command will generate the following HTML.
<picture>
<img src="/images/profile.webp" />
</picture>
In this example,
only one parameter was passed to the method,
so the HTML generated includes only the <img>
tag.
You can pass multiple <source>
options to the method to
define multiple sources for the image.
<%= picture_tag(
"profile.webp",
"profile.png",
class: "border-2",
image: { alt: "Profile" }
)
%>
The HTML output generated will include two <source>
tags,
one for profile.webp and another for profile.png.
The browser will choose the profile.webp source
if it supports the WebP format.
If the browser does not support WebP,
it will use the profile.png source instead.
<picture class="border-2">
<source srcset="/images/profile.webp" />
<source srcset="/images/profile.png" />
<img alt="Profile" src="/images/profile.png" />
</picture>
You can also pass a block to the picture_tag. While passing a block, you get complete control of the sources and the image tags. You can specify each source or image tag's size, width, or class.
<%= picture_tag(class: "border-2") do %>
<%= tag(:source, srcset: image_path("profile.webp")) %>
<%= tag(:source, srcset: image_path("profile.png")) %>
<%= image_tag("profile.png", alt: "Profile") %>
<% end %>
The above code will generate the following:
<picture class="border-2">
<source srcset="/images/profile.webp" />
<source srcset="/images/profile.png" />
<img alt="Profile" src="/images/profile.png" />
</picture>
Using the media
attribute,
you can render the pictures based on the width of the screen size.
You must set the media
attribute when specifying the source
.
<%= picture_tag do %>
<%= tag(:source, srcset: image_path("ruby.webp"), media: "(min-width: 1500px)") %>
<%= tag(:source, srcset: image_path("python.png"), media: "(min-width: 750px)") %>
<%= image_tag("go.png", alt: "Language") %>
<% end %>
The above helper method will generate the HTML code as below.
<picture>
<source srcset="/images/ruby.png" media="(min-width: 1500px)" />
<source srcset="/images/python.png" media="(min-width: 750px)" />
<img alt="Language" src="/images/go.png">
</picture>
To know more about the picture_tag
feature,
please refer to this
PR.