Noémien Kocher
Noémien Kocher

Reputation: 1364

Display right image according to screen size

It's maybe an easy question but after some research I didn't find any valid solution.

I use carrierwave to generate multiple versions of an uploaded image. Each image has a specific size for different screen sizes. For example (in my uploader) I have

version :xl 

for screens larger than 1200px.

How can I use rails to display specific image according to client screen size ?

I know there is gem responsive-images but I can't use size.
The subject of responsive images is for the moment quite vast and nobody seems to have the same answer, especially with javascript and html5. How about rails (even if it's server side) ?

Upvotes: 2

Views: 3057

Answers (2)

Noémien Kocher
Noémien Kocher

Reputation: 1364

Well, I really wanted to do it in a more rails way. I ended up using ajax :

Fire ajax at load page :

# assets/javascript/cards/index.js
// fire loading image
$.ajax({
  url: document.URL,
  data: {
    w: window.innerWidth
  }
});

In controller, respond to ajax :

# controllers/cards_controller.rb
render 'cards/images/loadimage' if request.xhr?

Then load your images

# cards/images/loadimage.js.erb
<% w = params[:w].to_i %>
document.getElementById('banner-container').innerHTML = "<%= j image_tag @card.banner_type_url(w), class: 'banner' %>";
document.getElementById('logo-container').innerHTML = "<%= j image_tag @card.logo_type(w), class: 'logo' %>";

I made in my model a method to return right image given screen width (and based on carrierwave version) :

 # models/card.rb
 # returns banner type based on width (w)
 def banner_type_url(w)
   return self.banner.s.url || banner_default('s') if(w <= 768) 
   return self.banner.m.url || banner_default('m') if(w <= 992) 
   return self.banner.l.url || banner_default('l') if(w <= 1200) 
   return self.banner.xl.url || banner_default('xl') if(w <= 1920) 
   return self.banner.full.url || banner_default('full')    
 end
 def banner_default(s)
   "card/banner/#{s}_default-banner.jpg"
 end

Upvotes: 1

steel
steel

Reputation: 12580

Here are a couple of ways:

  1. Load the page with all the paths to various image sizes stored as data attributes, grab the screen width with js, then stick an image tag with the correct path where you want it. Code might look like (not tested, and I've been using coffeescript, so probably missing details):

    # ruby command line
    $ @image.mobile_asset_url
    => "path/to/mobile/image"
    $ @image.desktop_asset_url
    => "path/to/desktop/image"
    
    
    # html.erb
    <img src="" class="placeholder" data-mobile-url=<%[email protected]_asset_url%> data-desktop-url=<%[email protected]_asset_url%>></div>
    
    # javascript
    el = $('.placeholder')
    data = el.data();
    width = $(window).width();
    mobile_breakpoint = 480;
    
    if (width <= mobile_breakpoint) {
      url = data.mobileUrl;
    } else {
      url = data.desktopUrl;
    }
    
    el.attr('src', url)
    
  2. Do a server side test not for screen width, but browser type with a gem like browser, and load smaller images for mobile specific browsers like iOS8. Logic like this might go best in a decorator. I'm more fluent with Ruby, so an example might look like (this code not tested):

    # user_decorator.rb, from the Draper gem
    class UserDecorator
    
      def profile_url
        if mobile_browser?
           "path/to/small/image"
        else
           "path/to/large/image"
        end
      end
    
      private
    
      def mobile_browser?
        browser.ios || browser.android || ...
      end
    
    end
    

Upvotes: 5

Related Questions