Crossing out text diagonally

31st Jul 2017

Utilities

cssjavascriptnpm

While CSS provides a method for putting a strikethrough on text using text-decoration: line-through;, there isn't any inbuilt function for a diagonal line through text, or a method that allows you to style that strikethrough. Recently I had to come up with a solution to this similar to the following design:

crossout image

There were three main methods that I could think of for going about this:

Linear Gradient background

By utilising the linear-gradient CSS background property you could create a crossout effect on a piece of text, example code:

.crossedout {
    background: linear-gradient(to left top, transparent 47.75%, currentColor 49.5%, transparent 52.25%);
}

The width could be altered by fiddling with the percentages of the transparent sides and the colour could be changed by changing currentColor to whatever colour is desired. However, there were a few drawbacks with this method:

  • Altering percentages to change thickness is awkward
  • Cross-out will be behind text
  • Aliasing at larger sizes
  • Angle cannot be changed

Pseudo-element :after/:before

You can configure one of the pseudo-elements on the text to act like a line over the top of the text using the transform CSS property. Example:

.crossout {
    display: inline-block;
}
.crossout:after {
    content: '';
    display: inline-block;
    position: absolute;
    top: 0; right: 0; bottom: 0;
    margin: auto;
    width: 100%;
    transform: rotate(-9deg);
    height: 2px;
    background-color: #000000;
}

For this, the thickness can be modified with the height property, colour with the backgroundColor property and angle with the transform property. So this looks like a very appealing method, however the angle is different for each text height, for example this -9deg angle may work for 16px font size but will be too thin for 32px font size, or a thinner font. So perhaps a JavaScript solution to automatically set the angle property depending on the text height and width. However, JavaScript cannot access pseudo-elements so while it will mean more markup, additional spans will need to be used

Inner span

The inner span's CSS is defined much the same way, albeit without the content property. But this allows us to now access the line and modify it via JavaScript to match the angle up or dynamically change any other property. To calculate the necessary angle in JavaScript, some simple trigonometry can be used:

var h = el.offsetHeight;
var w = el.offsetWidth;
var rotation = mult * (Math.atan(h / w) * (180/Math.PI));

Where el is the text we're crossing out. The mult variable is either -1 or 1 depending on whether we want the line to go from bottom left to top right (-1) or top left to bottom right (1). From this code, it is possible to expand the functionality into a small library that can programmatically cross out text. So I built the crossout.js library (https://github.com/DanFoad/crossout.js). This library can be either just included in your scripts folder or required via npm (install using npm install crossout).

The crossout.js library crosses out any text in a span with a data attribute of data-crossedout and allows for a host of local or global settings to change the thickness, color, direction etc. All of which is described in the readme in the repo or on the npm package page.