Blog

The DOM Diet and Year Pickers

I think we all know that having a smaller DOM is good for performance but I was never sure what’s considered big or small, or at what points performance is affected. Knowing a little more can change how you approach things.

I was recently doing a performance analysis on some pages and the tool I chose to use was the Chrome Performance Audit. If you open Dev Tools (F12) and go to the Audits tab you’ll see a range of available audits which includes Performance. This uses a tool called Lighthouse and gives estimates for various performance metrics as well as Opportunities and Diagnostics.

One of the diagnostics which came up for me was “Uses an excessive DOM size” and the detail gives us this:

Browser engineers recommend pages contain fewer than ~1,500 DOM nodes. The sweet spot is a tree depth < 32 elements and fewer than 60 children/parent element. A large DOM can increase memory usage, cause longer style calculations, and produce costly layout reflows.

The item that triggered this diagnostic for me was a year picker, a select element with 150 options. Whilst I don’t think it’s really causing any major performance issues it did strike me that 1 parent element and 150 children does seem excessive for just picking out one number from a consecutive range so I started looking at alternative ways we could do this. I wanted to put my year picker on a  “DOM Diet”. I created this pen:

See the Pen Year Pickers by Chris Smith (@chris22smith) on CodePen.dark

Here’s a quick comparison of 4 possible ways of selecting a year from a consecutive range. It’s important to not only look at possible DOM performance but also the user experience side – ease of understanding and ease of use. No point making it faster if it’s confusing or hard work.

Select/Dropdown

This is the standard method. It can have a default value or a blank value as the first option. It’s very familiar, ease to understand and use. It’s probably better to start with a blank value so that we know a user has actually made a selection rather than just left the default. It supports arrow keys and mousewheel. It’s easy to validate using just the required property as the available options are set. It can look untidy in some browsers when long option lists run off the bottom of the screen and it does use a lot of DOM nodes.

Range Input

The input[type=range] doesn’t show a value by default so you have to do a bit of work to show an output value, and a bit more work to do this elegantly. Through testing I found the output value had to go above the slider rather than below so it was not obscured by a finger using the control. I think this is fairly easy to understand but users may not be aware that they can use their arrow keys to get greater precision – either up/down or left/right. It can be hard to control and get the exact figure you want dragging the handle especially using a finger. It can also be wired up to support the wheel event and respond to scrolling up or down on the mousewheel. There’s no way to have a blank value so it has to have a default set. There’s no real validation to be done as it has to use a value in the range. It’s very kind to the DOM too with only 3 nodes.

Number Input

This method is very simple. You just let the user type in the date they want. It can be left blank or have a default value. It can be controlled using arrow keys or the mousewheel though I’m not sure how many users know this. By setting the min, max and step attributes it can limit the range entered when not typing. If the value is typed (or pasted) it will require validation. This uses a single DOM node.

Multiple Number Inputs

This final method is just a bit of a “left field” design. The advantage of it is that it’s very easy to update using the tab key and arrow keys. By having the digits separated the range for each is only ever 10 so in theory it should mean less to change. If left blank it could be set to automatically shift the focus to the next input when a value is added. This makes it as fast to type the 4 digits as a single number input. The min, max and step attributes can limit the range for each digit. It’s light on the DOM too with only 5 nodes. The disadvantage with this method is the validation – it’s going to be a bit more involved, parsing the 4 digits as a single value to be checked and then highlighting the invalid digit(s) could be difficult. On a mobile device with a number pad it also means the pad flashing in and out quickly, which is not a great experience so it’s only really suitable for desktop use.

I’m not sure I’d necessarily go running from the standard dropdown but some of the other methods are certainly possibilities and help keep the DOM smaller.

Why Are We Making Web Development So Hard?

I don’t think I’m the first person to think this by any stretch. There are lots of infographics around showing the difference between web tooling now and 10 years ago and it’s clearly ballooned at an extraordinary rate.

In the last year or so I’ve started working with Angular (as opposed to Angular.js a.k.a. Angular 1) and have also dabbled in Vue and React. All of these frameworks seem to share the same basic ideas – build everything as a component and push and pull them from the DOM as needed. Each component is made up of a HTML template, embedded CSS styles and a JavaScript controller.

This feels like an efficient way of working, very DRY. But is it? You create a component, let’s say a time picker. One it’s developed you can put it into multiple views or uses relatively quickly. However, if you later modify it to work slightly differently, using adding complexity, you have to test it in each use case and make sure it still works with no detrimental effects.

All UIs are basically built up of HTML, CSS and JavaScript. Traditionally HTML is for content, CSS for styling and JavaScript for reacting to user behaviour. With components we’re adding a whole load of JavaScript just to make the basic elements appear before we even get into any behavioural usage. This adds to page weight (size of files being transferred to the browser) and render times. There’s the library itself, often split into many smaller modules, plus a controller for the UI to assemble it and then the components. It could just be one HTML file, one CSS file and one JavaScript file.

Increasingly, what the developer writes in their editor is becoming further and further from what actually appears in the DOM. The frameworks insert a whole host of IDs and classes to elements, bloating the HTML and making it harder to read. Styles are inserted as inline <style> blocks rather than being cached in an external stylesheet. Opening the browser’s Dev Tools to track down and fix a problem is becoming harder, not easier.

Also, the more tools you use, the more you’ve got to maintain, keep up to date, upgrade and replace. It’s creating work just to keep up and inviting technical debt.

I think that what we’re gaining in terms of being able to develop new UI more quickly is all rooted in developer efficiency and production cost saving. It’s not thinking about the user. We’re making things slower for users. The mobile experience on most sites is still awful and the overhead of these frameworks is partly to blame.

The latest frameworks also rely on good browsers with all the JavaScript features. They do not use progressive enhancement but just grind to a halt on an older browser. This goes against the universal nature of the web – it should be easy to read and easy to write. The bells and whistles on the top is just that and should be optional, not prevent the basics from working.

I think we need to get back to making things simple. Write HTML, CSS and as little JavaScript as we can get away with. Go static wherever possible. Make it fast and simple for users. User experience should trump developer experience.

Learning Experiences as a Freelancer

I thought it might be useful to share some of my not-so-great experiences as a freelance web designer so that others can learn from my mistakes.

All Work and No Pay

What’s really frustrating is that I made the same mistake several times. That costly mistake was doing work and not getting paid for it. I’d get an enquiry for building a site by phone or email. I’d get straight back with some ideas and a quote and more often than not my quote would be accepted. I’d even have written confirmation that yes, they wanted to pay me for a website. On this basis I’d do the work and then when it came to sharing my design they’d say that they didn’t want to go ahead any more or that they’d found another designer.

It’s hard as a designer. You can get excited by a project. As soon as you finish speaking to the customer the ideas start flooding into your head and you want to capture that excitement and creativity there and then. Unfortunately, in my experience it often doesn’t actually materialise. They’re just not as serious about the project as you think they are.

My advice would be to assume that it’s just talk until you see some commitment, and by commitment I mean money. Ask for a deposit. It doesn’t have to be much, even £10 or $10 will do, but it’s just enough to prove that they’re serious. Don’t lift a finger until you’ve got a serious commitment. Trust me -you can’t afford to work for nothing.

The Price is Right

The other mistake I made was in my pricing. As I was fairly new to web design I thought I’d hit the low end of the market where I could compete on price and get lots of small cheap sites in my portfolio. It worked well for some customers but it’s surprising how many people expect you to travel to see them at your expense when you’re charging less than £100 for a website. The only way you can operate at the cheap end is by having very low outgoing costs.

Later, when I stopped being a full-time freelancer and moved into a permanent job I kept the web design going as a side line. At this point I could afford to be more picky about which projects I took on, and, without needing to be so competitive I raised my prices. In fact, I doubled my prices. Here’s the thing. I was expecting my number of enquiries to drop off. It didn’t. It pretty much doubled. I think that going too cheap was actually suggesting low quality or making people suspicious. Charging more can suggest higher quality and strangely provide some reassurance.

My advice would be to find the price that you think your service is worth and then double it. Serious customers want to buy quality services and with something like a website they’re looking for a long term relationship, not a quick handover.

Losing Focus

The third mistake I made was spending my time on the wrong things. I spent a lot of time trying to market myself rather than focusing on client work. I put a lot of hours into studying Google Analytics, SEO and building other sites to promote my main business. It would have been far more cost effective to just pay for advertising rather than commit this time. Trying to market myself by spending time and not money was a false economy. Focus on what you’re good at and pay others to do what they’re good at.

Hope that helps someone.

Super Fast Tree View in JavaScript

I thought I’d share a way of writing your JavaScript that will make a tree view hierarchy render and respond very quickly.

Firstly, the demo. I’ve got 100,000 items, quite a hefty data set, which is randomly generated in a function. You can change the number of items easily in the JS area. Click on the + or – icons to expand or collapse nodes.

See the Pen Super Fast JavaScript Data Tree by Chris Smith (@chris22smith) on CodePen.dark

It’s still quick, like instant, with 100,000 items. It can start to slow a little at a million but I’d say it’s still acceptable given that kind of data.

One Long List

The trick is in how the data is structured. It’s one big array, not hierarchical data with objects inside other objects. The reason for this is pretty simple, it’s all about iterations or looping. If you have a single array you can run through the whole list of items once. If it’s nested you have to get into loops inside other loops and it gets more complicated and takes longer. In fact, you’d be lucky for it to work at all without getting stack overflow errors.

JavaScript Magic

With a single array you can use the built in JavaScript Array methods, which are very fast – map(), filter() and some(). I’d definitely recommend reading up on these. All three work in IE9+ so hopefully you shouldn’t have to worry too much about browser support.

I use map() to convert each data item into a HTML list item which I can insert into the DOM. I use filter() to quickly find the children items of any item by returning a subset, and I use some() to see if an item has children. The beauty of some() is that once its found it child it stops iterating, saving time.

Easy on the DOM

The other part of this is keeping DOM manipulation to a minimum. Playing around with data in memory trivial for a browser but making changes to the DOM and rendering things on screen takes time. So, only the nodes that are needed right now exist in the DOM – there are not hidden items waiting on the sidelines. So, a new <ul> is added when you expand a node and the <ul> is removed when you collapse. A + icon is shown if the item has children of its own but we don’t know anything about how many it has or what they contain until it’s expanded.

More…

If you found this useful it might be worth looking at my older post Lightning Fast Filtering in JavaScript, which uses a lot of the same principles.

Stop Linking to Nowhere

Do you find yourself writing this kind of thing in your HTML?
<a href="#" onclick="doSomething()">Some action</a>

Does that href="#" make you feel slightly uncomfortable? Like it’s not really doing anything, a bit of a hack? You’d be dead right to think that.

Links are used like this all the time and there’s really no need. The intended purpose of links is to point to another location and provide navigation. That’s why the href is there. It’s pointing to another place but it’s often left pointing nowhere.

It’s probably worth pointing out that using href="#" doesn’t actually do nothing. It adds a # onto your current location, changing the URL, so when you then click the back button it appears to do nothing but is actually going back to the last location, the URL without the #. If you do use href="#" and an onclick event be sure to use event.preventDefault() with it to prevent this location change.

Links get used in this way mainly because we want the styling and the interactivity. Hovering a link gives visual cues – underline changes, cursor changes so it’s easy for a user to see it’s something they can interact with.

So, what’s the alternative? If you’re just performing an action, use a button. It has the visual cues. It doesn’t have any hacky href="#" nonsense. It can be styled however you wish if the default styling is too full-on. It can even be styled to look exactly like a link, though personally I think there’s value in differentiating between navigation and actions.

And there’s more… You get some more benefits for free with a button.

You have a disabled property. You can easily make your action unavailable. Not so easy with a link.

It’s more touch friendly. This depends on styling but out-of-the-box it’s a larger touch target.

It has an autofocus property so it can be in focus on page load without needing any JavaScript. Ready to go at the tap of the Enter key.

If you use links for navigation and buttons for actions you get every tool doing what it’s best at. You could cut your food with the side of your fork and raise it to your mouth on the side of your knife but why would you? This isn’t really so different.