Similar Dynamically created SVG elements are not rendered by the browser but my code already corresponded to their solutions.
I am trying to use SVG markup in my HTML in order to render some texts. The problem was very tricky because I just realized that the issue is when generating the SVG programmatically.
The markup
What I want to end up in my page is this fragment of code:
html {
background-color: #151515;
color: white;
background-image: url(https://picsum.photos/id/210/500/500);
background-size: 500px 500px;
}
body {
margin: 0;
padding: 0;
}
#navbar {
font-family: 'Katahdin Round', 'Arial Narrow Bold', sans-serif;
list-style: none;
}
#navbar .letter-path {
fill: white;
stroke: transparent;
stroke-width: 2.5;
stroke-dasharray: 400;
stroke-dashoffset: 400;
transition: fill 0.1s ease-in 0.1s, stroke 0.25s ease-out, stroke-dashoffset 0s linear 0.25s;
}
#navbar svg:hover .letter-path {
fill: rgba(255, 255, 255, 0.3);
stroke: white;
stroke-dashoffset: 0;
transition: fill 0.25s ease-out, stroke 0s, stroke-dashoffset 0.5s ease-in 0.1s;
}
#blurred-clip-background {
clip-path: url(#blur-letter-paths);
filter: blur(3px);
}
<body>
<ul id="navbar" class="relative inline-block">
<li><svg xmlns="http://www.w3.org/2000/svg" height="100" viewBox="0 0 279.468 100">
<defs>
<path id="letter-path-0" class="letter-path-T"
d="M27.934 79.496c-3.127 0-4.69-1.564-4.69-4.69V22.06H7.19c-3.127 0-4.691-1.563-4.691-4.69V7.05c0-3.127 1.563-4.69 4.69-4.69h51.807c3.127 0 4.69 1.563 4.69 4.69v10.32c0 3.127-1.563 4.69-4.69 4.69H42.944v52.744c0 3.127-1.563 4.69-4.69 4.69z"
transform="translate(0, 0)"></path>
<path id="letter-path-1" class="letter-path-E"
d="M56.6 74.805c0 3.127-1.564 4.69-4.692 4.69H7.191c-3.127 0-4.691-1.563-4.691-4.69V7.051c0-3.127 1.563-4.69 4.69-4.69h44.718c3.128 0 4.691 1.563 4.691 4.69v10.32c0 3.127-1.563 4.69-4.69 4.69H22.2v9.694h21.89c3.127 0 4.69 1.564 4.69 4.69v8.861c0 3.127-1.563 4.69-4.69 4.69H22.2v9.8h29.707c3.128 0 4.691 1.563 4.691 4.69z"
transform="translate(69.187, 0)"></path>
<path id="letter-path-2" class="letter-path-X"
d="M38.05 23.104l11.987-17.72c1.356-1.981 3.336-3.024 5.733-3.024h13.342c3.857 0 5.212 2.502 3.023 5.733L49.933 40.615l22.515 33.148c2.19 3.231.833 5.733-3.023 5.733H56.083c-2.397 0-4.378-1.042-5.734-3.023l-12.3-18.241-12.404 18.241c-1.356 1.98-3.335 3.023-5.733 3.023H6.57c-3.857 0-5.212-2.502-3.023-5.733l22.515-33.148L3.86 8.093C1.67 4.862 3.027 2.36 6.883 2.36h13.342c2.396 0 4.378 1.043 5.733 3.023z"
transform="translate(131.286, 0)"></path>
<path id="letter-path-3" class="letter-path-T"
d="M27.934 79.496c-3.127 0-4.69-1.564-4.69-4.69V22.06H7.19c-3.127 0-4.691-1.563-4.691-4.69V7.05c0-3.127 1.563-4.69 4.69-4.69h51.807c3.127 0 4.69 1.563 4.69 4.69v10.32c0 3.127-1.563 4.69-4.69 4.69H42.944v52.744c0 3.127-1.563 4.69-4.69 4.69z"
transform="translate(210.281, 0)"></path>
<clipPath id="blur-letter-paths">
<use href="#letter-path-0"></use>
<use href="#letter-path-1"></use>
<use href="#letter-path-2"></use>
<use href="#letter-path-3"></use>
</clipPath>
</defs>
<image id="blurred-clip-background" x="-40" y="-16" width="500" height="500"
href="https://picsum.photos/id/210/500/500"></image>
<use href="#letter-path-0" class="letter-path"></use>
<use href="#letter-path-1" class="letter-path"></use>
<use href="#letter-path-2" class="letter-path"></use>
<use href="#letter-path-3" class="letter-path"></use>
</svg></li>
<!-- <li>PROJECTS</li>
<li>CONTACT</li> -->
</ul>
<!-- <script src="script.js"></script> -->
</body>
If you take this and paste it inside a page, all is fine and the text is rendered!
Creating the SVG dynamically
But I want to create this content using JavaScript, so I have this:
// Dictionary of paths for each letter
const letterPaths = {
E: "M56.6 74.805c0 3.127-1.564 4.69-4.692 4.69H7.191c-3.127 0-4.691-1.563-4.691-4.69V7.051c0-3.127 1.563-4.69 4.69-4.69h44.718c3.128 0 4.691 1.563 4.691 4.69v10.32c0 3.127-1.563 4.69-4.69 4.69H22.2v9.694h21.89c3.127 0 4.69 1.564 4.69 4.69v8.861c0 3.127-1.563 4.69-4.69 4.69H22.2v9.8h29.707c3.128 0 4.691 1.563 4.691 4.69z",
T: "M27.934 79.496c-3.127 0-4.69-1.564-4.69-4.69V22.06H7.19c-3.127 0-4.691-1.563-4.691-4.69V7.05c0-3.127 1.563-4.69 4.69-4.69h51.807c3.127 0 4.69 1.563 4.69 4.69v10.32c0 3.127-1.563 4.69-4.69 4.69H42.944v52.744c0 3.127-1.563 4.69-4.69 4.69z",
X: "M38.05 23.104l11.987-17.72c1.356-1.981 3.336-3.024 5.733-3.024h13.342c3.857 0 5.212 2.502 3.023 5.733L49.933 40.615l22.515 33.148c2.19 3.231.833 5.733-3.023 5.733H56.083c-2.397 0-4.378-1.042-5.734-3.023l-12.3-18.241-12.404 18.241c-1.356 1.98-3.335 3.023-5.733 3.023H6.57c-3.857 0-5.212-2.502-3.023-5.733l22.515-33.148L3.86 8.093C1.67 4.862 3.027 2.36 6.883 2.36h13.342c2.396 0 4.378 1.043 5.733 3.023z",
};
const letterWidths = {
E: 54.099,
T: 61.187,
X: 70.995,
}
// Letter spacing constant
const LETTER_SPACING = 8;
const HEIGHT = 100;
// Function to create SVG for a word
function createWordSVG(word)
{
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
const defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
clipPath.setAttribute('id', 'blur-letter-paths');
const image = document.createElementNS('https://www.w3.org/2000/svg', 'image')
image.setAttribute('id', 'blurred-clip-background');
image.setAttribute('x', '-40'); // TODO: dynamic depending on svg pos
image.setAttribute('y', '-16'); // TODO: dynamic depending on svg pos
image.setAttribute('width', '500');
image.setAttribute('height', '500');
image.setAttribute('href', 'https://picsum.photos/id/210/500/500'); // xlink:href didn't work either
svg.appendChild(defs);
svg.appendChild(image);
let totalWidth = 0;
word.toUpperCase().split('').forEach((letter, index) =>
{
if (letterPaths[letter])
{
defs.appendChild(createLetterPath(letter, index));
clipPath.appendChild(createLetterUse(index, false))
svg.appendChild(createLetterUse(index, true))
totalWidth += letterWidths[letter] + LETTER_SPACING;
}
});
defs.appendChild(clipPath);
function createLetterPath(letter, index) {
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
path.setAttribute("id", `letter-path-${index}`)
path.setAttribute("class", `letter-path-${letter}`)
path.setAttribute("d", letterPaths[letter]);
path.setAttribute("transform", `translate(${totalWidth}, 0)`);
return path
}
function createLetterUse(index, isPath) {
const use = document.createElementNS('http://www.w3.org/2000/svg', 'use');
use.setAttribute("href", `#letter-path-${index}`)
if (isPath) {
use.setAttribute("class", `letter-path`)
}
return use
}
svg.setAttribute("height", `${HEIGHT}`);
svg.setAttribute("viewBox", `0 0 ${totalWidth} ${HEIGHT}`);
return svg;
}
// Main function to replace text in list items with SVGs
function replaceTextWithSVG()
{
const listItems = document.querySelectorAll('li');
listItems.forEach(li =>
{
const text = li.textContent.trim();
const svg = createWordSVG(text);
li.textContent = ''; // Clear the text
li.appendChild(svg);
});
}
// Call the function when the document is ready
document.addEventListener('DOMContentLoaded', replaceTextWithSVG);
html {
background-color: #151515;
color: white;
background-image: url(https://picsum.photos/id/210/500/500);
background-size: 500px 500px;
}
body {
margin: 0;
padding: 0;
}
#navbar {
font-family: 'Katahdin Round', 'Arial Narrow Bold', sans-serif;
list-style: none;
}
#navbar .letter-path {
fill: white;
stroke: transparent;
stroke-width: 2.5;
stroke-dasharray: 400;
stroke-dashoffset: 400;
transition: fill 0.1s ease-in 0.1s, stroke 0.25s ease-out, stroke-dashoffset 0s linear 0.25s;
}
#navbar svg:hover .letter-path {
fill: rgba(255, 255, 255, 0.3);
stroke: white;
stroke-dashoffset: 0;
transition: fill 0.25s ease-out, stroke 0s, stroke-dashoffset 0.5s ease-in 0.1s;
}
#blurred-clip-background {
clip-path: url(#blur-letter-paths);
filter: blur(3px);
}
<body>
<ul id="navbar" class="relative inline-block">
<li>TEXT</li>
<!-- <li>PROJECTS</li>
<li>CONTACT</li> -->
</ul>
<script src="script.js"></script>
</body>
Well, try to execute this in fiddle or in your browser and you’ll see it will not be rendered. When you inspect the HTML, you see that the -tag is not taking any space.
What is the problem?
This post is almost the same as the one made by Andry a while ago, where the problem was the creation of svg-elements using createElement
instead of createElementNS
. This isn’t my problem though, because in my case all svg-elements are already generated using the correct way. This becomes apparent, because everything else works, not the -tag though.