Composer Inline Aliases: Fake a PHP Package Version by Aliasing a Specific Commit to it

Great tip by Mattias:

You can alias directly when requiring a package:

composer require monolog/monolog:"dev-bugfix as 1.0.x-dev"

Surely comes in handy when locally adjusting a library. More info on Inline Aliases in the Composer Documentation.

The Quest for the Perfect Dark Mode, using Vanilla JavaScript

In The Quest for the Perfect Dark Mode, Joshua W Comeau extensively explains how he has implemented the Dark Mode toggle on his Gatsby-powered website. It follows the system’s light/dark mode preference, but also allows for an override which he persists in localStorage.

The flow to decide if Dark Mode should be used or not is as follows:

Based upon this flow, I decided to create a Vanilla JS version. Here’s a Pen with the final result:

πŸ€” One thing that I personally find missing from Joshua’s implementation is a way to reset the override to auto. To not diverge too much from his implementation I’ve added the reset option via a separate link. What ideally could be done is to use radio buttons (instead of a checkbox) to change between auto, light, and dark.

🎨 Before you continue: Note that this post goes into detail on how to implement Dark Mode, not on how to design your Dark Mode theme. For the latter I refer to How to Design Delightful Dark Mode Themes.

Also note that Dark Mode goes beyond adjusting colors. You might also need to tweak your fonts, tweak the appearance of images (or ship entirely different ones), tweak your favicon, etc.

~

To override Dark Mode I use a data-* attribute on the html element.

<!-- No Override (e.g. follow System Preferences) -->
<html>

<!-- Force Light Mode -->
<html data-force-color-mode="light">

<!-- Force Dark Mode -->
<html data-force-color-mode="dark">

That way, I can implement Dark Mode like it’s meant to be implemented: Using CSS.

/* Light Color Scheme (Default + Override) */
:root,
:root[data-force-color-mode="light"] {
	color-scheme: light dark;
	--text-color: #000;
	--background-color: #fff;
	--link-color: #00f;
}

/* Dark Color Scheme (System Preference) */
@media (prefers-color-scheme: dark) {
	:root {
		--text-color: #fff;
		--background-color: #333;
		--link-color: #2196f3;
	}
}
/* Dark Color Scheme (Override) */
:root[data-force-color-mode="dark"] {
	--text-color: #fff;
	--background-color: #333;
	--link-color: #2196f3;
}

πŸ˜… I know, I have to duplicate the declaration of my Dark Mode CSS Custom Properties, but that’s the only downside to this method imo.

~

To prevent a FOUC on load in case an override is set the same technique as Josh uses is applied: the use of a blocking script. I’ve added the snippet into the head of the page to update the html element if need be.

<html>
<head>
    <script>
        // Check if there's any override. If so, let the markup know by setting an attribute on the <html> element
        const colorModeOverride = window.localStorage.getItem('color-mode');
        const hasColorModeOverride = typeof colorModeOverride === 'string';
        if (hasColorModeOverride) {
            document.documentElement.setAttribute('data-force-color-mode', colorModeOverride);
        }
    </script>
</head>
<body>
  …
</body>
</html>

There’s also a small piece of inline JavaScript needed to make sure the Dark Mode Checkbox shows the correct value on page load. I’ve placed this snippet directly after the markup needed for the Checkbox, so that there’s no FOUC going on.

<input type="checkbox" id="toggle-darkmode" />
<label for="toggle-darkmode"><span>Toggle Light/Dark Mode</span></label>
<script>
    // Check the dark-mode checkbox if
    // - The override is set to dark
    // - No override is set but the system prefers dark mode
    if ((colorModeOverride == 'dark') || (!hasColorModeOverride && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
        document.querySelector('#toggle-darkmode').checked = true;
    }
</script>

~

The Dark Mode checkbox itself will show either a πŸ”† or a πŸŒ™ depending on which mode is used. This is implemented without any JavaScript.

Upon clicking it the setColorMode function will kick into action. This function is also used by a reset-link.

const setColorMode = (mode) => {
	// Mode was given
	if (mode) {
		// Update data-* attr on html
		document.documentElement.setAttribute('data-force-color-mode', mode);
		// Persist in local storage
		window.localStorage.setItem('color-mode', mode);
		// Make sure the checkbox is up-to-date
		document.querySelector('#toggle-darkmode').checked = (mode === 'dark');
	}
	
	// No mode given (e.g. reset)
	else {
		// Remove data-* attr from html
		document.documentElement.removeAttribute('data-force-color-mode');
		// Remove entry from local storage
		window.localStorage.removeItem('color-mode');
		// Make sure the checkbox is up-to-date, matching the system preferences
		document.querySelector('#toggle-darkmode').checked = window.matchMedia('(prefers-color-scheme: dark)').matches;
	}
}

~

Finally, to stay in sync with the system preferences, a listener is placed on the Dark Mode Media Query. If no override is set, the toggle will follow the system preference

const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
mediaQuery.addListener(() => {
	// Ignore change if there's an override set
	if (document.documentElement.getAttribute('data-force-color-mode')) {
		return;
	}

	// Make sure the checkbox is up-to-date
 	document.querySelector('#toggle-darkmode').checked = mediaQuery.matches;
});

~

That’s basically it. The Dark Mode itself is implemented using only CSS. It’s only for the override that we must rely on JavaScript. It requires some jumping through hoops, but all-in-all it’s not that hard I must say.

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 always put a smile on my face. Thanks!

β˜•οΈ Buy me a Coffee (€4)

The Cost of Javascript Frameworks

Tim Kaldec has measured the JavaScript bytes and the JavaScript CPU time for a bunch of sites.

Right now, if you’re using a framework to build your site, you’re making a trade-off in terms of initial performanceβ€”even in the best of scenarios.

Some trade-off may be acceptable in the right situations, but it’s important that we make that exchange consciously.

No surprises there. Perhaps the folks at Jira should take a good look at this πŸ˜‰

The Cost of Javascript Frameworks →

Limit the colors to choose from in <input type=”color”> with <datalist>

Christian Heilman:

The input type colour supports the list attribute, which allows you to define a preset list of options. The colours need to be defined as hexadecimal colours. They can be defined as values or text inside the option tags, but the values take precedence.

Pictured at the top of this post is how Chromium-browsers render the following snippet:

<input type="color" list="presets"></label>
<datalist id="presets">
  <option value="#cccccc">Grey</option>
  <option value="#ffffff">White</option>
  <option value="#6699cc">Blue</option>
</datalist>

In his article he continues with dynamically adjust the colors to choose from, based on the color palette of an uploaded image.

UPDATE 2020-04-27: Turns out it’s also possible to limit the options for datepickers and range sliders: datalist experiment. (via)

Limiting input type=”color” to a certain palette (from an image) →

Dark Mode and Variable Fonts

Robin Rendle writing for CSS-Tricks, on leveraging Variable Fonts when implementing a Dark Mode:

Oddly enough, these two bits of text [shown above] are actually using the same font-weight value of 400. But to my eye, the white text looks extra bold on a black background.

How do we fix this?

Well, this is where variable fonts come in! We can use a lighter font weight to make the text easier to read whenever dark mode is active

Like so:

body {
  font-weight: 400;
}

@media (prefers-color-scheme: dark) {
  body {
    font-weight: 350;
  }
}

Sidenote: 😍 Yanone Kaffeesatz β€” Back in 2005 we used this as the company font for the company I then worked at. Liked it from the moment I first saw it.

~

Depending on the design, there’s more you can do to adjust for dark mode with variable fonts besides adjusting weight. The Louvette font for example has an explicit passage on this:

With the Louvette variable fonts you can adjust the hairline axis (yopq) independently. The is particularly useful if you have light text on a dark background and need to thicken the hairlines to avoid ink from filling in, or on screen for β€œdark mode” settings.

~

Dark Mode and Variable Fonts →

πŸ’‘ Besides tweaking colors and fonts, you might also want to tweak your images and even your favicon for Dark Mode display.

Chrome vs. BlinkMacSystemFont: A Workaround

UPDATE 2020-04-28: Good news everyone! A workaround for this bug has landed in Canary (Chromium 84) and will be merged into the M83 release! The workaround described here still applies for Chromium 81.

The problem

As detailed before there’s this bug that shipped with Chromium 81 which somehow prevents the font-weight CSS property from being applied on the BlinkMacSystemFont font. Quite annoying, as that font is part of the widespread system font stack and affects all modern versions of macOS.

The Chromium bug itself is marked as a blocker for Chromium M83 – the next Chromium version – but as far as I can tell there’s no real progress being made on it. Above that the M83-based build of Google Chrome won’t start shipping until May 19, so we’re stuck for at least another month with this issue. Other browsers (such as Edge, Brave, etc.) might ship their M83-based build even later.

~

The Fix

As a workaround, some users have suggested to simply not use SF Pro (which is the outcome of using BlinkMacSystemFont) but that’s quite a hard measure I must say. Thankfully there’s a better solution. Thanks to Twitter I’ve come to known that the Inter font family is practically a drop-in replacement for SF Pro.

Here on bram.us I’ve adjusted my font stack to no longer use BlinkMacSystemFont and load Inter – served by Google Fonts – instead. To preserve other platforms to load their own system font, I’ve added Inter somewhere at the back of the line.

Here’s a diff of my CSS:

+ @import url('https://fonts.googleapis.com/css2?family=Inter&display=swap');

…

- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", 'Inter', "Helvetica Neue", sans-serif;
+ font-family: -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", 'Inter', "Helvetica Neue", sans-serif;

πŸ’‘ Note that in the snippet above I’m loading all available font-weight Inter supports. It’s recommended to limit this and only load the font-weights you actually need. You can do this via the Google Fonts website

~

With this adjustment in place my website looks quite decent again. Let’s hope the Chromium team can fix this issue soon. In the mean time we can use Inter as workaround.

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 always put a smile on my face. Thanks!

β˜•οΈ Buy me a Coffee (€3)

dotJS 2012 – Brian Leroux – WTFJS

Back in 2012 at dotJS – which I attended – Brian Leroux gave his talk WTFJS. Somehow the video of that talk got recommended on YouTube to me. It was fun watching this again πŸ™‚

Gotta love coercion 😍

Also: Wat?

Think About Solving Problems

Photo by Zach Lucero on Unsplash

When presented with a problem, Nicholas C. Zakas has settled on a set of 5 questions he asks himself for each problem as it arises. Asking these questions, in order, helps him make the best decision possible:

  1. Is this really a problem?
  2. Does the problem need to be solved?
  3. Does the problem need to be solved now?
  4. Does the problem need to be solved by me?
  5. Is there a simpler problem I can solve instead?

I especially like the first one, as opinions are often mistaken for problems.

How I think about solving problems →