0

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.

Offset stroked text

starball
  • 20,030
  • 7
  • 43
  • 238
dooblr
  • 458
  • 1
  • 5
  • 18

2 Answers2

1

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>
herrstrietzel
  • 11,541
  • 2
  • 12
  • 34
granite
  • 304
  • 4
  • This is pretty good but i'd like to have the space between the inner text and outer text be transparent, so the (animated) background shows through. – dooblr Jan 27 '23 at 03:12
0

Multiple text strokes with pseudo elements

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;
  });

Reusable svg filter

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>
herrstrietzel
  • 11,541
  • 2
  • 12
  • 34