2

Although I've found similar questions, none explicitly match my goal.

I'm trying to display text with a gradient colour, with low opacity (so you can see the background through it), but also with a (matching) solid gradient border (i.e. text-stroke). I've discovered that answers to similar questions develop a workaround by creating a ::before underlay state that replicates a (gradient) border effect, but changing the opacity on the text's natural state just displays the colour of the ::before underlay text instead of the background colour (the desired result).

What I'm wondering is, is there any workaround to effectively create a solid gradient text-stroke with (internal) gradient text that has an opacity lower than 1?

Using the aforementioned other similar questions, I've developed the following code over a period of hours but can't quite figure out how it can be done. You'll notice in my code that I've used different rgba values - this was simply done to view the result more easily and see if I acheived my intended goal of making the (internal) text have opacity (to enable the background to be seen), as opposed to using identical colours. The more opacity I apply, the more you can see the gradient colours of the workaround/makeshift text-stroke.

body {
  background: #000000;
}

h1 {
  font-size: 60px;
  font-weight: 800;
  font-family: arial;
  color: rgb(255, 255, 255);
  background-image: linear-gradient(to left,
      rgba(255, 0, 0, 0.7),
      rgba(0, 0, 255, 0.7),
      rgba(255, 0, 0, 0.7));
  -webkit-text-fill-color: transparent;
  -webkit-background-clip: text;
  margin: 10px;
}

h1::before {
  content: attr(data-text);
  background: -webkit-linear-gradient(-180deg, #3399ff, #82ed89, #3399ff);
  -webkit-background-clip: text;
  -webkit-text-stroke: 5px transparent;
  position: absolute;
  z-index: -1;
}
<h1 data-text="Text">Text</h1>

2
  • for the question you linked, did you check this: stackoverflow.com/a/56234003/8620333? with SVG you can easily do it Commented May 15, 2020 at 20:00
  • @TemaniAfif yes - similar to this question I wanted to avoid the use of SVG (or any images) and see if there's a way to do it entirely with CSS, if possible. Commented May 15, 2020 at 20:24

1 Answer 1

3

Actually the only way i can think about using CSS and without SVG is to rely on element() combined with mask but still the support is too low:

Here is an example that will only work in Firefox. The trick is to create a text with only stroke and transparent color as a reference that will be used inside a mask of the same text where we have the same stroke to keep only the stroke visible and get the needed effect. Yes, it's a bit crazy as idea but it works.

body {
  background: #000000;
}
h1 {
  font-size: 80px;
  font-weight: 800;
  font-family: arial;
  color:#fff;
}
#ref {
  -webkit-text-stroke: 5px red;
  color:transparent;
  display:inline-block;
}
h1.grad {
  background-image: linear-gradient(to left,
      rgba(255, 0, 0, 0.3),
      rgba(0, 0, 255, 0.4),
      rgba(255, 0, 0, 0.5));
  -webkit-text-fill-color: transparent;
  -webkit-background-clip: text;
  margin: 10px;
}
h1.grad::after {
  content: attr(data-text);
}

h1.grad::before {
  content: attr(data-text);
  background: linear-gradient(-180deg, #3399ff, #82ed89, #3399ff);
  -webkit-background-clip: text;
  -webkit-text-stroke: 5px transparent;
  position: absolute;
  z-index: -1;
  -webkit-mask:element(#ref);
          mask:-moz-element(#ref);
          mask:element(#ref);
}

body {
  background:url(https://picsum.photos/id/107/1000/1000) center/cover;
}
<h1 data-text="Some Text" class="grad"></h1>


<div style="height:0;overflow:hidden;">
<h1 id="ref">Some Text</h1>
</div>

Below how it should look:

enter image description here

Another idea is to consider background-attachment:fixed and use the same background twice. This should work everywhere but you background will be fixed:

body {
  background: #000000;
}
h1 {
  font-size: 80px;
  font-weight: 800;
  font-family: arial;
  color:#fff;
}

h1.grad {
  background: linear-gradient(to left,
      rgba(255, 0, 0, 0.3),
      rgba(0, 0, 255, 0.4),
      rgba(255, 0, 0, 0.5)),
      url(https://picsum.photos/id/110/1000/1200) center/cover fixed;
  -webkit-text-fill-color: transparent;
  -webkit-background-clip: text;
          background-clip: text;
  margin: 10px;
}
h1.grad::after {
  content: attr(data-text);
}

h1.grad::before {
  content: attr(data-text);
  background: linear-gradient(-180deg, #3399ff, #82ed89, #3399ff);
  -webkit-background-clip: text;
  -webkit-text-stroke: 5px transparent;
  position: absolute;
  z-index: -1;
}

body {
  background:url(https://picsum.photos/id/110/1000/1200) center/cover fixed;
}
<h1 data-text="Some Text" class="grad"></h1>

enter image description here

Sign up to request clarification or add additional context in comments.

1 Comment

Excellent - the final version worked a treat (best one for differing browsers), but I will note that it can only be used with non-transparent bitmap images. Hopefully they'll update CSS with a gradient text-stroke feature - would be a useful feature for a variety of projects, particularly those with transparent backgrounds or backgrounds set on the user's device. Thanks for your help with this!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.