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 support for Retina sprites #19

Open
mmhd opened this issue Aug 14, 2012 · 9 comments
Open

Add support for Retina sprites #19

mmhd opened this issue Aug 14, 2012 · 9 comments

Comments

@mmhd
Copy link

mmhd commented Aug 14, 2012

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.

@joeylomanto
Copy link

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

@matsuodesign
Copy link

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/us_sprite@2x.png") 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

@ANTON072
Copy link

ANTON072 commented Jun 1, 2013

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

@ryana
Copy link

ryana commented May 2, 2014

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

@keithchu
Copy link

keithchu commented May 3, 2014

@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/us_sprite@2x.png") / 2) auto.

@keithchu
Copy link

keithchu commented May 3, 2014

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/sprites@2x.png',
                         :selector => '.icon-2x-') do |images|
  images.map do |image_name, image_data|
    ".icon-2x-#{image_name}\n\t@include hidpi-sprite(" +
    "'sprites/sprites@2x.png', " +
    "#{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/sprites@2x.png") / 2) auto
  height: $height / 2
  width: $width / 2

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

@sethjeffery
Copy link

sethjeffery commented Apr 21, 2016

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/sprites@2x.png) #{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

@masterkain
Copy link

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

@nburwell
Copy link

@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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants