The native HTML range input

Many of us have seen and used them. In the WordPress Block Editor, they are available for things like the font size of several blocks. This is how it looks for the core/paragraph block:

The "Typography" settings for the font size of a paragraph block, showing a number input on the left, and a range input on the right, with the numeric value in a tooltip below it.

When you use the range selector, it will show the current value under the “range thumb” and also updates it in the number input field left of it.

Options for the range input

The two most important attributes to the range input are probably the min and max attributes. So this is a basic example:

<input type="range" id="font-size" name="font-size" min="16" max="96" />
<label for="font-size">font size</label>

As always, don’t forget to have a <label> for your inputs. If you don’t set min, its default value will be 0 and for max it will be 100.

Another attribute you might want to use it step. This can be a decimal or floating-point value, like in this example:

<input type="range" id="font-size" name="font-size" min="16" max="96" step="4" />
<label for="font-size">font size</label>
<input type="range" id=">line-height" name="line-height" min="0" max="10" step="0.1" />
<label for="line-height">line height</label>

For some reason, WordPress is not using a range input, but only a number field. But it is also using a step width of “0.1” here.

On the documentation page, you will also find a rather crazy example for the step attribute, and it looks like this:

<input id="pi_input" type="range" min="0" max="3.14" step="any" />

If you use the value “any“, the input will really take “any floating-point” value in between min and max. Interestingly, if you use your keyboard to navigate to the range input, and then use the left/right cursor keys to move the thumb, you will get 100 discrete values. But if you use your mouse, you will get some random wild numbers in between.

Using the list attribute

In the last blog post on the HTML topic, we have already learned about the list attribute, and the range input also supports it. You can find some normal and creative examples in the documentation. In Chrome, using a list attribute lets the thumb “snap” to <option> values of the <datalist>, but you can still also have a value in between. In my opinion, you can best combine the list attribute with steps, as in this case, you only allow the selection of options in your <datalist>:

<label for="temp">Choose a comfortable temperature:</label><br />
<input type="range" id="temp" name="temp" list="markers" step="25" />

<datalist id="markers">
  <option value="0"></option>
  <option value="25"></option>
  <option value="50"></option>
  <option value="75"></option>
  <option value="100"></option>
</datalist>

This code shows an input without min/max values, but with an additional step="25" attribute. Also take a look at the example using labels.

Styling of the range input

The styling would look very different, depending on your browser or operating system. Even though WordPress is using a range input, what you see is not the input itself. It is made “transparent” and lays above some custom HTML using multiple spans to create a UI element, that looks the same in all browsers. If you want to use that exact element, you can use the RangeControl component in your JavaScript code.

But even if you can’t style the range input exactly the same, there are some options to styles it, like changing the color of the bar and thumb:

input[type='range'] {
  height: 30px;
}
input[type='range'],
input[type='range']::-webkit-slider-runnable-track,
input[type='range']::-webkit-slider-thumb {
  -webkit-appearance: none;
}
input[type='range']::-webkit-slider-runnable-track {
  height: 10px;
  background: red;
}
input[type='range']::-webkit-slider-thumb {
  position: relative;
  height: 30px;
  width: 30px;
  margin-top: -10px;
  background: green;
  border-radius: 50%;
}

This is only one example for Chrome/Webkit. It’s important to set many things to appearance: none, as otherwise the other styling changes would have no effect. These styles would result in a range input like this:

A label "Choose a comfortable temperature" with a range input below it. The input has a red background color (the range bar) and a green "thumb" (a circle to change the value).

You all know I’m not a designer, but I hope this illustrates the styling a bit. If you want to go really creative, take a look at the blog posts from CSS-Tricks, Smashing Magazine or W3Schools.

Conclusion

Range inputs can really make the UX of an online application better, since number inputs are not “as responsive” in some cases. And if you are not in the WordPress JavaScript ecosystem, using the native range input might be all you need.

Smooth scrolling using CSS

More than 9 years ago, I wrote a (German only) blog post about how to “improve JavaScript with scroll event handlers”. Back in the days, people would use a plugin like “WP-Smooth-Scroll” (it’s still around, but hasn’t been updated in 11 years). Smooth scrolling was often used in combination with a “scroll to top button”. The scroll effect was done with the scrollTop() function from jQuery. Nowadays, jQuery is not used as much. But scrolling with JavaScript is still around.

Scrolling a page with JavaScript

Beside “scroll to top buttons”, a website can also use “smooth scrolling” for anchors. If you want to see it in action, look no further than on the file wp-includes/js/admin-bar.js in WordPress core, where you will find this function:

/**
 * Scrolls to the top of the page.
 *
 * @since 3.4.0
 *
 * @param {Event} event The Click event.
 *
 * @return {void}
 */
function scrollToTop( event ) {
	// Only scroll when clicking on the wpadminbar, not on menus or submenus.
	if (
		event.target &&
		event.target.id !== 'wpadminbar' &&
		event.target.id !== 'wp-admin-bar-top-secondary'
	) {
		return;
	}

	try {
		window.scrollTo( {
			top: -32,
			left: 0,
			behavior: 'smooth'
		} );
	} catch ( er ) {
		window.scrollTo( 0, -32 );
	}
}

As you can see from the comment, this function has been around since WordPress 3.4, which was released in June 2012! The behavior: 'smooth' was added only later, since Firefox added it in 2015 and Chrome in 2017. But still today, you can click on the “Admin Bar” (on anything but a link) and the website will scroll up smoothly.

The issue with method

As we can see in the code above, the scrollTo() function takes an object with the exact scroll position in the viewport. For the WordPress “Admin Bar”, this is easy, since it sticks to the top of the page. But if we want to scroll to another element on the page using an anchor link, we need to calculate the position. And do you remember our last blog post on the CSS topic, “How to fix sticky headers“? If we want to make sure the scroll position is correct, we also need to take the scroll-margin-top offset into account.

An alternative JavaScript approach

There is another scrolling function, that is also around for many years: the scrollIntoView() function. With this one, we don’t have to calculate the position. We just select the element we want to scroll to and use this function on it:

const element = document.getElementById("some-anchor");
element.scrollIntoView();

The great thing about this one, is that you can even tell the function where to place the element. And it takes the scroll-margin-top or similar properties into account. There are some more examples on the documentation page. One of these other CSS properties is the one, I want to write about in this blog post.

The CSS scroll-behavior

Even without JavaScript, you can get a smooth scrolling by only using CSS. Just add the following to your page:

html {
	scroll-behavior: smooth;
}

Now, when you click on any anchor link, the site will “scroll smoothly” to that element. And since the browser knows exactly how to do that, we always get the perfect scroll position for that element.

Conclusion

Sure, you can use a function with 20 lines like in WordPress Core for a smooth scrolling effect. But you could also just use one CSS property and regular anchor links to get the same result. And I haven’t even told you about all the issues with JavaScript scrolling, like scrolling manual scrolling while the smooth scrolling is still animating, wrong position calculation due to lazy loading, etc. I hope this is enough to convince you for now. 😉

Labeled statement in JavaScript

You might now ask yourself: What?! That was also my first reaction, when I’ve heard about labeled statements. So what are they, and when can they be used?

Are they goto statements?

Many programming languages have goto statements. Some programming languages even only added them in later version, like PHP did with version 5.3, and this is how it would look like in PHP:

$array = [
	'one' => [ 1, 2, 3 ],
	'two' => [ 4, 5, 6 ],
];

foreach ( $array as $key => $numbers ) {
	foreach ( $numbers as $number ) {
		if ( $number === 4 ) {
			goto fourFound;
		}
	}
}

echo "There is no 4 in the array";
goto end;

fourFound:
printf( "There is a 4 in array '%s'", $key );

end:

In this example, we have two foreach loops. The code tries to and find a 4 in a two-dimensional array. As soon as a 4 is found, we can stop the loops and print the result. To leave the loop(s), this code is using a goto statement to “go to” line 17 to the label fourFound, where we print out the result. There is also a second goto at line 15, which would move to the end label. In any case, only one echo/printf function would be called.

Many experienced developers would see multiple ways to improve that code, but I hope it can demonstrate, how a goto in PHP (and many other languages work) works. But what are labeled statements in JavaScript? They are similar to the labels in PHP shown here, but there is no goto statement and those labels can only be used in combination with either the break or the continue keyword.

How to use continue and break in your code?

If you have a loop, you can break out of the loop, by using the break statement like this:

const numbers = [1, 2, 3, 4, 5, 6];

for (let i = 0; i < numbers.length; i++) {
	if (numbers[i] === 4) {
		console.log(`Found 4 at index ${i}`);
		break;
	}
}

This code would iterate through the numbers array, but as soon as it found the 4, it would “break out” of the array and not look at the other values.

The continue statement can be used to stop the current iteration and start with the next one. Like in this modified example:

for ( let i = 0; i < numbers.length; i++ ) {
	if ( numbers[i] % 2 !== 0 ) {
		continue;
	}
	if ( numbers[i] === 4 ) {
		console.log( `Found 4 at index ${i}` );
		break;
	}
}

In line 2, we check, if the current number is odd. If that’s the case, it can’t be the number 4 we are searching for. We then use the continue statement, to start with the next iteration, so the condition in line 5 would not be executed.

How to skip an “inner loop”?

Let’s take the first code example from PHP again and use the break statement instead of a goto statement:

$array = [
	'one' => [ 1, 2, 3 ],
	'two' => [ 4, 5, 6 ],
];

foreach ( $array as $key => $numbers ) {
	foreach ( $numbers as $number ) {
		if ( $number === 4 ) {
			break 2;
		}
	}
}

if ( $number === 4 ) {
	printf( "There is a 4 in array '%s'", $key );
} else {
	echo "There is no 4 in the array";
}

In PHP, you can use break 2 to not only exit the “inner loop”, but also the “outer loop”. So the number after break indicates how many “control structures” you want to break out from. Something similar is possible with continue 2, where the program would continue with the next iteration of the “outer loop”.

In JavaScript however, this is not possible. You cannot add any number after a break or continue statement. And that’s where labeled statements come into play.

Breaking out an inner loop in JavaScript

If we try to create the same code as above in JavaScript, we can use a labeled statement like in this code:

var array = {
	one: [1, 2, 3],
	two: [4, 5, 6],
};

outerLoop:
for ( var key in array ) {
	var numbers = array[key];
	for ( var i = 0; i < numbers.length; i++ ) {
		if ( numbers[i] === 4 ) {
			break outerLoop;
		}
	}
}

if ( numbers[i] === 4 ) {
	console.log( `there is a 4 in array ${key}'` );
} else {
	console.log( "There is no 4 in the array" );
}

The label does not need to be on its own line, it can also be in one line for the for loop. For better readability, I just formatted it like this.

If you prepend each loop with a label, you could also have use break statement to jump to any loop. The same is true for continue.

What should I use this for?

So should you use labeled statements? My advice would be similar to the one given by the xkcd comic on goto: Don’t use it!

If you end up writing some code that would profit from something like break 2, continue 2, or the JavaScript equivalent using a labeled statement, this would be a clear sign for me, that this piece of code should be refactored.

Instead of using a goto to jump out of a loop, put that loop inside a function and use return. And for nested loops, you can also use nested functions in loops.

There are plenty of things to optimize in the code above, not only the nested loops. With some modern JavaScript functions, it could look like this:

const array = {
	one: [1, 2, 3],
	two: [4, 5, 6],
};

function findTheFour(obj) {
	for (const property in obj) {
		if (obj[property].includes(4)) {
			return property;
		}
	}
	return null;
}

const found = findTheFour(array);
if ( found ) {
	console.log( `there is a 4 in array ${found}'` );
} else {
	console.log( "There is no 4 in the array" );
}

Isn’t that a lot easier to read? Using the includes() function for arrays, we can even safe the “inner loop”. And we do not need any labeled statement.

Conclusion

You may ask yourself why I’ve shown you this feature of JavaScript, and then advise against the usage of it. Well, there is code out there using it which you might not understand, if you have never seen labeled statements or goto in other programming languages. And I haven’t even shown you all the things you can do with it. So feel free to read the documentation on it, and maybe you do find a use case, where it can really benefit your code base, what ever case that might be.

Debugging arrays and objects in JavaScript with the console.table() function

In the first debugging blog post, we’ve learned about the console.log() method and how it works to debug scalar types or arrays. But there is a nicer way to log arrays or objects in the browser.

The console.table() function

As mentioned in the first blog post, the console object has some more useful functions, and today we want to take a look at the table() function.

Simple arrays

The function can be used to log arrays like this:

const colors = ["red", "green", "blue"];

console.table(colors);

This is the most basic example. We just use a one-dimensional (numerical) array. This is the result in the browser console:

Browser console, showing a table with "(index)" as the first column header and values ranging from 0-2, and "Value" as the second column header, with the color strings.

As you can see here, you get a table with two columns. The first one is the numerical “(index)” for the array, and the second one has the “Value” for each entry of the array. You will still always have the variable below the table, just as with console.log() and you can “expand” it here, to investigate it further.

Multidimensional arrays

The function can not only be used with simple one dimensional array, but you can also use it for multidimensional ones:

const names = [
	["Leia", "Organa"],
	["Luke", "Skywalker"],
	["Han", "Solo"],
];

console.table(names);

Now we have an array of (numerical) arrays and this is how it looks like in the console:

(index)01
0'Leia''Organa'
1'Luke''Skywalker'
2'Han''Solo'

We now have three columns. Since the “inner arrays” are numerical as well, we have column name “0” and “1” for them.

Logging objects

The function cannot only be used for arrays, but also for objects. The output depends on the structure of the objects.

Simple objects

Let’s create an object for one of the previous example:

function Person(firstName, lastName) {
	this.firstName = firstName;
	this.lastName = lastName;
}

const luke = new Person("Luke", "Skywalker");

console.table(luke);

And this is how that object would be logged into the browser console:

(index)Value
firstName'Luke'
lastName'Skywalker'

Logging arrays of objects

How about logging an array with multiple objects of the same type? Again, an example like before:

const leia = new Person("Leia", "Organa");
const luke = new Person("Luke", "Skywalker");
const han = new Person("Han", "Solo");

console.table([leia, luke, han]);

This is the resulting table for this array of objects:

(index)firstNamelastName
0'Leia''Organa'
1'Luke''Skywalker'
2'Han''Solo'

As many of you might have expected, the column names are now the property names of the objects.

Logging multidimensional objects

The previous example was using a numerical array. But how about an object of objects? Here is an example:

const family = {};

family.mother = new Person("Padmé", "Amidala");
family.father = new Person("Anakin", "Skywalker");
family.daughter = new Person("Leia", "Organa");
family.son = new Person("Luke", "Skywalker");

console.table(family);

And the result of this will look like this:

(index)firstNamelastName
mother'Padmé''Amidala'
father'Anakin''Skywalker'
daughter'Leia''Organa'
son'Luke''Skywalker'

That looks nice, right? Except for “(index)”, we have some good columns names and our index values also are not numerical anymore.

Logging only specific columns

The console.table() function has a second parameter columns, which is an array as well. It expects an array with the names of the columns/indices. So for our previous code, we could do this:

console.table(family, ["firstName"]);

And sure enough, this would be the logged results:

(index)firstName
mother'Padmé'
father'Anakin'
daughter'Leia'
son'Luke'

Pretty neat, isn’t it? This can be really useful when debugging some larger objects with multiple properties.

Conclusion

Even though you can use the generic console.log() function to debug and log arrays and objects, seeing them in a logged table, can make reading them a lot easier. You also don’t have to “expand” the tables.

Implement a color picker with native HTML

In the first advent calendar blog post with the topic HTML, I want to introduce an HTML element, some of you might not know. It’s not really its own element, but the <input> element of type color. With this element, you can add a very simple color picker to your web application.

Adding a color picker to your site

Inserting the color picker is straightforward. It’s an <input> element, and you can add a value attribute, if you want:

<input type="color" id="background" value="#000000" />
<label for="background">Background</label>

Yes, you always want to have a <label> with any form input field. If you don’t set a value, it would use #000000 as the default. You can also only set a hexadecimal RGB value, without an alpha value (transparency) so nothing like #00000066.

The color picker in different browsers

As with many other input-types, the color picker has a very different UI, depending on the operating system you are on and the browser you are using. There are some examples:

Chrome color picker in Linux
Chrome (Linux)
Chrome color picker in Windows
Chrome (Windows)
Firefox color picker in Linux
Firefox (Linux)
Firefox color picker in Windows
Firefox (Windows)

Chrome brings its own color picker, and it looks similar in Linux and Windows. Firefox on the other hand would use the native color picker from your OS.

Advanced usage with a color list

A bit hidden in the documentation of the element, you can see that the element can use a list attribute. That attribute alone would probably worth its own blog post. When you use that attribute, you can reference a <datalist> with some values. This is how it would be used:

<input type="color" id="text" list="text-colors"/>
<label for="text">Text</label>
<datalist id="text-colors">
	<option>#ff0000</option>
	<option>#00ff00</option>
	<option>#0000ff</option>
	<option>#ffffff</option>
	<option>#000000</option>
</datalist>

For the <option> values, you can also only use hexadecimal RGB values. This is how the color picker with the list looks like in Chrome:

Color list in Chrome (Windows)
Color list in Chrome (Windows)

If you have more than 5 values, it will show them in up to three rows with 5 colors each If you have even more values, it will show a scrollbar. In Firefox on Windows however, it would use the same color picker as before, and list the options below the “Custom colors” in the modal.

Bonus: Using WordPress color picker components

If you are developing a WordPress project, you can use the color picker components that are available in the WordPress components library.

The ColorPicker component

In @wordpress/components you will find the ColorPicker component, that would render the color picker:

import { useState } from 'react';
import { ColorPicker } from '@wordpress/components';

function MyColorPicker() {
    const [color, setColor] = useState();
    return (
        <ColorPicker
            color={color}
            onChange={setColor}
            enableAlpha
            defaultValue="#000"
        />
    );
}

When you use the components it would render “inline”, so not open on a click on a button:

ColorPicker component with a color picker, a select for "Hex", a "copy value" button and an input with "#000000" as its value.

If you want to have a button to open the color picker, you would have to implement that yourself. If you add the enableAlpha attribute, you can also use an RGB value with alpha (e.g. #00000066) in the input, or you switch from “Hex” to “RGB” or “HSL”, where you would have an alpha channel range setting.

The PanelColorSettings

There is currently no documentation for the PanelColorSettings component, but this is how you would use it:

import { useState } from 'react';
import { PanelColorSettings } from '@wordpress/block-editor';
import { __ } from '@wordpress/i18n';

export const MyPanelColorSettings = () => {
	const [ textColor, setTextColor ] = useState( { color: '#000' } );
	const [ backgroundColor, setBackgroundColor ] = useState( { color: '#fff' } );

	return (
		<PanelColorSettings
			__experimentalIsRenderedInSidebar
			title={ __( 'Color' ) }
			colorSettings={ [
				{
					value: textColor.color,
					onChange: setTextColor,
					label: __( 'Text' ),
				},
				{
					value: backgroundColor.color,
					onChange: setBackgroundColor,
					label: __( 'Background' ),
				},
			] }
		/>
	);
};

In the colorSettings object, you can set multiple colors. In this example, we have one for a text and background color. This is how it would render:

PanelColorSettings showing the modal to select a color, with the colors from the theme and core default colors listed on the left, and the "Text" and "Background" color settings on the right.

As you can see here, the PanelColorSettings will not show a generic color picker, like the ColorPicker would do. Instead, it will present you with the color presets from the theme and from Core, depending on how these color settings are defined in the theme.json file.

Conclusion

Implementing a color picker was never easier, than with the native HTML input type. No more need to add a heavy jQuery/JavaScript library. Unless you want to use a color picker inside a WordPress project and also use the color palette from the theme. Then you can use the components from the block editor. They also have the benefit, that they render in the same way in any browser and any OS.

If you need a quick color picker for some random use case, you could also just google for “color picker”. 😉

How to fix sticky headers

You all know these websites with a sticky header, right? They have a horizontal navigation at the top, often with the site logo on the left – which is also often way too big, so not too many navigation items fit beside them. And then you scroll down these pages with this large header … and the header does not scroll off the page. Many people want that for their own website, but many people using this page don’t like it as much. I’m one of them.

Issues with sticky headers

There are multiple issues with such a sticky header. While there are valid reasons to have them, most of the time they are used for the wrong reasons – like website owners always want to see their logos or important navigation items. In my opinion: if people need to use your main navigation to find things, you are doing content wrong on your site. But what are the actual issues?

Issue 1: Elements appear behind or before the sticky header

Sure, when your website is designed with a sticky header, it probably pushed the content down. But since the sticky header needs to above the content when scrolling down, it might also cover some content that you can’t interact with anymore, like a popup that has the close button in the top right and that is now behind the header. And since often with popups, you can’t scroll the page while they are open, you can’t hit that closing button.

But you could also have issues with content that appears before the header, when you scroll down the page. That happens quite often with embedded elements, like a video, PDF or map embed.

Issue 2: Anchor links don’t work anymore

When you use an anchor link to navigate to parts of your site – which is really popular on “one pager websites”. Such an anchor element scrolls the website down (or up) so that the element is at the top of the page. And then it is behind your header.

Issue 3: Too little vertical space

When those headers are really high, you end up having not too much vertical space left on the page to view the content.

Let’s take an 11″ laptop with 720px height. Not as uncommon as you might think. Then we calculate the available vertical height:

  • Total: 720px
  • Windows taskbar: 66px
  • Chrome tabbar: 40px
  • Chrome address bar: 48px
  • Chrome bookmark bar: 34px

That leaves us with just 532px remaining vertical space. And now reduce this by another 60px only – that is about the current height of the header on my blog, which is really not high. This leaves you with only 472px of available space. And have we talked about those sticky cookie banners at the bottom already? That’s about the space that many of us have in landscape mode on our phones, and who really enjoys browsing a website in landscape mode?

Solutions

There are multiple solutions for the issues mentioned. Here are some that might work in your cases.

Issue 1

If a single (type of) embedded element is overlapping your header, you have to find a good z-index value for this element and overwrite it. Or you increase the z-index value of your header. But this can the lead to the issue with elements behind your header. You probably end up trying around with many manual z-index changes for multiple elements and still you find some elements that don’t appear as you want them to.

Issue 2

Most websites use some CSS like this to make a header sticky and move the content down:

.fixed-header {
    position: fixed;
    top: 0;
    width: 100%;
    z-index: 999;
}
html {
    margin-top: 60px;
}

Something like this would work for my header. It’s also what WordPress does, when it shows the “adminbar”. But it’s not the best solution to create a sticky header.

There is a relatively new value sticky for the position CSS property, and this is how the CSS code for a sticky header would look like with this new value:

.fixed-header {
    position: sticky;
    top: 0;
}

The great thing about it: the header does not need to be the first/top element on the page. You could have a logo, followed by the sticky header, and once that header reached the top of your browser viewport when scrolling down, it “sticks” to the top. In the past, this was only possible by toggling the position to fixed with JavaScript, and adding the margin-top at the same time. But now, modern browsers can do this kind of effect automatically.

No matter how we make our header sticky, we still have the issue with anchor links not working. The margin of 60px will not push any element down by that value, but only the beginning of the body.

To solve this, you could use an additional CSS property, to add an offset for the scrolling to the anchor like this:

html {
    scroll-padding-top: 60px;
}

This additional scroll-padding-top should get a value of at least the height of the header. And here you see another issue with this solution: if the header height changes, e.g. when the items don’t fit into one line anymore and break into two lines, then those static values don’t work anymore. You could now add some JavaScript to dynamically update these two values, but that’s not a great solution.

Issue 3

My favorite solution for this issue: just don’t use a sticky header. It also solves all the other issues. No, seriously. Does your header really need to be sticky? Does it make your website more usable? Can people read your content better or even find their way around? Please think twice before making a header sticky, and not just “because you like it that way”.

So in case you really need to make it sticky, there are some ways to make you website more usable:

  • Reduce the height of the header, once your site scrolls down – this is what many themes do, and they often also shrink the logo
  • Hide the sticky header after some scrolling, and show it again, once you scroll up – many apps do that for sticky header and footer bars
  • Make the header “not sticky”, if you detect a too low viewport height or if a device is in portrait mode

Conclusion

Some people love sticky headers, other hate them. You have to decide for yourself, if you want to have them. But please do one thing: don’t only test your website on your large desktop/laptop screen. Grab your smartphone and browse your website in landscape mode. Do you still think a sticky header is a good idea? Then use the techniques mentioned above to solve the usual issues with them.

Fun with numbers in JavaScript

No, I’m not going to start a video channel on this topic. But I want to show you some things about numbers, you might not have known before. The answer, however, as we all know, is 42.

Types of numbers

Let start with the very basics. You probably all know that in JavaScript, just like in many other programming languages, there are decimal number and floating-point numbers. But internally, they are all of the type Number. They are 64-bit, which should usually be enough for most code. But if you need really large numbers, you can also use BigInt to store them.

Some lesser known number types

Now that we know, that all (small) numbers are of type Number, we only know parts of the truth. We can have more than just two types. Here are the two typical ones, and some more, you might not have heard of or used in JavaScript:

42 // decimal
42.0 // float
042 // octal => 34 decimal - as digits after leading zero(s) are <= 8
099 // not octal, decimal 99, as digits after leading zero(s) are > 8
0o42 // explicit octal number - either lower- or uppercase latin "o"
0x42 // hexadecimal => 66 decimal - either lower- or uppercase latin "x"
0b101010 // binary 42, nice sequence ;) - either lower- or uppercase lat. "b"
0.042e3 // exponential number 42 - either lower- or uppercase latin "e"
42n // BigInt 42 - decimal followed by latin lower- "n" even for small number

Comparing numbers

As we have discussed earlier, except for BigInt, all numbers are the same type. Therefore, comparing the following numbers, these are the results:

42 === 42.0 // true
042 === 42 // false
0o42 === 34 // true
042 === 34 // true
099 === 99 // true
0x42 === 66 // true
42 === 0b101010 // true
42 === 0.042e3 // true
42n === 42 // false
42n == 42 // true

That last one might be (a bit) unexpected. So when comparing a BigInt to any other number, you cannot use the “strict equality operator”, since the numbers are of a different type.

If you want to find out, if a number is an integer, you can use a function from the Number object:

Number.isInteger(42) // true
Number.isInteger(42.001) // false
Number.isInteger(42.0) // true
Number.isInteger(42.000000000000001) // true

As you can see, this function will return true, if the number is an integer, or a floating-point number with a zero fraction – or a really small fraction. Unfortunately, there are no similar functions to check for other number types.

Now some fun part

Do you need some very long numbers in your code? Then you probably end up with something really hard to read. But there is a neat little trick to make them more readable:

// That's a huge number!
let rubiksCubeConfigurations = 43252003274489856000;
// As a string, it's easier to read, but this is bad code!
let sameNumberAsString = parseInt("43252003274489856000");
// How about this?
let easierToRead = 43_252_003_274_489_856_000;

That’s more readable, right? The funny thing is, that you can use an underscore at any place, just not at the beginning or end of the number, not after a leading zero, and not two underscores in a row. But many of us will probably use them like shown above.

Bonus: Formatting numbers

Now that we have seen how to make numbers more readable in code, here is a tip to make them easier to read for people from different countries. In the US, you would write a number like this: “123,456.789”. But in Germany, you would write “123.456,789”. If we look at the Number object again, we will find the toLocaleString() function, and this is how you can use it:

const number = 1234567.89;
// German
console.log(number.toLocaleString("de")); // 1,234,567.89
// English (United States)
console.log(number.toLocaleString("en-US")); // 1,234,567.89
// Englisch (India)
console.log(number.toLocaleString("en-IN")); // 12,34,567.89
// Ukrainian
console.log(number.toLocaleString("uk")); // 1 234 567,89
// Dzongkha
console.log(number.toLocaleString("dz")); // ༡༢,༣༤,༥༦༧.༨༩

Would you have known, how numbers are formatted in different languages? And in some languages, JavaScript will even output them with non latin letters. The same function can also be used to format currencies:

const costs = 123.4567;
// German with EUR
console.log(
    costs.toLocaleString("de-DE", { style: "currency", currency: "EUR" }),
); // 123,46 €

Conclusion

There are many really useful trick then dealing with numbers in JavaScript. I hope there was something for you, that will help you in a future project. I can also recommend to look at documentation of the other functions and features of the Number object.

Getting started with JavaScript debugging

It’s that time of the year again. Some of you just celebrated Thanksgiving, while the rest of the world only “celebrated” Black Friday. But I’m speaking about the 24 days before Christmas. Starting in 2015, I’ve set myself the goal to write one blog post per day. I managed to do that in 2015 and 2016 in German. In 2017, I did it in English as well in, but after only 10 day, I had to stop. Since then, I haven’t tried it again.

Restart of the advent calendar

This year, I will try to do it again. In the past editions, I hadn’t really planned all topic, if any. But this year, I was prepared a week early and already collected 24 potential topics to write about. I will focus on frontend topics and debugging. Every day, I will write about one of these four topics:

  • Debugging
  • JavaScript
  • CSS
  • HTML

The topics will be alternating, so you will get a debugging topic today, and then again in 4 days. The debugging topic came to mind, since we had some team learning session on Xdebug and looked at debugging in the browser as a follow-up. In my 6 blog posts on this topic, I will focus on the debugging in the browser.

Logging in the browser

The topic of debugging is very brought, and modern browsers offer numerous ways to debug things. So, let’s get started with something basic: logging things in JavaScript.

When you write some code in JavaScript, you might want to debug the code and see the value of certain things in the flow of a piece of code. In order to do this, you can use the console.log() function:

console.log(some_variable);

You can add this line to a JavaScript file in your (external) JavaScript code you use in your project, but you can also use this in the browser console directly. All modern browsers do have such a JavaScript console. In Chrome, you can open them with “CTRL + SHIFT + J” (Windows and Linux).

Logging some values

After opening the “Console” tab in the DevTools, you can enter any JavaScript code in the “prompt” at the end of the console. Let’s debug something here:

Screenshot of the Chrome "Console" with a line "console.log(document.location.href)" executed, showing the value "https://example.com" in the first line and "undefined" below.

In this very simple example, we are debugging the value of the current URL of the site. The first line after our executed code is the output of the console.log() function. The second line with the undefined value is the response of the function itself.

If you are using the browser console, you don’t even need to use the console.log() function. You could directly type the JavaScript code into the prompt and hit enter. The console.log() function is usually used in some (external) script on your site:

const colors = ["red", "green", "blue"];
const capitalizedColors = colors.map(item => {
	console.log(item);
	return item.charAt(0).toUpperCase() + item.slice(1);
});
console.log(capitalizedColors);

Let’s take this sample code. We have an array with colors and want to capitalize the values. We use the map() function on the array. Inside the function, we log the current item and after we have run it, we log the resulting capitalizedColors variable. The logging in the browser looks like this:

Screenshot of the Chrome "Console" three lines logging the values and an expanded array. After each line, it references the file and line it was logged at.

Since the array has three items, we see three lines with the value. At the end of each logged value, we see a reference index.html:6, which indicated the filename and line in this file the logging was done. We also see the logged array, which I already expanded by clicking on the small arrow. Chrome will even show us the length of the array and the “[[Prototype]]” for the array. If we expand this, we can see all properties and functions of the array. Here we would also find the map() function we just used.

Conclusion

That should be enough for today. Many of you will probably already know about this function. But did you know that there are more debugging functions available? We will take a closer look at some of them in the following blog posts in December.

I mainly use the Chrome DevTools, but you can also use the Firefox DevTools similarly. If you use Safari, Edge, Brave, or any other popular browser, just search for some resources on how to get started with those tools. So give it a try and debug some of your own JavaScript code.

The HTML lang attribute and how to overwrite it

Since I have stopped my current project with the new theme, I am now allowing myself to blog about other topics again. This week, I want to write about an important global HTML attribute: the lang attribute.

Maybe some of you have never (actively) used this attribute, but it’s quite important. Not only does it tell a search engine, what language the content on your website is written it, it also tells an assistive technology, like a screen reader, which voice to use when reading the text. It can even be set inline for a single word or parts of a text.

The main lang attribute however is set on the <html> tag. In WordPress, this is handled by the language_attributes() function, you would usually find in a header.php file in a classic theme. In a block theme, this is handled automatically in Core.

Reasons to overwrite the lang attribute

You would usually not want to change the value of the lang attribute, since WordPress will use the correct one, based on the language setting of your website. But there are cases in which you might want to change it.

Multilingual websites

WordPress can only have one frontend language, unless you install a multilingual plugin. I use MultilingualPress, which is based on multisite. In a WordPress multisite, you can set language per sub-site. This will automatically use the correct lang attribute in each site.

If your website does not use a multilingual plugin, but you have one page with a different language, you could overwrite the lang attribute with some code.

Loading of external code

Another use-case is when you use plugins, that would use the lang attribute to load some external data. I came across a cookie banner plugin this week, which would load the text for the banner from an external resource. It would use the exact value of the lang attribute, but it expects a value like en, so only with two characters. WordPress however is using a value like en-US, which would not work for this cookie banner. So we need to strip the second part of the value.

CSS using the attribute

A good example for a use-case in CSS is the quotes property. Different languages are using different quotation marks. When you want to use the proper quotation marks in a <q> HTML tag, you usually don’t have to do anything, since the browser will handle that for you, as the value is set to quotes: auto. But if you want to overwrite this, you could do the following:

q {
	quotes: "«" "»" "‹" "›";
}

This would always use quotes that are used in French and other languages, even if your lang attribute is set to en.

Some CSS libraries to use the lang attribute to change styles, but they might be doing it like this:

[lang="en"] q {
	/* Some styles */
}

This would not work, if the value is en-US for the lang attribute. There is the CSS :lang() pseudo-class that would work here:

:lang(en) {
	/* Some styles */
}

If you use en here, it would also work for en-US, en-GB, etc. But if you use en-US, it would not work for only en as well.

As the CSS from such a framework might be static, overwriting it might be a bit too complicated, so you might also want to change the value of the global lang attribute of the <html> tag.

How to change the value?

Let’s say, we want to change the value to a static other value for a specific page, you could do something like this:

function my_static_lang_attribute( $output ) {
	$object = get_queried_object();
	if ( $object && str_contains( $object->post_name, 'english' ) ) {
		return 'lang="en-US"';
	}

	return $output;
}

add_filter( 'language_attributes', 'my_static_lang_attribute' );

This would overwrite the lang attribute of any page/post with “english” in the permalink to lang="en-US" for the <html> tag.

As you can see from the function, the filter would not only return the value, but also the attribute name. If you look at the full code of the get_language_attributes function, you can see that the function may return other attributes like dir as well:

function get_language_attributes( $doctype = 'html' ) {
	$attributes = array();

	if ( function_exists( 'is_rtl' ) && is_rtl() ) {
		$attributes[] = 'dir="rtl"';
	}

	$lang = get_bloginfo( 'language' );
	if ( $lang ) {
		if ( 'text/html' === get_option( 'html_type' ) || 'html' === $doctype ) {
			$attributes[] = 'lang="' . esc_attr( $lang ) . '"';
		}

		if ( 'text/html' !== get_option( 'html_type' ) || 'xhtml' === $doctype ) {
			$attributes[] = 'xml:lang="' . esc_attr( $lang ) . '"';
		}
	}

	$output = implode( ' ', $attributes );

	/**
	 * Filters the language attributes for display in the 'html' tag.
	 *
	 * @since 2.5.0
	 * @since 4.3.0 Added the `$doctype` parameter.
	 *
	 * @param string $output A space-separated list of language attributes.
	 * @param string $doctype The type of HTML document (xhtml|html).
	 */
	return apply_filters( 'language_attributes', $output, $doctype );
}

And plugins could also hook into this filter, so overwriting the $output with something static might not work. Unfortunately, there is no filter to change the $lang value only, and hooking into get_bloginfo(), to overwrite the language might break some other places, where this code is used. If you want to strip the second part of the value, you could use some regular expression like this:

function my_dynamic_lang_attribute( $output ) {
	return preg_replace( '/lang="(\w+)([^"]+)"/', 'lang="$1"', $output );
}
add_filter( 'language_attributes', 'my_dynamic_lang_attribute' );

If you need something even more complex, it’s probably best to just overwrite the whole function.

Conclusion

The lang attribute is a very important attribute every website should always set. But the value might not always be, what you need it to be. In those cases, you have a filter you can use to overwrite its value, but always make sure not to return something invalid.

Too much custom CSS: I have to stop!

My last blog post was back in July. I was not able to keep my usual rate of a new blog post every two weeks. This had many different reasons, some personal and some regarding people I care about. But one other reason was the slow pace on getting my new theme ready enough. And today I have to say: stop!

I used the demo content I usually use to design a theme and tried to replicate every little element “as pixel perfect as possible”. But since I’m now at ~900 lines of custom CSS code, and this would prevent people from overwriting styles in the Site Editor, this approach is not going to be a good one.

How to continue with this project?

As my main goals were to create a theme that is usable by as many users of the original Waipoua theme as possible, with as few “migration steps” as possible, I have to realize that it’s simple not feasible. I always knew that I would also need to offer a “companion plugin” as well, preserving all the shortcodes Waipoua was offering. But is that really worth it? How many users are there still who use Waipoua and who would be brave enough to migrate?

Option 1: Offering two different versions of my theme

My first thought, even some time ago, was to offer two variants of my theme. One that would try to be almost “pixel perfect” not breaking the styles of elements on existing sites. And one that would leverage the Site Editor to its fullest, by only adding styles through the Site Editor using the theme.json file.

In this approach, the first variant would load this ~900 lines of CSS file, the second one would only load one, that is necessary to style the header with the search. Or it would not try to replicate the search exactly how it is, and instead just offers a different search in the header.

Option 2: Taking this as a learning opportunity and move on

This project was really fun! But it was also very frustrating at times. One main thing I learned from it: writing a great theme is not easy! And my respect for the work of Ellen and Manuel grew with every hour I’ve tried to replicate their work.

Going forward

I still plan to create a new theme that would look similar enough to Waipoua, so people would recognize my page, and maybe not even realize it is a different theme. If you don’t compare the new and old version side by side, and just look and the colors, fonts and structure, you will probably just think there were some minor changes in the current theme.

I really don’t like the idea to add any custom CSS to my very first theme, that cannot be overwritten in the Site Editor by any user. And I would also like to not force users to use a companion plugin to make it work with their current content. I am one of these users myself, since I have used some shortcode in old blog posts, as there was no Block Editor around that would allow you to create “buttons” or columns in the text.

Help me with your feedback!

I often ask in my blog posts for comments, and most of the time I don’t get any. But this time I would really appreciate your feedback. Even more if you use Waipoua on one of your site. What would you like me to do? Create a theme with two variants (Option 1)? Or just try to create a real Block Theme that would not try to “support legacy content” (Option 2)?