Lighthouse - Optimize your website, Part 3: Best practices

So how did 3 weeks just pass by like that? My original plan was to post every Tuesday but sometimes work and life just gets in the way. Time flies! 😉

But now I’ve got part 3 in the “Lighthouse — Optimize your website” ready for you. Today it’s time to take a look at the “Best practices” part — a great mix of UX and security.

For the sake of this post I’ve created a very bad test page for you right here: http://test.frontenddesigner.dk/lighthouse_best-practices.html. The score speaks for it self:

Low score in Lighthouse, Best Practices.

On the page I created I’ve got issues in these 4 categories:

  • Trust and Safety

  • General

  • User Experience

  • Browser Compatibility

Let’s take a look at why my page performs so badly in the “Best practices” category.

Trust and Safety

This is a very important part of your website. If your website isn’t safe — and if user don’t trust your site — you site will likely never be performing at it’s best. I’ve got three issues on my test page:

  • Does not use HTTPS

  • Does not redirect HTTP traffic to HTTPS

  • Requests the notification permission on page load

Does not use HTTPs and does not redirect HTTP traffic to HTTPS

The first two is related, but not exactly the same. You can use HTTPS, but still don't redirect traffic from HTTP to HTTPs.

To fix the issue with HTTPS all you have to do is install a SSL certificate on your server and attached it to your site. I often host small and simple sites at simply.com where you can easily setup a free Let’s Encrypt certificate on your site: https://www.simply.com/dk/support/faq/1/123/ (article in Danish).

If you want to use Let’s Encrypt on a server you have access to, you can install https://www.win-acme.com/ which allows you to create certificates for sites on your server.

To make sure your site redirects traffic from HTTP to HTTPS you most likely have an option in your CMS (if you use one) to redirect the traffic. If not, it can easily be set in a web.config file:

<configuration>
	<system.webServer>
		<rewrite>
			<rules>
				<rule name="RedirectToHTTPS" stopProcessing="true">
					<match url=".*" />
					<conditions logicalGrouping="MatchAll">
						<add input="{HTTP_HOST}" pattern='"ocalhost" negate="true" />
						<add input="{HTTPS}" pattern="off" ignoreCase="true" />
					</conditions>
					<action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" redirectType="Permanent" appendQueryString="false" />
				</rule>
				<!-- Any other rules here. -->
			</rules>
		</rewrite>
	</system.webServer>
</configuration>

If you’re on a PHP platform you can do the same in a .htaccess file. I haven’t worked much with PHP, so I’ll lead you in another direction here 😉 Here's a Google search for HTTPS redirect in .htaccess.

Requests the notification permission on page load

Last item in the Trust and Safety part is the “Requests the notification permission on page load”. This is quite simple to fix. Just don’t ask for permissions for notifications on page load 😉

I see a lot of pages doing this as the first thing when you enter their website. To me it’s just annoys me — there’s no way I would accept notifications at this point. Maybe later, if i find the page relevant and useful to me. But asking for the permissions right away just leaves me with a bad first impression. And I guess that’s exactly what Lighthouse means, when they tell us:

Users are mistrustful of or confused by sites that request to send notifications without context. Consider tying the request to user gestures instead.

My code to request permission for notifications looks like this:

Notification.requestPermission().then(function(result) {
	console.log('Notification permission:', result);
});

Don’t do that! Wait for the user to interact with your site — and ask them in other ways if they would like notifications about news on your site. You can do it with regular content, that triggers the requestPermission() when clicking on a button instead:

<button id="notifyMe">Notify me!</button>
<script>
	const button = document.getElementById('notifyMe');

	button.addEventListener('click', function() {
		Notification.requestPermission().then(function(result) {
			console.log('Notification permission:', result);
		});
	});
</script>

General

In this part I’ve got to issues to fix on my test page:

  • Uses deprecated API’s

  • Browser errors were logged to the console

Uses deprecated API’s

Deprecated APIs is APIs that might be removed in newer versions of the browsers — or API’s that are no longer available on an insecure origin (a page without a SSL Certificate). In my example I actually have to issues related to this:

  • I’m trying to use the Notification API (as shown above in the Trust and Safety part) on an insecure origin (I don’t use HTTPS on my test site)

  • I’m trying to use “getCurrentPosition()” from the navigator.geolocation

For both of these I need to be on a secure origin and as with the Notification API it also goes for the Geolocation API. Don’t ask right away — ask when it makes sense for the user. It could be on a page where you’d like the user to interact with a Google Map.

Browser errors were logged to the console

This indicates that you’ve probably got some code not working like supposed to. In my example I’ve got this code:

console.log(testObject.testValue);

The problem with this is that I haven’t declared my “testObject” anywhere — it doesn’t exist — but still I’m trying to read the “testValue” of the object. Naturally this gives me an error in the console:

Uncaught ReferenceError: testObject is not defined

To fix this issue, remember to always make sure that what you are trying to read from — in this case the “testObject” — exists:

if (typeof testObject !== 'undefined') {
	console.log(testObject.testValue);
}

In this case, the property testValue might be null or undefined, but you know that testObject exists before trying to read from it.

User Experience

I’ve just got a single issue in this part:

  • Does not have a tag with “width” or initial-scale

If you don’t have this meta tag — or if you have it with an initial-scale with a value less than 1, you’ll end up having a website with a 300 ms. tap-delay for users.

To prevent this from happening, you just have to add this inside the elements:

<meta name="viewport" content="width=device-width, initial-scale=1.0" />

Browser Compatibility

Let’s have a look at the issues I’ve got in the Browser Compatibility part:

  • Page lacks the HTML doctype, thus triggering quicks-mode

  • Charset declaration is missing or occurs too late in the HTML

Page lacks the HTML doctype, thus triggering quicks-mode

What-mode? Quirks-mode! We really have to travel way back in internet-time to find the origin of the “Quirks-mode”. It’s from way back in the day where there was no standard and sites was developed in two versions; one for Netscape Navigator and one for Internet Explorer.

To fix this issue, nowadays we simply just put this doctype declaration at the top of out document:

<!DOCTYPE html>
<!-- THE REST OF THE DOCUMENT -->

Charset declaration is missing or occurs too late in the HTML

It’s all about character(s)! Without a charset the browsers won’t always now what each byte represents and you might have issues with ÊÞÄ (in Danish) and a lot of other special characters.

You fix it by putting a charset inside the head tags:

<meta charset="UTF-8" />

Note that a charset declaration that appears to late in the HTML might cause some issues. Google says:

Note: Theoretically, a late element (one that is not fully contained in the first 1024 bytes of the document) can also significantly affect load performance. See Issue #10023.

Final result

Let’s have a look at the final result. I’ve created another test page where everything from the report is fixed. You can have a look here: https://test.frontenddesigner.dk/lighthouse_best-practices-fixed.html

The score is now 100 / 100. Accomplished by doing a few simple things:

  • Install a SSL Certificate

  • Redirect traffic from HTTP to HTTPS

  • Remove code that asks for permissions to the Notification API instantly on page load

  • Remove use of deprecated API’s (actually fixed by installing a SSL Certificate and changing requests to the Notification API and the Geolocation to be triggered on a button click instead of on page load)

  • Making sure objects exists in JavaScript, before trying to read from them

  • Adding a tag to the head element

  • Adding a doctype to the HTML

  • Adding a charset declaration to the head element

100 in Lighthouse, Best Practices.

That’s it for today. Reach out at [email protected] if you have any input to this post or if you’d like me to dig into a specific area of frontend development.