I am trying to wrap the first letter of each word in my heading tags with a span class so that I can style them using CSS. I have tried to use a snippet I've found on here, but I have 2 h1 tags and it is taking the first one and repeating it for the second!
The function is this:
<script>
$(document).ready(function() {
var words = $('h1').text().split(' ');
var html = '';
$.each(words, function() {
html += '<span class="firstLetter">' + this.substring(0, 1) + '</span>' + this.substring(1) + ' ';
$('h1').html(html);
});
});
</script>
So I have an h1 in the banner at the top, and another one at the start of the content, but the function is taking the top banner heading and replacing the content heading with it, but the span class is working!
I know you shouldn't have 2 h1s, but I want to target all headings anyway, and its a CMS for a client so I can't guarantee they won't use multiple h1 going forwards, so I am testing it out!
Recursively loop over the text nodes inside the headings and then wrap the words within a span and replace the text node with a container span that holds all the wrapped words.
Then style the first letter of these spans using the ::first-letter CSS pseudo element.
NOTE:
Directly replacing the innerHTML of the headings might cause bugs if the headings have elements in them.
For ex: In the snippet below, the headings have some elements within them. The first one has an anchor element and the second one has an svg and these are common use cases. But if you directly replace the innerHTML of these headings that would eliminate these elements inside them, which is not desired. So, it's essential that you only wrap the text nodes within a span.
::first-letter only works with block-level elements, so you need to set the display property of spans to inline-block.
const headingEls = document.querySelectorAll("h1");
function wrapWithSpan(node) {
if (node.nodeName === "#text") {
const containerSpan = document.createElement("span");
containerSpan.innerHTML = node.textContent
.split(" ")
.map((word) => `<span class="word-span">${word}</span>`)
.join(" ");
node.parentNode.replaceChild(containerSpan, node);
} else {
Array.from(node.childNodes).forEach(wrapWithSpan);
}
}
headingEls.forEach(wrapWithSpan);
a[href^="#"] {
display: inline-block;
text-decoration: none;
color: #000;
}
a[href^="#"]:hover,
a[href^="#"]:hover *,
a[href^="#"]:focus,
a[href^="#"]:focus * {
text-decoration: underline;
}
a[href^="#"]:hover::after,
a[href^="#"]:focus::after {
color: #aaa;
content: "#";
margin-left: 0.25rem;
font-size: 0.75em;
}
h1 .word-span {
display: inline-block;
}
h1 .word-span::first-letter {
color: palevioletred;
text-transform: uppercase;
}
<h1 id="heading"><a href="#heading">Heading with link</a></h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
<h1>Heading with SVG <svg height="20" width="20"><circle cx="10" cy="10" r="10" fill="green" /></svg></h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
If you just want to style the first letter of each heading, you don't need JS, you can do it by using only the ::first-letter CSS pseudo element.
a[href^="#"] {
text-decoration: none;
color: #000;
}
a[href^="#"]:hover,
a[href^="#"]:focus {
text-decoration: underline;
}
a[href^="#"]:hover::after,
a[href^="#"]:focus::after {
color: #aaa;
content: "#";
margin-left: 0.25rem;
font-size: 0.75em;
}
h1::first-letter {
color: palevioletred;
text-transform: uppercase;
}
<h1 id="heading"><a href="#heading">Heading with link</a></h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
<h1>Heading with SVG <svg height="20" width="20"><circle cx="10" cy="10" r="10" fill="green" /></svg></h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With