Photo by Quino Al on Unsplash
In my latest side project, I have two main goals:
- To learn TypeScript properly by vowing to never use the
- To make the app as web accessible as possible.
Number 2 means that all of the functionality of the web app should be easily accessible to keyboard users, hearing-impaired users and sight-impaired users. This is making development take a fair bit longer than it usually would, but it’s a good learning exercise for me, and I think it’s something we (as developers) should all be mindful of.
When it came time to build a form, I took a lot of inspiration from the form designs we use at flaik, but I wanted to improve a few things.
Firstly, each input field at flaik has a number of nested divs to achieve the desired aesthetic look. I think they are unnecessary and only make the HTML cluttered. I wanted to use CSS in a way that would reduce the number of div elements needed.
Secondly, while using CSS transitions can make the UX much better, not all CSS properties are treated equally when it comes to transitions. For example, using CSS transitions on color, font-size, height, width etc require the browser to repaint for each frame which isn’t performant at all. However using CSS transitions on transforms like translateX, translateY, scale and rotate don’t require repaints and can actually use the GPU to handle the transitions.
Thirdly, as I’m not a hearing impaired, or sight impaired person, I researched quite a bit into how to make the form accessible, which mostly boils down to following best practices like ensuring each input field has a label. I also wanted to make sure I didn’t remove any important hover/focus styling which keyboard only users use to see which input field they are editing.
As I’m building my app in React, I originally build this form as a React component. But I then refactored it to CodePen and removed any dependencies on frameworks, it’s just straight HTML/CSS/JS.
I’m super happy with the end result.
The HTML is nice and simple, with just a HTML form element, and just a single container div surrounding each label and input combo.
Using absolute positioning, I was able to position the label on top of the input such that it looks like the input placeholder - but the HTML markup is still as you would expect with the two elements being siblings so screen readers will understand it.
blur events which adds and removes a
hasValue class to the input container div. It was important to put the classes on the container and not the input element itself, because then styling the label later on becomes much easier.
I really really like these transitions. Instead of transitioning the font-size and the line-height and maybe the top and left positions, which would cause a lot of re-painting by the browser and potentially janky transitions, I instead used the
transform property, and translated the X and Y position, and scaled the font down to give the effect of reducing the font size.
One problem I had at first, was by scaling the label down, it would scale vertically like I wanted, but the horizonal scale would be dependant on how long the label text was. This meant that as the transition started moving the label up towards the top of the input box, it would also start moving along the x axis different distances depending on how long the label text was.
transform-origin CSS property is what came to the rescue. The
transform-origin property sets the point around which a transformation is applied, so by setting it to left (
transform-origin: left;), that meant that the left side of the text became fixed, and when the label scaled down, it still scaled horizontally, but only the right side scaled in. Perfect.
Furthermore, by reducing the number of CSS properties that are transitioning, I was able to make better use of the CSS
will-change property, which tells the browser which properties are going to change so it can make further optimizations. Bonus.
I hope you enjoy the form, and if there are any accessibility things you think I missed, please reach out to me.