The CSS border property is great for adding stroke outlines to your elements, but it offers little flexibility when working with dashed borders. For example, you can't customise dash lengths, gaps between dashes, or even the caps on each dash.
To overcome this, we'll be writing our own dashed border renderer using the new CSS Houdini Paint API. The full code is available at the end of the post and on GitHub here.
Final result |
Note that as of 2021, the Paint API is not supported by Firefox or Safari, so if this feature is mission-critical to your project in these browsers, you might want to look for alternatives. Support tables for the API can be found here.
Writing a Custom Paint Class
To start with, we need to create a class that handles all the custom painting we'll be doing. It will be responsible for exposing available properties and drawing the actual borders themselves.
As you can see, the class has a method that returns all properties we'd like to use, and another method that takes in a drawing context to handle the painting. The context that is being passed works exactly like the 2D context of a canvas, so our code will look familiar to you if you have worked with canvases before.
Defining Custom Properties
Custom properties let us pass configuration options to the renderer. In our case, we would like to have properties to modify the colour, width (thickness), length, border radius, gap, and cap of the dashes. We'd thus have to edit the inputProperties getter like so:
These properties can now be set like any other CSS variables in our CSS declaration. We will discuss this in detail below when we actually use the renderer in our stylesheets.
Setting up the Paint Method
Next, we need to access these properties from inside the paint() method and format them for further use. It is important to note that all properties are inferred as literals, meaning using 40% in your stylesheet does not automatically convert to the computed value for that percentage. Thus, we have to manually parse any integers and trim any strings we wish to use while rendering.
The props argument of the paint() method contains all the properties used in the selector. We can query them using props.get(), as shown.
We also provide default values if no properties are defined in the selector.
Drawing the Border
Now that we have everything ready, it is time to start drawing the actual border! We will approach the edges first, and then deal with each corner separately.
The gist of the drawing algorithm is to draw many small lines along the edges with a set gap between them.
We first start with the left edge, as you can see below
The same can be replicated for all four edges.
Drawing Corners
To draw corners, we will make use of the arc() method of the context. The process is simple: we start with an initial arc angle, draw an arc up to a small increment of this angle, skip a few degrees to achieve the "gap", and continue this till we reach the end angle.
The same can be done for all four corners, as shown.
Note that for the top right corner we start from 2PI and move to 1.5PI. This is equivalent to moving from 0PI to 1.5PI.
That's it! We've successfully written our custom renderer class! All that's left now is to register it and use it in CSS.
Registering the Class
Before we can use our new border function, we need to register it with the CSS Paint API. To do this, add this code in the same file where your class is.
The first parameter is the name of the paint function. This is the name we will be using in our CSS stylesheets.
Finally, make sure to add the JavaScript file you've written the renderer in as a module. I've placed it in my main.js file, but you can add it anywhere.
Using in CSS
We can now use our custom border function in CSS! To apply these borders, use the following properties in the required selector:
And that's all! Your custom borders should now appear on any element with the class .dashed!
If you enjoyed this guide, do follow for more!
Comments
Post a Comment