Alt vs Figcaption

This message by Elaina Natario writing over at Thoughtbot cannot be repeated enough:

While both the alt attribute and the figcaption element provide a way to describe images, the way we write for them is different. alt descriptions should be functional; figcaption descriptions should be editorial or illustrative.

Examples of both functional and editorial descriptions in the full post!

Alt vs Figcaption →

CSS Sticky Parallax Sections Demo

Nice demo on CodePen by Ryan Mulligan, featuring some sections with a sticky parallax background image:

See the Pen CSS Sticky Parallax Sections by Ryan Mulligan (@hexagoncircle) on CodePen.

I expected to find the the translateZ() + scale() method to create the parallax layers in there, but turns out Ryan took another approach:

  1. Scale down each enclosing section, using a scaleY transform with a number lower than 1, e.g. scaleY(0.9)
  2. Scale up each contained direct child of those sections using an inverse scaleY transform, e.g. scaleY(1.11111111)

As the second scaling (1.11111) undoes the first scaling (0.9), the content is rendered at the original scale of 1 again (e.g. 0.9 * 1.11111 = 1).

:root {
  --speed: 0.1;

.section {
  transform-origin: center top;
  transform: scaleY(calc(1 - var(--speed)));

.section > * {
  transform-origin: center top;
  transform: scaleY(calc(1 / (1 - var(--speed))));

Note that I’ve renamed Ryan’s --scale parameter to --speed here, as that’s what it affects.

Using Emoji as the Mouse Cursor on a Webpage

Recently I saw this tweet by Marco Denic fly by:

To use an emoji as the cursor you can’t simply type in the emoji though.

/* ❌ This won't work */
html {
	cursor: 👻, auto;

What you’ll have to do instead is embed the emoji inside an SVG and then successively embed that SVG in the CSS file by passing it as a Data URL into the url() function.

/* ✅ This will work */
html {
	cursor: url('data:image/svg+xml;utf8,<svg xmlns="" viewBox="0 0 32 32" height="64" width="64"><text y="28" font-size="32">👻</text><path d="M0,2 L0,0 L2,0" fill="red" /></svg>'), auto;

See the Pen
Emoji Cursor
by Bramus (@bramus)
on CodePen.

I’ve also added a little triangle in the top left corner of the SVG, as that’s where the actual tip of the pointer is. Omitting it makes up for a really weird experience.

If you’re on a device that does not show a pointer, here’s a recording of what the demo looks like:

To customize the color of the tip you can change its fill value to any color you like. Although not recommended you can remove the entire <path> if you don’t want it.

To change the overall size of the emoji cursor, change the height and width attributes of the SVG. Best is to leave the other attributes (such as viewBox and font-size) alone, as those have been carefully tweaked.

🔥 Using this same technique you can set an emoji as the favicon.


Did this help you out? Like what you see?
Thank me with a coffee.

I don't do this for profit but a small one-time donation would surely put a smile on my face. Thanks!

☕️ Buy me a Coffee (€3)

To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.

Chrome 88 – What’s New in DevTools

I especially like the New CSS Angle Visualization Tool 🙂

What’s New In DevTools (Chrome 88) →

The Lava Lamps That Help Keep The Internet Secure

At the headquarters of Cloudflare, in San Francisco, there’s a wall of lava lamps: the Entropy Wall. They’re used to generate random numbers and keep a good bit of the internet secure: here’s how.

How geeky! 🤩


I like this demo. Very pleasing on the eyes.

To easily create WebGL demos the author created a little library called RGBA.js which is used under the hood.

Focusing on hiding WebGL/JavaScript code from you and giving ability to write fragment shader code only

Once included, this is the only code one has to write:

float channel(vec2 p, float t) {
  float a = atan(p.x, -p.y);
  float w = sin(a*8.0 + t*2.0)*sin(t+a);  
  float d = length(p) - w*0.013 * smoothstep(0.85, 1.4, abs(a*0.5));
  d = abs(d - 0.25);
  return smoothstep(0.005, 0.0005, d);

void main() {
  vec2 p = gl_FragCoord.xy/resolution-0.5;
  p.x *= resolution.x/resolution.y;
  gl_FragColor = vec4(
    channel(p, time*0.7),
    channel(p, time*0.9+1.0),
    channel(p, time*1.1+2.0),

More demos in this CodePen Collection

How to delete lots of rows from a MySQL database without indefinite locking

Interesting post over at the Flare blog, where they had to delete over 900 million records from a MySQL table. They couldn’t simply run a DELETE FROM table query, as that would lock it:

When a deletion query using a WHERE clause starts, it will lock that table. All other queries that are run against the table will have to wait.

Because of the massive size of the table, the deletion query would probably run for hours. The lock would be in place for hours, essentially halting the entire app.

What I learnt from the post is that you can add a LIMIT clause to a DELETE query.

# Will only delete the first 1000 rows that match
DELETE FROM `events`
WHERE `added_on` < "2020-12-13 23:00:00"
LIMIT 1000;

That way you can chunk your DELETEs, so that your table isn’t locked for an indefinite amount of time. Here’s a little script that I built to run locally:


$cutoffDate = new \DateTime('-1 month');
$batchSize = 1000;

$db = …;

echo "♺ Deleting events before " . $cutoffDate->format(\DateTime::RFC3339) . PHP_EOL;
$total = 0;
do {
    $res = $db-> executeStatement('DELETE FROM `events` WHERE `added_on` < ? LIMIT ' . $batchSize . ';', [ $cutoffDate->format('U') ]);
    echo "  - [" . date(\DateTime::RFC3339) . "] Deleted " . $res . " rows" . PHP_EOL;
    $total += $res;
} while ($res == $batchSize);

echo "\x07✔ Deleted a total of $total rows" . PHP_EOL . PHP_EOL;

In their blog post they mention other ways to do so, including Laravel’s built-in jobs mechanism.

How to safely delete records in massive tables on AWS using Laravel →

Smooth Scrolling and Find In Page, a not so Smooth Combination …

There was this interesting Twitter conversation last week between Chris Coyier and Schepp last week. Apparently if you have Smooth Scrolling enabled, it also affects the behavior of Find in Page in Chrome: Whenever you want to go to the next result it will smooth scroll, instead of jump to it.

Schepp chimed in and offered the solution: leverage the :focus-within pseudo-class selector so that it’s only applied when the html has focus.

Combine it with prefers-reduced-motion and you’ll end up with this:

@media(prefers-reduced-motion: no-preference) {
    html:focus-within {
        scroll-behavior: smooth;

There’s on nasty side-effect though: in-page jump links that refer to the id of an element will no longer work. You’ll actually need to sprinkle some <a name="…">#</a> elements over your markup to make those work smoothly …

Fixing Smooth Scrolling & Page Search →
Chromium Bug #866694 →

Preview, Edit and Generate Meta Tags with

Speaking of meta tags in the previous post, the Meta Tags tool has been sitting in my bookmarks for quite a while now:

With Meta Tags you can edit and experiment with your content then preview how your webpage will look on Google, Facebook, Twitter and more!

Drop in an image, type some text, and you’ll get the resulting meta tags come out. Example Output:

<!-- Primary Meta Tags -->
<title>Meta Tags — Preview, Edit and Generate</title>
<meta name="title" content="Meta Tags — Preview, Edit and Generate">
<meta name="description" content="With Meta Tags you can edit and experiment with your content then preview how your webpage will look on Google, Facebook, Twitter and more!">

<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:url" content="">
<meta property="og:title" content="Meta Tags — Preview, Edit and Generate">
<meta property="og:description" content="With Meta Tags you can edit and experiment with your content then preview how your webpage will look on Google, Facebook, Twitter and more!">
<meta property="og:image" content="">

<!-- Twitter -->
<meta property="twitter:card" content="summary_large_image">
<meta property="twitter:url" content="">
<meta property="twitter:title" content="Meta Tags — Preview, Edit and Generate">
<meta property="twitter:description" content="With Meta Tags you can edit and experiment with your content then preview how your webpage will look on Google, Facebook, Twitter and more!">
<meta property="twitter:image" content="">

Meta Tags →

The serverless gambit: Building on Cloud Run

Interesting read how Greg Wilson built, a website that can track chess games played by sending links to eachother.

Instead of tweeting moves back and forth, players tweet links back and forth, and those links go to a site that renders the current chessboard, allows a new move, and creates a new link to paste back to the opponent. I wanted this to be 100% serverless, meaning that it will scale to zero and have zero maintenance requirements.

The board’s state is represented as a string using the Forsyth–Edwards Notation (FEN)

rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1

That same FEN is also fed to service that generate static images of the board for use in the meta tags.

The serverless gambit: Building on Cloud Run →
ChessMsgs Source (GitHub) →