Today I Learned HTML, CSS, JavaScript & PHP Fri, 25 Sep 2020 23:32:00 +0000 en-US hourly 1 Restricting Access to Content in WP Fri, 25 Sep 2020 23:31:57 +0000 Read moreRestricting Access to Content in WP

A few notes on how to restrict access to content in WordPress, both for anonymous visitors and logged-in visitors with a specific user role, by using wp_safe_redirect().


When you want to hide some of your content, for example posts in a certain category, a page, a particular Custom Post Type, you can use the wp_safe_redirect() function. This does not allow for showing a teaser on the page, since visitors will never see the page, and I don’t think the following is a good solution for a full-fledged membership site.

This solution might be good though for a temporary lockdown of a site, or very simple membership sites.


Basically, it’s this: check which page is being called, check if the user is logged in, redirect if necessary.

add_action( 'template_redirect', 'bw_restrict_content');
function bw_restrict_content(){
	if( ( is_singular( array( 'my-cpt-1', 'my-cpt-2' ) ) || is_page('my-page') ) && !is_user_logged_in() ) {
		wp_safe_redirect( home_url() );

I’m redirecting within the site, so I’m using wp_safe_redirect() instead of wp_redirect(), but choose the later if you want to redirect to a different site altogether. And I’m redirecting them to home in this case, because the site I’m using this on does not have an open registration, but you can redirect to any old URL.

The nocache_header() function is called, as kZeni mentions on the WP reference page for this function, so that the redirect isn’t cached and users will actually see the restricted content once they log in, instead of still being automatically redirected.

You can use this with any number of conditional tags, such as is_category(), is_feed() and I’ve used it with is_author() and is_search() for example.

If you want to check for a specific user role, you can check for capabilities. For example, want to hide posts with the category “premium” from not-logged-in visitors and logged-in subscribers?

add_action( 'template_redirect', 'bw_hide_premium' );
function bw_hide_premium(){
    if( (!is_user_logged_in() || !current_user_can( 'edit_posts' ) ) && ( is_category( 'premium' ) || in_category( 'premium' ) ) ){
        wp_safe_redirect( home_url() );

Snippets like this should not be the functions.php file, in my opinion, because they remain true, regardless of the theme I’m using. A site-specific plugin would make more sense, but I usually end up tweaking snippets like this regularly, so I like something a bit more accessible: the Code Snippets plugin.

I am also using a plugin to control which items are visible in the site navigation: User Menus. Once you’ve activated it, all necessary options can be found in the standard WordPress menus and menu items.

For any posts, pages, CPT that should only be visible to Administrators en Editors, I just set them to Private. If it’s something I want to add to site navigation (usually a page), I will publish first, then add to a menu, then set to Private, and then I hide the menu item from everyone with the User Menus plugin settings.


An answer on WordPress StackExchange by bynicolas.


I used to use a plugin for this: Restrict User Access. I still might on occasion, I like it, it does enough and not too much. But on my last project, just turning the plugin on removed the CPT from the author archive pages and, well, it was too much hassle to fix that.

I tried another plugin that showed promise: Control Content. Sadly, it didn’t work at all, though it seemed sympathetically lightweight and unobtrusive. One of the nice options it has is that you can very easily hide widgets as well, something Restrict User Access lacks, and which was the one thing that actually worked for me. Control Content also led me to the User Menus plugin, since it’s from the same plugin authors, but this one actually works and is really easy to use. Beautiful plugin.

]]> 0
WP Media Library Front-end Gallery Wed, 02 Sep 2020 01:14:44 +0000 Read moreWP Media Library Front-end Gallery

Using a WordPress loop to pull images directly from the WordPress Media Library and displaying them with a shortcode.

A crucial part of filtering the images you want to show from the rest of what is in your media library is done by attaching a taxonomy to the media library items. This has the added benefit of creating the foundation needed to allow for filtering of the gallery on the front end as well.

Filterable Gallery that pulls images straight from the media library

Everything in the Media Library WordPress considers an attachment and for the sake of taxonomies and the loop, attachments are simply a post type. A post type with some peculiarities but a post type nonetheless.

I like using CPT UI for creating taxonomies and once you do, they have nice little checkboxes next to all the post types you can associate your taxonomy with and “Media” is one of them. So this part is easy. Of course, if you prefer to add a taxonomy a different way, go for it.

The next step is to assign a term from your new taxonomy to any of the images in your library you want to show in the gallery. If an image has no term assigned it won’t show up. If it has a term assigned from another taxonomy, it also won’t show up.

Your images are ready, now the rest. I made a shortcode that is ready to use. You just have to stick all the code that is in that file somewhere in your install. You can add it to the functions.php file if you’re using a child theme, or you can install a plugin like Code Snippets and stick it in a snippet. Either way you can then use the shortcode in a page or post for example.

But if you want to make your own loop, here are the basics of what I did.

Get all the terms from the taxonomy that’s assigned to Media.

$oAllTerms = get_terms( array( 'taxonomy' => 'your_media_tax' ) );

get_terms() by default only returns the terms that aren’t empty which is exactly what I want. This now allows me to do two things 1) set up a button group with a button for each term, which will allow for filtering of the gallery 2) set up a query to get all the images I want from the media library.

1) Filtering buttons

<?php $aTermIds = array(); ?>
<div class="button-group gallery-filter">
    <button class="filter button active" value="fgimage">All</button>

<?php foreach( $oAllTerms as $oAterm ){ ?>
    <button class="filter button" value="<?php echo $oAterm->slug; ?>">
        <?php echo $oAterm->name; ?>
    <?php $aTermIds[] = $oAterm->term_id;
} ?>

2) Setting up a query

The array $aTermIds is in preparation for the query that’s following now, because if I only specify the taxonomy and not the terms I want attachments from, there will be no attachments to show at all. So while I’m looping through all the terms with attachments anyway, I might as well put all of the term IDs in an array for use later.

//WP_Query Arguments
$args = array(
    'post_status' => 'any',
    'post_type'   => 'attachment',
    'post_mime_type' => 'image',
    'posts_per_page' => -1,
    'tax_query' => array(
	    'taxonomy' => 'your_media_tax',
	    'terms' => $aTermIds

//The Query
$bw_query = new WP_Query( $args );

Three things I want to comment on in the above:

  1. Attachments do not get a post status of ‘published’ (which is the default in WP_Query), their post status is ‘inherit’. You can use either ‘inherit’ or ‘any’.
  2. Since you have a lot of control over what is being pulled out of your media library, adding the post mime type is perhaps unnecessary, but I like being cautious. Of course, if you’re doing your own thing with it, you might not want to limit the loop to that mime type, or you might want to narrow it even more and specify what type of images, image/jpg for example.
  3. Setting posts per page to -1 means that all your images with a taxonomy term assigned will be shown; be careful to not have that be too many images…

Displaying the images

<?php //The Loop
if( $bw_query->have_posts() ){ ?>

    <ul class="filterable-gallery">

    <?php while( $bw_query->have_posts() ){

	$oPostTerms = get_the_terms( null, 'your_media_tax' );
	$aTermlist = array();
	foreach( $oPostTerms as $oPostTerm ){
	    $aTermlist[] = $oPostTerm ->slug;
	$sTermlist = implode( " ", $aTermlist); ?>

	    <li class="fgimage <?php echo $sTermlist; ?>">
	        <?php echo wp_get_attachment_link( null, 'medium', false ); ?>
    } ?>


} else { ?>

    <p>There are no images to show.</p><?php


//Restore original Post Data

Even though we’re treating the attachments as posts in a way, the_content() won’t output anything. If we want the image we still have to use wp_get_attachment_link(). Since we’re in the loop, we don’t need to set the post id and null will work fine for that. I’m using the medium size, but any of the public names available for any of the image sizes in your WP install will work as will an array of width and height values in pixels (in that order).

get_the_terms() in the code above is used to convert the terms attached to the image to a list of classes used in the li that wraps around the image, also needed to allow for filtering.

Making the filtering work

I’m using a bit of jQuery, but you do you.

<script id="filterable-gallery-js">
		jQuery(".filter.button").on('click', function(){
			var btnValue = jQuery(this).prop("value");
			jQuery(".filterable-gallery").fadeTo("fast", 0.01);
			jQuery(".fgimage").not("." + btnValue).fadeOut();
				jQuery("." + btnValue).fadeIn();
				jQuery(".filterable-gallery").fadeTo("fast", 1);
			}, 400);

First we fade the whole gallery almost to invisible, then we fade everything out that doesn’t have the right term / class, which means that all those images get a display: none. Since that makes all of the items in the gallery jump around, I wait a beat before first fading in the images with the correct term / class and then I fade the whole gallery back to full opacity.
And last but not least, I give the active button a class of “active”, so I can target it with some CSS and make it visually stand out.

That’s it. How you style your gallery is up to you. If you have any comments or questions, let me know!

]]> 0
WP version 5.5 Fri, 14 Aug 2020 19:52:40 +0000 Read moreWP version 5.5

This update has a few changes that make me happy!

What: First and foremost: a simple way to filter archive titles. Yay! Hooray! Tired of

Category: Books


Archive: Products

You can change that Category: or Archive:, or any other archive title prefix, to anything you want or remove it altogether.


If you want to remove the prefix altogether:

add_filter( 'get_the_archive_title_prefix', '__return_empty_string' );

That’s enough, that’s all you have to add to functions.php in your theme, or in a plugin, or for example in the Code Snippets plugin.

If you would prefer to replace the prefix with a custom one, instead of using __return_empty_string, pass the filter a function. For example:

function your_archive_title_prefix( $prefix ){
    $prefix = __( 'All my favorite ', 'your-text-domain' );
add_filter( 'get_the_archive_title_prefix', 'your_archive_title_prefix' );

Where: WP 5.5 Field Guide, specifically this post: Filtering Archive Page Headings in WordPress 5.5

Thoughts: This is not the only change I’m happy with, but the one I’ve been longing for the longest.

Another one I’m happy with is the improvements to WordPress image editing. I always warned people against using this because it made display of an image unreliable, or maybe it’s better to say too reliable: it would only display in the way you’d edited it in WordPress. Which might work in one context but not in every context.

Now you can edit directly in the block editor, with more intuitive tools, and it will create a new version of your image, so you can still use the old one elsewhere. What I’m not yet sure of: how well the changes you make to an image will work across devices. We’ll find out by and by.

Read more about Editing Images in the Block Editor.

I think it’s wonderful news that you can now pass arguments to template files and that lazy loading images is part of WordPress.

Wonderful new release, very happy with it. Read the rest of the changes in the WordPress 5.5 Field Guide.

Image credit: WordPress Logo with tacky boke effect by me
]]> 0
Removing Spaces from Filenames on Windows Wed, 17 Jun 2020 19:40:17 +0000 Read moreRemoving Spaces from Filenames on Windows

I received 60 documents to put online, beautifully named, but with SPACES!!! Aaaah!

Thankfully, you can bulk remove them in a powershell: hooray! This simple, understandable and beautiful solution on Stack Overflow shows you how:

  • Open the command prompt, by searching for CMD
  • Open a powershell by typing in powershell
  • cd to the folder the files are in
  • and try this command
    get-childitem *.pdf | foreach {rename-item $_ $" ","")}
    replace pdf with whatever the relevant extension is

That’s it, works beautifully!

Photo credit: de moi, 2020.
]]> 0
Database Storage Engine Tue, 16 Jun 2020 01:01:00 +0000 Read moreDatabase Storage Engine

I have run into more than one database that has both MyISAM and InnoDB tables and I’m very happy to know that I can change all of them into InnoDB–providing it’s at least MySQL 5.6.4.

This little, practical article from Kinsta tells how and has more detail, but basically, you can just change it from a dropdown once you’re in phpMyAdmin, or you can use:

ALTER TABLE wp_comments ENGINE=InnoDB;

using wp_comments as an example.

This will help me streamline some old DBs! \o/

If you want to read more about databases and WordPress, Delicious Brains has a nice article about it, which is also where I got the link to the Kinsta one.

Photo credit: de moi, 2020
]]> 0
Free Software for Animation Sat, 06 Jun 2020 19:36:13 +0000 Read moreFree Software for Animation

Once a year I teach Animation & Interaction at MKstart in Amsterdam. When I started teaching this class over 10 years ago, I used Flash. I’d make some very tiny animations with them during the first few classes and then some mini games during the last few classes. I loved it, they loved it, it was great. When Flash died, eventually I switched to Animate. The brush tool is still the same, the regular crashes are the same, but working in Canvas has made Animate more buggy and unreliable. I haven’t found any good alternatives so I use it anyway.

The students are not expected to have the software themselves. They use the school laptops during class. This year, because Corona, I was in New York, my students were at home–without school laptops…

The students do not have a lot of money, they do not have very fancy computers and the school doesn’t have enough money to fix those problems. The first thing I decided was to focus on one of the two subjects. The second thing was that it would be animation.

I made a website for them where they would be able to find all the classes online with examples and were they could upload what they’d made if they wanted to. I also added a list of free software that might come in handy and instead of just copying and pasting from everyone else’s lists of free software, I tried all of them to see if they would work for my class.

What did I look for?

  • suitable for 2D drawing / animation
  • options for people who can’t install any software on their machine
  • software for turning a series of photos into a movie
  • software that doesn’t rely on a webcam
  • flipbook software
  • software with timelines
  • drawing software
  • image manipulation software
  • easy and intuitive to use because if they’re all using different software, I won’t have time to explain it all

The list

Animation – online

  • Make a video from pictures, StopMotion: Kapwing
  • Very simple animation software: Brush Ninja
  • Make a digital flipbook, also very simple: FlipAnim
  • Make a pixel animation with Piskel
  • Converting a series of PNGs is also possible at
  • You can also convert a series of pictures to an animated GIF, for example with EZGIF
  • At EZGIF you can also make a APNG (Animated PNG), which sometimes leads to a more lightweight file with good or better quality than a GIF: worth a try
  • Another service that converts pictures to a GIF: Make a GIF

Image editing online

  • Doka.Photo | Free Online Image Editor | Powered by Doka.js – A free photo editor, nice to use
  • Another online photo editing app: Fotor
  • Online vector / drawing app: Gravit Designer (not just for designing apps or websites!) works in most browsers but you can download it as well
  • Online vector / drawing app Vectr is a little simpler than Gravit but also good. Can be used in the browser but I think it can be downloaded as well.
  • Online vector / drawing app Boxy SVG works in Chrome and Chrome-based browsers (Opera, Vivaldi, Brave, new Edge).
  • Online vector / drawing app Method Vector Editor
  • Photopea is a Photoshop clone online
  • The free version of Pixlr E has some limitations but a lot of options as well and it’s really nice to use

Animation and image editing online

  • Krita is wonderful software for drawing and animation, it has vector options and very good brushes
  • Inkscape is vector drawing software
  • Gimp is photo editing software in which you can also draw and make some very simple animations
  • Pencil2D Animation is 2D animation software
  • Synfig is also 2D animation software
  • Blender is very extensive animation software (though 3D, just to good not to mention)
  • OpenToonz is also 2D animation software
  • MorevnaProject OpenToonz is a different version of the same software as OpenToonz

Those are my lists. One of my students really liked using Krita although he didn’t use the timeline, he would just string the separate drawings together in the video software that came with his computer.

At least two student drew the frames by hand, took photos of their drawings with their phones and made them into a movie using Kapwing or free video editing software. Some of them used FlipAnim some used Pixlr.

Some students had crappy computers, but they did have iPads with Apple pens and Procreate (or their parents or sisters did), which has some timeline options that work pretty good for simple animations.

]]> 0
Jittery Scrolling Sat, 25 Apr 2020 20:23:39 +0000 Read moreJittery Scrolling

What: Jittery Scrolling, or very slow scrolling in Chrome-based browsers. It’s caused by too many paint operations when scrolling, in my particular case caused by an SVG set as a background-image with background-size: cover and background-attachment: fixed.

How: Remove the background-attachment: fixed and use a pseudo-element with position: fixed and will-change: transform, like so:

body {
  min-height: 100vh;
  position: relative;
body::before {
  background-image: background.svg;
  background-size: cover;
  content: "";
  height: 100%;
  left: 0;
  position: fixed;
  top: 0;
  width: 100%;
  will-change: transform;
  z-index: -1;

Where: Blog post at Four Kitchens with links to more information.

Thoughts: It feels like a complete hack to me that I have to use a pseudo-element to use position: fixed with a 40kb SVG image to get Chrome to scroll normally. What it feels like is regression. More and more Chrome just really does not seem like a particularly good browser to me and I don’t understand why people like it so much.

Photo Credit: Photo of an abandoned train in Garibaldi Oregon. By me.

]]> 0
Media Queries for Input Devices Fri, 17 Apr 2020 18:44:15 +0000 Read moreMedia Queries for Input Devices

What: Since not every touch enabled device is a handheld device, checking for size and checking for touch should be handled separately, since the changes to the design and functionality they require are not the same.

How: You can use media queries.

@media( pointer: coarse | fine | none ){ ... }
/* Primary input device is a finger | a mouse, touchpad or stylus | there is 
no primary pointing device */

@media( hover: hover | none ){ ... }
/* Primary input device can hover | it cannot hover or there is no primary 
pointing device */

@media( any-pointer: coarse | fine | none ){ ... }
/* Any input device (not necessarily the primary one) is a finger | a mouse,
touchpad or stylus | there is no pointing device at all */

@media( any-hover: hover | on-demand | none ){ ... }
/* Any input device (not necessarily the primary one) can hover | shows hover 
state without hovering (with a prolonged tap for example) | no input device 
has any ability to show hover state or there is no pointing device at all */

Where: You can read more at CSS-Tricks. The article is over 3 years old but still good.
You can check support at Can I use…

Thoughts: I haven’t been using these enough and they can be a big help in making user experience better. Support is excellent, the only exception is IE, but at least you can assume that IE will rarely be used on a touch screen. But if you want to play it safe, I guess you could always design for touch screens with coarse control first, and add hover options etc through media queries.

Photo credit: Photo of the Empire State Building lit up in red from the Hudson. By me.

]]> 0
Taking My WordPress Class Online Tue, 17 Mar 2020 23:49:26 +0000 Read moreTaking My WordPress Class Online

Because of the pandemic I too have to start teaching online. I’ve been setting everything up and I’m going to track my progress and findings under the teaching online-tag. This post is about my preparations to make this class available online.

The Class

The course students are taking consists of one class every week for (nearly) the entire school year, they get different subjects during this year and my subject, WordPress, is one of the last ones. It is not a straight-up, plain-old, WordPress class. During the year they have worked on a project and made a design for a website or an app, during my class those designs will be turned into actual sites or webapps with WordPress.

The Situation

The class is in Amsterdam at MK24 and I was going to fly back there on March 19 but now I’m staying in New York City. Not a bad deal by any stretch of the imagination but let’s say I’m very glad that my class is an evening class. With the time difference between Amsterdam and New York, it will be 1 or 2pm in New York (depending on whether the clocks have changed in Amsterdam as well) when class starts.

The Tools

All the content for the classes will be on one WordPress website and each student will get their own WordPress site in a folder of the main site.

Since I’m being paid by MK24 to teach this class, I cannot show you all of it. You can look at the public part at but most of the information for students, the classes, the video conferencing, is restricted to students.

Students can log into the main site. Their roll, in WordPress terms, is Subscriber. Once logged in, they will never see the admin area of the site or the WordPress toolbar at the top but they will be able to see a lot more content, including the page with the video conferencing embedded and all the classes and resources for the classes.

What I’m using to build this site:

  • GeneratePress – a solid, fast, neutral and versatile theme.
  • BuddyMeet – to embed an instance of I like the thought of having the video conferencing software be part of the website that contains everything about their class. I provide a link so they can use Jitsi directly if they prefer but they can also log into the site and go to the “Meeting online” page and that will add them to the conference call automatically.
  • Custom Post Type UI – I’ve added the custom post type Classes and the taxonomy Subject. All of my classes are under the subject WordPress, just in case one of the other teachers wants to add their own classes.
  • GP Premium – the premium version of GeneratePress, not because this theme is perfect but because it gives me such a solid foundation to build almost any website on, and because they are so helpful on their forums.
  • Koko Analytics – so I can keep an eye on whether students are actually looking at all the material. It doesn’t collect any identifying information but if none of them ever looks at the Resources page, I know I need to direct them more forcefully.
  • Link Library – to easily add to the Resources page. (For an idea of what I’m putting on that list, you can take a look at my Resources page on my Today I Learned blog.)
  • Login Widget with Shortcode – so I can easily add the login form to the home page of the site.
  • Restrict User Access – this plugin allows me to make the content only accessible to my students. Pretty easy to use and lightweight.
  • WP Show Posts – I’m using the free version of this plugin to have a little more control over the archive page for my custom post type Classes.

I’m using some other plugins as well but nothing that is specific to teaching online.

Thoughts so far

Based on my recommendation the teacher of this week’s class (I start next week) tried out Jitsi and send me a quick email to tell me that though it changed the dynamic of course, it worked well, so that makes me hopeful. He is going to tell me more later this week.

One of the reasons I chose Jitsi is because it is open source and has a good community and because you don’t have to have an account or install any software. It is particular though about the browser you use. I put a list together for my students and I thought I would add it here for you:

Jitsi Supported Browsers

  • Chrome – Optimal experience. Windows, Mac, Linux. [Tested by me]
  • Brave – I had an optimal experience when I used this on the site itself once I allowed autoplay. But if you try the embedded version on this site, it doesn’t work because of Brave’s focus on privacy. If you would prefer to use Brave, please go directly to the Jitsi website. Windows, Mac, Linux. [Tested by me]
  • Opera – It doesn’t support screen sharing, aside from that it works well. Windows, Mac, Linux. [Tested by me]
  • Vivaldi – Should work at least as well as Opera but I haven’t tested it. Windows, Mac, Linux.
  • Chromium – Should be an optimal experience but is best suited for Linux. Find it through the repository.
  • Firefox – You get a warning when you connect, and I had some weird connectivity issues. I had to restart the browser. Chat didn’t work. Windows, Mac, Linux. [Tested by me]
  • Safari – Only sound, no video or screen sharing, but the chat works. Mac. [Tested by me]
  • Edge – Not supported. Windows. [Tested by me]
  • New Edge – Might work because it is based on Chromium/Chrome. Windows, Mac.
  • IE11 – Not supported. Windows. [Tested by me]

If you have any questions, thoughts or suggestions, I would love to hear them!

]]> 0
scroll-margin-top Tue, 25 Feb 2020 23:40:20 +0000 Read morescroll-margin-top

What: CSS-Tricks just posted about this last Friday and since I could have used this that day (!) but didn’t find it until now, I’m adding a note here for myself:

You have a page with a table of contents (with links), or you have a one page website with in-page navigation and you have a fixed header — when you click a link the content scrolls up too far and is hidden by the fixed header. This is not a good user experience, and you can improve it with scroll-margin-top in Firefox and Chrome-based browsers…

How: Use scroll-margin-top on the item that is being covered by the fixed header, like so:


header { position: fixed; top: 0; width: 100%; height: 6em; }
h3 { scroll-margin-top: 6em; }


<header>My fab website</header>
  <nav class="table-of-contents">
      <li><a href="#topic-1">Topic 1</a></li>
      <li><a href="#topic-2">Topic 2</a></li>
      <li><a href="#topic-3">Topic 3</a></li>
    <h3 id="topic-1">Topic 1</h3>
    <p>A whole bunch of text.</p>
    <h3 id="topic-2">Topic 2</h3>
    <p>A whole bunch of text.</p>
    <h3 id="topic-3">Topic 3</h3>
    <p>A whole bunch of text.</p>

Where: as said, Chris Coyier wrote about it @ CSS-Tricks

Thoughts: Support is not very good: IE, Safari, iOS and old Edge all have no support.

On Friday I decided, since it was a rush job and I didn’t have time for complex hacks or prolonged research, that in this case the table of contents was more important than the fixed header and I nixed the fixed header. Since cross-browser support is not very good, I still think that is the best solution in this case, but I might add some scroll-margin-top anyway, just to make it look a bit nicer, when people scroll–not quite as cramped.

Photo credit: Photo of dusk at the Hudson River, NY NY, looking towards New Jersey. By me.

EDITS: As a lovely person pointed out, I actually wrote margin-scroll-top in one instance instead of scroll-margin-top.

The same lovely person also asked if I knew how to make this work in iOS and … that stopped me because I had in my mind that browser support was good. I checked this post and that was in fact what it said “Support is very good” even with a link to Can I Use which, when I looked again, yes, the Safari and iOS boxes where vaguely green but with those little numbers in them implying caveats… and the caveats mean, in this case, that it doesn’t work in Safari or iOS.

You would have to use scroll-snap-margin-top instead of scroll-margin-top and this is because Safari has implemented it as part of the CSS scroll snap module, which means it is only to be used with scroll snap containers. Since that’s not what we’re doing here, it won’t work in Safari or iOS, I am sad to say.

The simplest solution with good cross-browser support is still this one:

h3 {
  padding-top: 6em;
  margin-top: -6em;

Source: stackoverflow

I am very sorry for my earlier sloppiness and I updated this post to make it clear right away.

Also: thank you very much, lovely person who let me know! I’m sorry I don’t have better news, but I appreciate you emailing me about this.

In general, comments and emails to let me know things like this, or to ask me anything, are always welcome!

]]> 1