Modifying Specific Letters with CSS and JavaScript
Changing specific characters can be a challenge in CSS. Often, we’re forced to implement our desired changes one-by-one in HTML, perhaps using the span element. But, in a few specific cases, a CSS-focused solution may still be possible. In this article, we’ll start by looking at some CSS-first approaches to changing characters, before considering at a scenario where we need to turn to JavaScript.
CSS
Right now, CSS doesn’t excel at targeting specific characters without making alterations to the HTML. However, there are a few scenarios where CSS could be the go-to.
@font-face
The @font-face
rule is regularly used to create custom fonts, but its unicode-range
property can also allow us to target specific characters.
For example, imagine our site often contains ampersands in its headings. Instead of using the heading font, we want something a tad more flamboyant. We can look up the unicode value of an ampersand (U
+0026
) and use unicode-range
to target this specific character.
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@300');
h1, h2, h3, h4, h5, h6 {
font-family: 'Ampersand', Montserrat, sans-serif;
}
@font-face {
font-family: 'Ampersand';
src: local('Times New Roman');
unicode-range: U+0026;
}
Try this with the following HTML to see it in action:
<h1>Jane Austen Novels</h1>
<h2>Pride & Prejudice</h2>
<h2>Sense & Sensibility</h2>
::first-letter
The ::first-letter
pseudo-element was primarily designed with drop caps in mind and it is supported by all major browsers.
p::first-letter {
font-size: 125%;
font-weight: bold;
}
Of course, this is only useful in a relatively limited number of scenarios. There have been several calls for an ::nth-letter
pseudo-element (including here on CSS-Tricks) but, right now, that’s just a pipe dream!
::after
Using the ::after
pseudo-element and content
property, we can achieve a similar effect for the final character — so long as that character is always the same. For example, here’s how we could add a jazzy, italicized exclamation point after every h2
element:
h2::after {
content: '021';
color: red;
font-style: italic;
}
font-variant-alternates
Finally, there’s the font-variant-alternates
property. This is only supported by Firefox, so it’s not recommended for production, but it may be worth knowing about for really specific scenarios: if a font happens to contain alternate glyphs, we can use this property with the character-variant()
function to select a preferred glyph for a character of our choice.
JavaScript
Turning to JavaScript doesn’t need to come at a cost to performance, especially if we run HTML-altering functions at build time. The most common use case is probably to find and replace specific characters in our HTML with a span element. For simplicity’s sake, I’ll begin with an example on the client-side, and after that we’ll look into running this at build with webpack.
Find and replace at runtime
Let’s imagine that, whenever we have the text “LOGO” in a header on our site, we want to add a special style to the first “O” character only, by wrapping it in a span
element with the class .special-o
.
const headings = document.querySelectorAll("h1, h2, h3, h4, h5, h6");
for (const heading of headings) {
heading.innerHTML = heading.innerHTML
.replace(/bLOGOb/g, 'L<span class="special-o">O</span>GO');
}
In the JavaScript above, we’re performing a find-and-replace on every heading tag.
Our regular expression uses the metacharacter b
to ensure that LOGO is always a word — rather than an element of a larger word. For example, we don’t want to match the plural “LOGOS.” Right now, it would be impossible to do this with CSS, not least because we only want to target the first “O” in the sequence.
The same principle applies if we want to replace the “O” — or even the whole word “LOGO” — with an image.
Find and replace at build
There are plenty of build tools out there, but as webpack is so popular, we’ll use that for our example — and luckily, there’s a plugin for what we need called string-replace-loader. For those new to webpack, a loader is used to preprocess files. Here, we can perform a find-and-replace on specific files as part of our build.
First, we need to install the plugin:
npm install --save-dev string-replace-loader
Then, inside webpack.config.js
add:
module.exports = {
// ...
module: {
rules: [
{
test: /.html$/i,
loader: 'string-replace-loader',
options: {
search: '/bLOGOb/g',
replace: 'L<span class="special-o">O</span>GO',
}
}
]
}
}
By changing the test
property value, we could target JSX, TSX, PUG, Handlebars or any other templating file format:
/.html$/i # HTML
/.[jt]sx$/i # JSX or TSX
/.pug$/i # PUG
/.handlebars$/i # Handlebars
The advantage of this approach is that no unnecessary JavaScript will run in our client’s browser.
Final note
Finally, if you’re comfortable creating and editing fonts and would rather avoid CSS or JavaScript, a custom font could be a solution for many of the scenarios set out above. There are plenty of free font-editing tools such as Font Forge or Birdfont for those who want to try this more design-focused approach.
The post Modifying Specific Letters with CSS and JavaScript appeared first on CSS-Tricks.
You can support CSS-Tricks by being an MVP Supporter.