jekyll_picture_tag icon indicating copy to clipboard operation
jekyll_picture_tag copied to clipboard

New output format: CSS background image

Open CraigChamberlain opened this issue 3 years ago • 11 comments

The fragment option is good. I've used it to create a background image css style set. I don't really like the string manipulation in the template, I'm concerned about images with spaces in their names (user uploaded). Of course the css could be made smarter and optimised this is just proof of concept.

Do you think something like this would have wide enough appeal to include in the plugin?

{% if include.image and include.image != '' %}             
{% capture imagesrc_set %}{% picture only_srcset "{{ include.image }}" 3:2 --picture class="image is-3by2" %}{% endcapture%}
{% assign imagesrc_set = imagesrc_set | split: ","%}
{% endif %}
<style>
  {% for imgsrc in imagesrc_set %}
    {% assign img = imgsrc | split: ' ' | first %}
    {% assign res = imgsrc | split: ' ' | last | replace: 'w', '' %}
    @media screen and (min-width: {{ res }}px){
      .banner {
        background-image: url({{ img }});
      
      }
    }
  {% endfor %}
</style>

<style>  
    @media screen and (min-width: 400px){
      .banner {
        background-image: url(/website/generated/uploads/banner-bw-lion-400-4a679da67.jpg);
      
      }
    }
    @media screen and (min-width: 600px){
      .banner {
        background-image: url(/website/generated/uploads/banner-bw-lion-600-4a679da67.jpg);
      
      }
    }
    @media screen and (min-width: 800px){
      .banner {
        background-image: url(/website/generated/uploads/banner-bw-lion-800-4a679da67.jpg);
      
      }
    }
    @media screen and (min-width: 1000px){
      .banner {
        background-image: url(/website/generated/uploads/banner-bw-lion-1000-4a679da67.jpg);
      
      }
    }
  
</style>

CraigChamberlain avatar Aug 18 '20 12:08 CraigChamberlain

Hey, sorry for the really long delay on answering this.

We've talked about doing CSS background image before, but I put it off because there's so much variation in possible implementation that the configuration is a challenge. Any ideas on how that could work?

I'm just not sure of the best way to generalize the output.

rbuchberger avatar Jan 04 '21 17:01 rbuchberger

Honestly, I ended up moving to a node solution and then just let netlify sort all my images in the as it proved to be the easiest method with the features I was looking for including smart crop.

I thought maybe another tag you could configure just like your image tags. My example above just deals with one image format so no art direction. I understand there may be extra options of interest such as vertical media queries? Just supporting a single aspect ratio I would have though was straight forward, and very similar to my code quoted above, with the benefit of starting with an array of values not having to de serialise. I can see that adding extra features would make this much harder to rationalise.

CraigChamberlain avatar Jan 04 '21 21:01 CraigChamberlain

I'm seeing the complexity grow as I look at this. You might want to pass the selector into the tag too, for example .banner

CraigChamberlain avatar Jan 04 '21 21:01 CraigChamberlain

The tag might read

{% background-image image-url="example.jpg" ratio="3:2" selector=".banner" wrap-style=true %}

where wrap-style was an optional parameter that could wrap the rules with

On reflection, this might be better served with sass mixins and functions.

This is kind of where I got off ruby and jumped into node and then an image processing service. I was caching gigabytes of only potentially required derivative images for my site and it was really getting really slow and hard on my repo. Kind of flew in the face of the static site simplicity.

Sorry if that's all a bit negative. I do think that jekyll_picture_tag is great. It's actually so good I wanted it to take on more roles and act as a image processing suite. I would now argue that a css tag should really be another plugin, equivalent to the picture tag or a figure tag plugin. Ideally they should all depend on a common core image processor, and a set of processed images. This way, one might swap the image processing between technologies and services relatively easily.

CraigChamberlain avatar Jan 04 '21 22:01 CraigChamberlain

Not negative at all! Use the best tool for the job; I've built a few nuxt/vue sites, and I'd be the first one to tell you that JPT is awesome but it can't do everything. When deployed to netlify and the like it's better for sites with <100 images, or the build times get crazy as you experienced. (I might mention that in the docs.)

I have for a long time wanted to break up JPT into an image handler, a markup generator, and a Jekyll interface, so it's not so tightly integrated with Jekyll. That way I could make a CLI, or make plugins for other Ruby frameworks without rewriting the whole thing. Problem is since I'm not getting paid for any of it, it's tough to justify the time investment.

So yeah, I agree with you that a complete solution to css background images is probably outside the scope of this plugin. A limited feature set to handle some of the more common use cases might be more reasonable; if anyone comes up with a nice clean solution I'll happily merge the pull request.

rbuchberger avatar Jan 05 '21 10:01 rbuchberger

Hi there,

I would really support this, but don't know much about how to implement responsive background images. If you can help me with that, I'm possibly able to make a pull request for that.

What is you solution in the meantime for that?

grauschnabel avatar Dec 29 '21 12:12 grauschnabel

Hi @grauschnabel - thanks for the interest!

There are basically 2 questions that I can't come up with good answers for:

  • How would configuration work?
  • What would the output be?

If we can work out good inputs and outputs, the rest is just plumbing.

My problem with implementing CSS background images is that there are so many implementation details that it's hard to write a general solution which can be generated programatically, without writing tons of configuration. The CSS equivalent of srcset- image-set - is still a working draft and is not well supported. To get JPT's best features you'd basically have to reimplement most of responsive images, except in CSS or with javascript. IMO that's beyond the scope of JPT, barring some elegant solution I haven't thought of yet.

If you want to use JPT to generate CSS background images, you can accomplish it using the direct-url markup format and writing your own CSS.

rbuchberger avatar Dec 29 '21 14:12 rbuchberger

Hi there,

I think I need to read about how this is done, but I prefere a css only way (without js). I like Craig's tag earlier in this thread. It would be possible to create a css section in the page header with an additional tag, if necessary. Maybe we find a solution?

grauschnabel avatar Dec 29 '21 15:12 grauschnabel

We aren't shipping any javascript now, and I ain't about to start. So yeah I agree CSS only is better :)

You can use liquid tags inside CSS files, or throw it in a <style> tag. We can just output CSS and people can decide which they want to do.

rbuchberger avatar Dec 29 '21 20:12 rbuchberger

I did some work here, see PR https://github.com/rbuchberger/jekyll_picture_tag/pull/272.

grauschnabel avatar Dec 29 '21 22:12 grauschnabel

It's now been a few years, and I've also encountered this problem. Fragments can pretty much solve it, and I'd propose modifying only_srcset to have the needed properties for CSS image-set by default. It's pretty easy:

  1. Create _data/picture.yml with this config:
presets:
  direct:
    markup: direct_url
  only_srcset:
    markup: naked_srcset
    base_width: 800
    pixel_ratios: [1, 2]
  1. Provide a fallback for IE etc.: background-image: url('{% picture direct {{ image }} %}'); # maybe the url() should be generated too
  2. Actually use the source set images
background-image: image-set({% picture only_srcset {{ image }} %});
This currently doesn't work as the urls are not wrapped in quotes, you have to fix it with Liquid:
{% capture srcset %}
  {% picture only_srcset {{ image }} %}
{% endcapture %}
{% assign paths = srcset | split: ", " %}
{% capture css_srcset %}
 background-image: {% endif %}url('{% picture direct {{ image }} %}');
  background-image: {% endif %}image-set(
    {% for path in paths %}
      url('{{ path | split: " " | first }}') {{ path | split: " " | last }}{% unless forloop.last %}, {% endunless %}
    {% endfor %}
  );
{% endcapture %}

All the plugin should do is provide the generated URLs via two presets/fragments (I'm not sure what the difference is), this way users can customize it all they want.

Friendly-Banana avatar Feb 21 '24 21:02 Friendly-Banana