Christian Heilmann

You are currently browsing the Christian Heilmann blog archives for February, 2021.

Archive for February, 2021

Scratching my own itch: a JavaScript slide show for full screen looping GIFs and MP4s

Thursday, February 25th, 2021

Lately I thought it would be good to convert a lot of the GIFs I have to MP4 to save space on some of memory sticks. The problem that I found with that is that Quicklook on Mac doesn’t loop MP4s when you view them, which is annoying.

Slide show showing a picture of a dog with a lot of tennis balls.

So I scratched my own itch and wrote a quick, plain vanilla JavaScript slide show and you can see it in action on GitHub.

Features include:

  • Displays any video or image in a folder in the largest possible size without cropping
  • Mouse or keyboard navigation (Arrow Left and right for back and forward, Space to toggle automatic advancing)
  • Slide show option showing a new image every x seconds.
  • Slide show waits for images to load and videos to be playable before advancing
  • Stores the current position of the slide show. Next time you load the document it commences where it stopped last time.

Usage and customisation

You can use the slideshow by giving it a container to create all the elements in, define the different settings of the slideshow object:

  • container: a DOM reference to the HTML element the slide show should be added in
  • media: an Array of images and videos to display
  • folder: the folder containing these – this should be a child folder of one the slide show is in.
  • autoplay: yes or no indicating if the slide show should start or not
  • speed: time in milliseconds to advance to the next media item (f.e. 1000 for a second)

The code to use in your HTML is:

<div id="slideshow-container"></div>
<script>
  let slideshow = {
    container: '#slideshow-container',
    media: [
    'ball.mp4','dinowalk.mp4','dirty.mp4',
    'goldiejump.mp4','step.mp4','tippy.mp4','wag.mp4'
    ],
    folder: 'imgs/',
    autoplay: 'yes'
  }
</script>
<script src="slideshow.js"></script>

Automating the media collection

Currently I am using this on my hard drive running a local server and the index.php script. If you are using a Mac, PHP comes with the system. Go to the terminal, navigate to the folder where the slide show is and run:

$ php -S localhost:8000

Then you can navigate in you browser to localhost:8000 and the rest happens automatically.

The index.php script lists all the current folders in the directory the script is in and gives you list of all of them. Clicking the link of the name starts the slide show with the current folder. Feel free to check the script, but there isn’t much magic there.

The index.php is part of the GitHub repo, so cloning or downloading the zip will get you started.

A code snippet to scrape all headings and their target URLs from a markdown generated page

Friday, February 19th, 2021

When you use Markdown to write your documentation most static page generators will generate IDs for each of the headings in the document to allow you to navigate directly to them. (more…)

Using position: sticky to create persistent headers in long texts

Tuesday, February 9th, 2021

Macbook covered in sticky notes

The sticky value of CSS positioning is an underused gem. It treats an element as it if is positioned relative until it reaches a certain position on the screen and then turns it into a fixed position.

I’ve used this on the developer advocacy handbook to keep headers in sight above the current section until you scroll to the next one. You can see it in action in the following screencast:

The CSS responsible is this:

h1, h2, h3, h4 {
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  letter-spacing: -1px;
  position: sticky;
  top:0;
  background: var(--background);
  padding: .5em 0;
}

This means that any heading that reaches the top of the screen when you scroll will stick there (position: sticky and top:0). Giving the heading the same background colour as the main document and adding some padding makes sure that the rest of the text isn’t visible behind the fixed heading.

There are quite a few JavaScript solutions for this, but as you can see these are not needed.

Sticky had a problem that it wasn’t supported by Safari for a while, but as with everything that is “impossible to use”, this was only temporary. The web keeps moving, it is fun to catch up with it.

Sharing data between CSS and JavaScript using custom properties

Monday, February 8th, 2021

One of the big battles we see in the web development world is still CSS vs. JavaScript. Both have their merits, their own syntax and ideas and it can be tough to get your head around them.

This is why I love that we have ways to make the two communicate and use each for what it is best at. For one thing, I always found it annoying to manipulate the styles object of a DOM element. It meant accessing the element and setting the various style properties. In the end, it resulted in an inline style attribute you’d never write by hand.

A much cleaner way to me is to use CSS custom properties. These are commonly called “CSS variables” and you define them in CSS using the—syntax.

:root {
  --pagebackground: powderblue;
}
body {
  background: var(--pagebackground);
}

Being “variables”, you can re-use them throughout your styles document.

The fun begins when you use JavaScript to manipulate them. In the case of this example, the CSS custom property is set on the root element of the document. So you can read it with JavaScript using the following.

let bg = getComputedStyle(document.documentElement).
  getPropertyValue('--pagebackground');

And you can set it with JavaScript by accessing the style of the root element (or any other element with custom properties) and setting a property.

document.documentElement.style.setProperty('--pagebackground', 'firebrick');

You can try this live on codepen:


See the Pen
Testing CSS Custom properties interaction
by Christian Heilmann (@codepo8)
on CodePen.


The great thing about that is that you can use the power of JavaScript to give CSS things it can’t access. For example, CSS can’t read the coordinate of the mouse cursor, but JavaScript can.

In our CSS, we can define two properties as 0:

:root {
  --mouse-x: 0;
  --mouse-y: 0;
}

And in JavaScript, we add a mousemove handler to the document and manipulate these two properties:

let root =  document.documentElement
document.addEventListener('mousemove', e => {
  root.style.setProperty('--mouse-x', e.x);
  root.style.setProperty('--mouse-y', e.y);
});

And that’s all the JavaScript we need. As CSS custom properties are live and change their value, we can now, for example, show a circle where he mouse cursor is in CSS using the following.

Our HTML:

<div id="ball"></div>

The CSS:

:root {
  --mouse-x: 0;
  --mouse-y: 0;
}
#ball {
 width: 20px;
 height: 20px;
 background: white;
 border-radius: 100%; 
 transform: translate(
 calc(calc(var(--mouse-x) - 10) * 1px), 
 calc(calc(var(--mouse-y) - 10) * 1px)
 );
}

Some information on the CSS here:

  • We set the width and height of the ball DIV to 20 pixels and the background to white.
  • Adding a border-radius of 100% makes sure we get a circle and not a square.
  • We then use transform: translate to position the circle on the screen. This could be something like transform:translate(200px, 300px) to position our ball at 200 pixels horizontal and 300 pixels vertical.
  • As JavaScript sets the CSS custom property to a numeric value, we need to convert it to pixels by multiplying it with “1px”.
  • And as the ball is 20 pixels big, we can’t just place it at—mouse-x and—mouse-y but we need to subtract 10 from it to centre it on the cursor.

This trick allows us to do complex calculations, read out browser state and interaction state in JavaScript and still keep all the look and feel in CSS. To me, that’s a win.

If you want to see it in action, you can try this codepen. I also added a background effect to show how you can re-use the mouse x and y data:


See the Pen
Mouse position as custom CSS property
by Christian Heilmann (@codepo8)
on CodePen.