sprite-factory icon indicating copy to clipboard operation
sprite-factory copied to clipboard

Add support for Retina sprites

Open mmhd opened this issue 12 years ago • 9 comments

It would be amazing if we could add @2x to icons which are the Retina counterparts of their non-Retina versions. Doing would create a new rule in the same stylesheet but only for @2x versions. Some JavaScript would be needed to handle when the @2x version is used.

mmhd avatar Aug 14 '12 20:08 mmhd

I agree. This would be great. Glue does something similar to what you're describing. http://glue.readthedocs.org/en/latest/ratios.html

joeylomanto avatar Nov 13 '12 21:11 joeylomanto

I'm close to coming up with a solution by using sprite-factory's "Customizing the entire CSS output" method. I'm passing variables into a SASS mixin that then writes most of the necessary css/media query. I'm also using this as a general mixin for use in my stylesheets, so all the variables that'd come from sprite factory are optional and come after the $sprite: false declaration.

The only real issue I'm running into is trying to figure out a way to access the width and height of the final output image (necessary to set the correct background size on retina). I feel like I'm probably overlooking something simple... have tried using :cssw, :cssh. Any suggestions?

The code assumes you're starting with your highest resolution assets; I may try to integrate some sort of image processor after the sprite-factory call to create the second image scaled at 50%.

Again any suggestions on accessing the final output size, or code improvements would be greatly appreciated! And if you're curious I'm using retina.js for images outside the stylesheet.

@mixin retina_url($path, $filetype, $repeat: no-repeat, $rwidth: auto, $rheight: auto, $sprite: false, $sprite-posx: 0, $sprite-posy: 0, $sprite-width: 0, $sprite-height: 0)
  display: inline-block
  background-image: image-url('#{$path}.#{$filetype}')
  background-repeat: $repeat
  width: $rwidth
  height: $rheight
  @if $sprite
    background-position-x: -($sprite-posx / 2)
    background-position-y: -($sprite-posy / 2)
  // RETINA MEDIA QUERY, MAY ALSO NEED -MOZ PREFIX
  @media all and (-webkit-min-device-pixel-ratio : 1.5)
    background-image: image-url('#{$path}@2x.#{$filetype}')
    background-repeat: $repeat
    @if $sprite
      background-position-x: -($sprite-posx)
      background-position-y: -($sprite-posy)
      background-size: ($sprite-width / 2) ($sprite-width / 2)
    @else
      background-size: $rwidth $rheight

Here's my custom css output:

    SpriteFactory.run!('app/assets/images/us_sprite', :nocomments => 'true', :output_style => 'app/assets/stylesheets/sprites/us_sprite.css.sass', :output_image => "app/assets/images/compiled/[email protected]") do |images|
      #Writing SASS, mostly done with mixin retina_url()
      images.map do |image_name, image_data|
      ".#{image_name}\n\t@include retina_url(compiled/us_sprite, png, no-repeat, #{image_data[:width] / 2}px, #{image_data[:height] / 2}px, true, #{images[:cssx]}px, #{images[:cssy]}px)"
      end.join("\n")
    end

matsuodesign avatar Dec 19 '12 22:12 matsuodesign

Awesome! It's great!!!!!!

ANTON072 avatar Jun 01 '13 11:06 ANTON072

Any thoughts on this? I'm surprised this thread has been stale for so long. I would have it would be taken care of, or a reason to not do it would have been discovered

ryana avatar May 02 '14 15:05 ryana

@matsuodesign I'm using https://github.com/ai/rails-sass-images to grab the image width of the 2x sprite.

After that, it's just background-size: (image-width("compiled/[email protected]") / 2) auto.

keithchu avatar May 03 '14 20:05 keithchu

FYI, @matsuodesign's workaround is working for me.

Here's my configuration if it helps. I'm using https://github.com/ai/rails-sass-images to grab the width of the output 2x sprite. Also, the +respond-to($hidpi) is just a helper for targeting @media screen and (-webkit-max-device-pixel-ratio: 1.5), screen and (max-resolution: 1.5dppx).

Ruby:

SpriteFactory.run!('app/assets/images/sprites/2x',
                         :output_style => 'app/assets/stylesheets/_sprites-2x.sass.erb',
                         :output_image => 'app/assets/images/sprites/[email protected]',
                         :selector => '.icon-2x-') do |images|
  images.map do |image_name, image_data|
    ".icon-2x-#{image_name}\n\t@include hidpi-sprite(" +
    "'sprites/[email protected]', " +
    "#{image_data[:cssw]}px, " +
    "#{image_data[:cssh]}px, " +
    "#{image_data[:cssx]}px, " +
    "#{image_data[:cssy]}px)"
  end.join("\n")
end

Sass:

// _icons.sass
=icon($sprite-name: null, $image-name: null)
  +respond-to($hidpi)
    @extend .icon-2x-#{$sprite-name}_#{$image-name}
=hidpi-sprite($path, $width: 0, $height: 0, $x: auto, $y: auto)
  background-image: image-url('#{$path}')
  background-repeat: no-repeat
  background-position: ($x / -2) ($y / -2)
  background-size: (image-width("sprites/[email protected]") / 2) auto
  height: $height / 2
  width: $width / 2

// usage:
.icon-facebook
  &:hover
    +icon("social", "facebook-hover")

keithchu avatar May 03 '14 21:05 keithchu

Hi guys, I understand this thread is 2 years old but it's still open so in case others are searching like me, here is the method I am using that doesn't rely on rails-sass-images. It makes an assumption (seems to be correct) that the generated sprite file won't have extra padding around the sprites.

SpriteFactory.run!('app/assets/images/sprites/2x') do |images|

  # Find the max right-most point of any sprite in the list.
  # This must therefore be the image width.
  image_width  = images.values.map{|data| data[:x] + data[:width]}.max

  # The rest is standard issue, now that we know the background size.
  images.map do |name, data|
    <<-SCSS
      .icon-2x-#{name} {
        width: #{data[:width] / 2}px #{data[:height] / 2}px;
        background: image-url(sprites/[email protected]) #{data[:x] / -2}px #{data[:y] / -2}px no-repeat;
        background-size: #{image_width / 2}px auto;
      }
    SCSS
  end.join("\n")
end

Updated 18th April 2017

sethjeffery avatar Apr 21 '16 13:04 sethjeffery

hello, in the proposed solution I find that data[:w] is nil, both with chunkypng and rmagick. any solution to that?

masterkain avatar Feb 12 '17 23:02 masterkain

@masterkain looks like the data is now data[:width] and data[:height]

@sethjeffery any chance you could update your example block of code with the updated keys from the images hash?

nburwell avatar Apr 14 '17 23:04 nburwell