Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a picture_tag helper #48100

Merged
merged 1 commit into from
May 12, 2023
Merged

Conversation

jpbalarini
Copy link
Contributor

@jpbalarini jpbalarini commented Apr 30, 2023

Motivation / Background

We wanted to use the HTML <picture> tag in our website for responsive images (specifically, for art direction) and found that Rails did not have built-in support for it. By introducing the picture_tag helper, we can simplify the usage of the <picture> element in Rails applications, enabling developers to incorporate responsive images in their projects easily.

The need for a picture_tag in Rails led to the creation of this gem and this RailsConf talk. After presenting the talk, a lot of people told me I should add this feature to Rails, so I'm porting some of the gem's functionality here.

The picture tag is a more "robust" version of the img tag, because it supports resolution switching, art direction, and image support fallback, so I think we should have it in Rails (the img tag only supports resolution switching). More information here:

Detail

This PR adds support for the HTML picture tag. It supports passing one element (String), multiple (an Array), or a Block if you need full control of what it's being generated. All properties that are passed to the helper will apply to the picture tag. If you need to pass properties to the img tag, you can do it inside the :image key.

Since the picture tag requires an img tag (contrary to the audio_tag or video_tag, which only require sources), the last element you provide will be used as the source for the img tag. For complete control over the picture tag, a block can be passed, which will populate the contents of the tag accordingly.

It can be used like this for a single source:

<%= picture_tag("picture.webp") %>

which will generate the following:

<picture>
    <img src="/images/picture.webp" />
</picture>

For multiple sources:

<%= picture_tag("picture.webp", "picture.png", :class => "mt-2",  :image => { alt: "Image", class: "responsive-img" }) %>

will generate:

<picture class="mt-2">
    <source srcset="/images/picture.webp" />
    <source srcset="/images/picture.png" />
    <img alt="Image" class="responsive-img" src="/images/picture.png" />
</picture>

Full control via a block:

<%= picture_tag(:class => "my-class") do %>
    <%= tag(:source, :srcset => image_path("picture.webp")) %>
    <%= tag(:source, :srcset => image_path("picture.png")) %>
    <%= image_tag("picture.png", :alt => "Image") %>
<% end %>

will generate:

<picture class="my-class">
    <source srcset="/images/picture.webp" />
    <source srcset="/images/picture.png" />
    <img alt="Image" src="/images/picture.png" />
</picture>

Additional information

Another option would be to be more explicit on the image and sources that are generated (could be more cumbersome).
Something like this:

picture_tag("image.jpg", sources: [{ srcset: "image_small.jpg", media: "(min-width: 400px)" }, { srcset: "image_big.jpg" }], alt: "An example image", class: "responsive-image")

The issue with this is that we would need a way to specify which properties belong to the img tag and which to the picture tag itself. I did not go with this approach since I tried to more or less replicate how the audio_tag, video_tag, and image_tag helpers work.

Checklist

Before submitting the PR make sure the following are checked:

  • This Pull Request is related to one change. Changes that are unrelated should be opened in separate PRs.
  • Commit message has a detailed description of what changed and why. If this PR fixes a related issue include it in the commit message. Ex: [Fix #issue-number]
  • Tests are added or updated if you fix a bug or add a feature.
  • CHANGELOG files are updated for the changed libraries if there is a behavior change or additional feature. Minor bug fixes and documentation changes should not be included.

@rails-bot rails-bot bot added the actionview label Apr 30, 2023
@jpbalarini jpbalarini force-pushed the add-picture-tag-helper branch from a7be564 to fac9218 Compare April 30, 2023 17:44
# picture_tag(user.profile_picture)
# # => <picture><img src="/rails/active_storage/blobs/.../profile_picture.webp" /></picture>
def picture_tag(*sources, &block)
sources.flatten!
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wondering why it is necessary to flatten! here.

@guilleiguaran guilleiguaran merged commit a3adc6c into rails:main May 12, 2023
mattbrictson added a commit to mattbrictson/vite_ruby that referenced this pull request Oct 5, 2023
Rails 7.1 introduced a `picture_tag` helper.[^1] This commit adds a
corresponding `vite_picture_tag` helper that handles resolving assets
via Vite, but otherwise behaves the same as `picture_tag`. It is only
exposed for Rails >= 7.1.0.

[^1]: rails/rails#48100
mattbrictson added a commit to mattbrictson/vite_ruby that referenced this pull request Oct 5, 2023
Rails 7.1 introduced a `picture_tag` helper.[^1] This commit adds a
corresponding `vite_picture_tag` helper that handles resolving assets
via Vite, but otherwise behaves the same as `picture_tag`. It is only
exposed for Rails >= 7.1.0.

[^1]: rails/rails#48100
mattbrictson added a commit to mattbrictson/vite_ruby that referenced this pull request Oct 5, 2023
Rails 7.1 introduced a `picture_tag` helper.[^1] This commit adds a
corresponding `vite_picture_tag` helper that handles resolving assets
via Vite, but otherwise behaves the same as `picture_tag`. It is only
exposed for Rails >= 7.1.0.

[^1]: rails/rails#48100
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants