How would you recreate this effect where there are multiple layers of strokes on text? Is it possible with only one element and CSS?
webkit-text-stroke
does not seem to be able to provide the offset I need.
This should get you close to a solution (just create several layers of the same text, one on top of the other, and put a different stroke on each). You will need to use a rounded font (otherwise it will show as sharp edge text on Edge and Chrome):
body {
background-color: #eff;
font-family: 'Arial Rounded MT', 'Comic Sans MS', 'Cooper', Arial, sans-serif;
}
.container {
width: 300px;
}
p {
position: absolute;
font-size: 7em;
font-weight: 600;
text-stroke: 4px black;
-webkit-text-stroke: 4px black;
}
.stroke {
text-stroke: 30px black;
-webkit-text-stroke: 30px black;
}
.no-stroke {
text-stroke: 20px white;
-webkit-text-stroke: 20px white;
}
<div class="container">
<p class="stroke">Stroke</p>
<p class="no-stroke">Stroke</p>
<p>Stroke</p>
</div>
You could also use :before
and :after
pseudo elements to create multiple stacked text-strokes.
Explained by @Luke Taylor's: "Text Stroke (-webkit-text-stroke) css Problem"
But you also need to create a data-attribute containing the current text:
<h1 class="stroked" data-content="stroke pseudo elements">stroke pseudo elements</h1>
.stroked:before{
content: attr(data-content);
position: absolute;
left:0;
-webkit-text-stroke: 0.15em #000;
pointer-events: none;
z-index:-10;
}
You can automate this by a litte javaScript copying all text to the data attribute:
let textOutline = document.querySelectorAll(".stroked");
textOutline.forEach((text) => {
text.dataset.content = text.textContent;
});
You'll need to inline an invisible <svg>
element with your filter definition.
Then you can apply this filter by ID like so:
.strokedSvg{
color:magenta;
filter: url(#inset);
font-style:italic;
}
Example based on @defghi1977's answer: Using SVG filter to create an inside stroke
let textOutline = document.querySelectorAll(".stroked");
textOutline.forEach((text) => {
text.dataset.content = text.textContent;
});
body {
background-color: #000;
font-family: Arial, "Comic Sans MS", sans-serif;
font-size:2em;
margin:2em;
}
.strokedSvg{
color:magenta;
filter: url(#inset);
font-style:italic;
}
.stroked{
position: relative;
font-style:italic;
}
.stroked, .stroked:before, .stroked:after{
color:magenta;
}
.stroked:before, .stroked:after{
content: attr(data-content);
position: absolute;
top:0;
left:0;
pointer-events: none;
display:block;
width:100%;
}
.stroked:before{
-webkit-text-stroke: 0.15em #000;
z-index:-10;
}
.stroked:after{
-webkit-text-stroke: 0.2em #fff;
z-index:-20;
}
<!--
using data attribute for pseudo elements:
Based on: @Luke Taylor's answer :
https://stackoverflow.com/questions/69253420/text-stroke-webkit-text-stroke-css-problem/69937834#73146972
-->
<h1 class="stroked" data-content="">stroke pseudo elements</h1>
<h1 class="stroked" data-content="">stroke pseudo elements2</h1>
<h1 class="strokedSvg">stroke svg filter</h1>
<!--
based on @defghi1977 answer: Using SVG filter to create an inside stroke
https://stackoverflow.com/questions/42443730/using-svg-filter-to-create-an-inside-stroke#42449363
-->
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<filter id='inset' x='-50%' y='-50%' width='200%' height='200%'>
<!--outside-stroke-->
<feFlood flood-color="white" result="outside-color"/>
<feMorphology in="SourceAlpha" operator="dilate" radius="7"/>
<feComposite in="outside-color" operator="in" result="outside-stroke"/>
<feFlood flood-color="black" result="mid-color"/>
<feMorphology in="SourceAlpha" operator="dilate" radius="5"/>
<feComposite in="mid-color" operator="in" result="mid-stroke"/>
<!--fill-area-->
<feMorphology in="SourceAlpha" operator="dilate" radius="2"/>
<feComposite in="SourceGraphic" operator="in" result="fill-area"/>
<!--merge graphics-->
<feMerge>
<feMergeNode in="outside-stroke"/>
<feMergeNode in="mid-stroke"/>
<feMergeNode in="fill-area"/>
</feMerge>
</filter>
</defs>
</svg>