Having a random header on reload is a neat feature. I managed to get it to work. Try it… hit reload!. I have included my initial attempt which didn’t work but parts of it made it into the solution.

The initial idea

Loop through header images and construct a list

I have placed all the header images that I would like to randomize in /assets/images/headers/. So I want to loop over all site.static_files and add only the images within that specific folder to my list.

1
2
3
4
5
6
7
8
9
10
<!-- init the list -->
{% assign headers = "" | split: ',' %}

<!-- loop and add -->
{% for image in site.static_files %}
  {% if image.path contains '/assets/images/headers/' %}
    <!-- add image -->
    {% assign headers = headers | push: image.path %}
  {% endif %}
{% endfor %}

We can now have a look at what is stored in the headers array with:

1
{{ headers | inspect }}

which outputs:

["/assets/images/headers/CIG_Group_Photo_2.jpg", "/assets/images/headers/c72dcb0f-8d7a-4956-b49e-5b8461c777a2.jpg", "/assets/images/headers/cig_llnl_sw4_ws.jpg", "/assets/images/headers/e0642ed4-7bb9-41e3-ae9e-52a8d75ea044.jpg", "/assets/images/headers/img_0144.jpg", "/assets/images/headers/img_0319.jpg", "/assets/images/headers/img_0376.jpg", "/assets/images/headers/img_0551.jpg", "/assets/images/headers/img_1540.jpg", "/assets/images/headers/img_1912-pano.jpg", "/assets/images/headers/img_1912.jpg", "/assets/images/headers/img_2407.jpg", "/assets/images/headers/img_2423.jpg", "/assets/images/headers/img_2426-animation.gif", "/assets/images/headers/img_2427.jpg", "/assets/images/headers/img_2428.jpg", "/assets/images/headers/img_2553.jpg", "/assets/images/headers/img_2583.jpg", "/assets/images/headers/img_3022.jpg", "/assets/images/headers/img_3139.jpg", "/assets/images/headers/img_3187.jpg", "/assets/images/headers/img_3217.jpg", "/assets/images/headers/img_3619.jpg", "/assets/images/headers/img_3672.jpg", "/assets/images/headers/img_4365.jpg", "/assets/images/headers/img_4637.jpg", "/assets/images/headers/img_4829.jpg", "/assets/images/headers/img_5227.jpg", "/assets/images/headers/img_5275.jpg", "/assets/images/headers/img_5296.jpg", "/assets/images/headers/img_5297.jpg", "/assets/images/headers/img_5306.jpg", "/assets/images/headers/img_5325.jpg", "/assets/images/headers/img_5875.jpg", "/assets/images/headers/img_5896.jpg", "/assets/images/headers/img_5903.jpg", "/assets/images/headers/img_6016.jpg", "/assets/images/headers/phd_overview.png", "/assets/images/headers/wadi_rum_pan.jpg"]

Pick a random header

Using the sample filter we get a random item from the headers array.

1
2
{% assign random-header = headers | sample %}
{{ random-header | inspect }}

"/assets/images/headers/img_5275.jpg"

The problem is that because Jekyll is a static site generator, this happens when the static page is built and not on reload. So we need to encapsulate this in a JavaScript that is executed every time a page is served.

The solution

I found this very helpfull post by James W Thorne that mixes Liquid code and JavaScript code. This may not be the most elegant solution but id works.

default.html layout

I added the following JavaScript/Liquid mix to the <head> section of the default.html layout:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<!-- Load jQuery -->
<script src="/assets/js/vendor/jquery/jquery-3.3.1.min.js" type="text/javascript"></script>

{% if page.header.image == 'random' or page.header.overlay_image == 'random' %}
  <!-- Make a list of header images -->
  <!-- init the list -->
  {% assign header_images = "" | split: ',' %}

  <!-- loop and add -->
  {% for image in site.static_files %}
    {% if image.path contains '/assets/images/headers/' %}
      <!-- add image -->
      {% assign header_images = header_images | push: image.path %}
    {% endif %}
  {% endfor %}

  <!--
    Javascript and Liquid code to gather a list of all header images
    in /assets/images/headers/
  -->
  <script type="text/javascript">
    // get images from ``header_images`` array to js var
    var header_images = [
      {% for image in header_images %}
        "{{ site.baseurl }}{{ image }}",
      {% endfor %}
    ];

    var randomIndex = Math.floor(Math.random() * header_images.length);

    // and the winning ``header_image`` is...
    var header_image = header_images[randomIndex]

    // image without overlay
    {% if page.header.image == 'random' %}
      $(document).ready(function() {
        $(".page__hero-image").attr('src', header_image);
      });

    // image with overlay
    {% elsif page.header.overlay_image == 'random' %}
      // make sure overlay filter is handled correctly
      {% if page.header.overlay_filter contains "rgba" %}
        {% capture overlay_filter %}{{ page.header.overlay_filter }}{% endcapture %}
      {% elsif page.header.overlay_filter %}
        {% capture overlay_filter %}rgba(0, 0, 0, {{ page.header.overlay_filter }}){% endcapture %}
      {% endif %}

      $(document).ready(function() {
        $(".page__hero--overlay").attr('style',
          '{% if page.header.overlay_color %}
            background-color: {{ page.header.overlay_color | default:
                "transparent" }};
          {% endif %}
          background-image: {% if overlay_filter %}
            linear-gradient({{ overlay_filter }}, {{ overlay_filter }}),
          {% endif %}url(' + header_image + ')');
      });

    {% endif %}
  </script>
{% endif %}

Line 2 loads the jQuery library that allows setting the src attribute of the .page__hero-image class in the case of image: or the style attribute of the .page__hero--overlay class in the case of overlay_image:.

On build, line 4 makes sure nothing happens unless randomization is needed. If not, lines 5 through 62 will completely vanish from the page source.

Lines 7 through 15 compile a list of images in /assets/images/headers/ and assigns that list to a header_images array variable. This is outside the JavaScrip code so it is run only when the page is built, not every time it is served.

The contents of the square brackets between lines 23 and 27 must be one line. Similarly, Lines 50 through 57 must be one line. *Lines here are broken for readability.

YAML front matter

Every other layout is initially dependent on the default layout so header image or overlay_image can be randomized in all layouts. Simply set image: random or overlay_image: random in the front matter and you are set.

Here is an example of a page with a random header image (unlike this post which has a random header overlay_image). If you were wondering what the front matter for this post looks like, here it is:

1
2
3
4
5
6
7
8
9
10
11
12
---
title: Randomizing header image
header:
  overlay_image: random
  overlay_filter: rgba(255, 255, 255, 0.3)
  caption: "Image subject to Copyright: [**© Shahar Shani-Kadmiel**](https://shaharkadmiel.github.io)"
tags: [Random stuff, Images, Jekyll, Liquid, JavaScript, jQuery, Hacking]
toc: true
toc_label: "Contents"
author_profile: true
published: true
---

Leave a Comment