Blog Posts

CSS Feature Selectors

I have a number of locations on my website where I've been faking a masonry layout (you know, like how Pinterest lays things out) using CSS grid columns. They work, but they're not what I'm looking for.

I've been waiting for the official masonry grid display to land, and discovered that it's now an experimental feature in Chrome-based browsers that you can enable (it's been available for Firefox for awhile).

But... how can I check to see if the feature exists? Turns out CSS already has that covered, via the @supports selector:

@supports (display: masonry) {
    .container {
        display: masonry;
    }
}

@supports not (display: masonry) {
    .container {
        display: grid;
    }
}

I love that CSS is fully embracing the idea of progressive enhancement! I've used feature testing in JS for a long while, but hadn't realized this was now baked in to CSS, too.

Continue reading...

Linux desktop files and xdg-open

I've been using Linux on the desktop for more than 25 years now. While I don't put icons on my desktop any longer (and haven't for probably around 15 years), I do use the gnome-shell launcher to quickly open programs, and this utilizes desktop files.

Recently, I wanted to create launchers for different Obsidian vaults. Obsidian provides a URL schema for this: obsidian://open?vault=VaultName. The application registers the schema handler with the system, so this should open, but evidently you can no longer use "Type=Link" in your desktop files.

What I found:

  • You MUST have a "Version=1.0" line; gnome-shell just ignored any of my desktop files that omitted it.
  • You can use xdg-open in your Exec line to open the URL.
[Desktop Entry]
Version=1.0
Name=Notes
Icon=/usr/share/icons/hicolor/256x256/apps/obsidian.png
Comment=My Obsidian vault for notes
Categories=Office;ProjectManagement;
Type=Application
Exec=xdg-open "obsidian://open?vault=notes"

Continue reading...

Disabling the Zoom mini window on Linux

Zoom used to have a strange behavior, one I'm sure they thought would be useful, but in reality was infuriating: if you moved between virtual workspaces, Zoom would minimize to a thumbnail window that followed you around to workspaces.

At some point, it went away, thankfully... but after a recent release, it turned back on, and it's been a huge pain for me. There's a bug in that the mini window follows me to the initial virtual workspace, but then doesn't follow around from there, requiring me to use the workspace tools to move it to the workspace I want, and then re-maximize it, only to have to do the whole thing again if I switch screens.

Continue reading...

Matching Attribute Values in CSS Selectors

I had a situation where I was doing some web scraping, and the site, while it had a predictable structure, had some unpredictable class names for the elements I was searching for.

In all cases, there was a class that began something like "ItemOfInterest_image_item__", but where the suffix would vary such that I couldn't depend on it matching from request to request.

So, today I learned that you can match an attribute value in a variety of ways:

// Match at the start of the attribute declaration
div[class^=ItemOfInterest_image_item__] img {}
// Match at the end of the attribute declaration
div[class$=ItemOfInterest_image_item__] img {}
// Match anywhere in the attribute declaration
div[class*=ItemOfInterest_image_item__] img {}

In my case, the specific class name could appear anywhere in the string, so I used the * selector.

Continue reading...

Overriding values when merging Docker Compose config

I've recently started using the ability to merge Docker Compose files, as it reduces repetition when having different configuration for production from development. This also helps reduce cases where configuration gets updated in one, but not the other, leading to issues when debugging why something runs in one environment but not another.

Generally, when overriding something in development, I'm overriding volumes and environment variables. I started also using the fact that the env_file directive can take a list of files, which allows segregating environment variables by context, allowing re-use of specific variables between services, so that I don't go polluting services with ENV variables that it doesn't use.

The problem I ran into, however, is that on a particular service, I have production env variable files in a secure, global location, but in development, I use a single .env file. When these get merged, because the value is a list, I was getting complaints in development that one or more env files did not exist.

Since I knew I wanted to keep just the one entry in development, I needed a way to tell Compose to use only the value in that file.

Turns out this is well supported via the !override directive:

### In my development compose YAML:
services:
    app:
        env_file: !override
            - .env

Continue reading...

Handling PHP-FPM using Caddy

I've been using Caddy for years as a reverse proxy in front of other services, but recently wanted to use it to directly route traffic to PHP-FPM. Caddy has a specialized reverse proxy directive for PHP-FPM, php_fastcgi, which seemed like it would do the trick, but I found that no traffic was ever getting routed to my FPM pool.

Continue reading...

An Experiment in Journaling

I've been struggling to make time to either journal or draw.

The last I journaled regularly was in the winter of 2016/2017. Before that, it had been a number of years as well. I type so much faster than I write by hand, and my handwriting is atrocious. But when I type my journal entries... it's too easy to get distracted and do something else, or to edit as I go, instead of just letting the words spill out.

As for drawing, it's not that I'm not drawing, it's that I'm not drawing regularly. It's felt like an effort, which is unfortunate, as drawing was what I was doing to relax.

So I made a choice.

Continue reading...

SQL Nested Queries or Sub Queries with Doctrine DBAL

I recently ran into a problem with my website for which the solution was a nested query (sometimes termed a subquery). However, I use Doctrine DBAL for creating my dynamic queries, and there's no documentation on how to do them.

Continue reading...

Comments are Back

For a number of years, I was using Disqus to provide comments on my blog. However, I was increasingly unhappy with how bloated the solution was, how many additional entries I was having to put into my Content Security Policy, and unsure how comfortable I was with having a third party own comments to my own site.

So last year, I removed comments from my site entirely.

This worked fine, and I didn't really think about it much, until somebody reached out to me via email recently, with what was essentially a comment on a blog post, and I realized that nobody else but me was going to benefit from it.

So I started thinking about how to go about adding comments again.

Continue reading...

Fixing issues with Yubico's PAM U2F bindings in version 1.3.1

I've been using a Yubikey for years, now, and on each computer I use, I install their U2F (Universal 2 Factor) bindings for the linux Pluggable Authentication Modules (PAM) support, requiring usage of my Yubikey for login and sudo access.

Today, I updated my work machine, and didn't even notice that there were new pamu2fcfg and libpam-u2f packages, updating to version 1.3.1; I never really care, as everything just works. But when I came back to my machine after lunch, I was unable to login: I'd provide my password, but my Yubikey wouldn't activate.

Continue reading...