模拟外部笔画::before伪元素:透明文本问题 [英] Simulate external stroke ::before pseudo elements: problem with transparent text

查看:24
本文介绍了模拟外部笔画::before伪元素:透明文本问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发现很难相信没有标准和简单(且独立于浏览器)的方法可以使用 CSS 在文本的外部周围放置描边效果.

我们确实有 -webkit-text-stroke 但由于一些奇怪的原因,笔画以文本的边框为中心,而不是文本之外em>,正如在此哀叹.

因此,我正在尝试基于 这个想法实施一种解决方法,该方法将原始未描边文本后面的伪元素中的描边文本.我已经在 this jsfiddle 中演示了这一点,代码如下:

var jQueryAttr = function(selector, attr, setterFunction) {document.querySelectorAll(selector).forEach((el, i) => {el.setAttribute(attr, setterFunction.call(el, i, attr));});};jQueryAttr('.myclass', 'data-myclass', function(index, attr) {返回 this.innerHTML;});

body {背景:无;}.基本的 {颜色:RGBA(186, 218, 85, 1);字体:2.5em Georgia,serif;}.我的课 {位置:相对;背景:透明;z-索引:0;}.myclass::before {内容: attr(data-myclass);位置:绝对;-webkit-text-stroke: 0.2em rgba(0, 0, 0, 1);z-索引:-1;}.anotherclass {-webkit-text-stroke: 0.2em rgba(0, 0, 0, 1);}

<p class="basic">没有任何笔划的文字</p><p class="myclass basic">带有外笔划的文本</p><p class="anotherclass basic">没有应用技巧</p>

这很好用,只是如果文本本身具有一定的透明度,那么您会看到下面的黑色描边,如 这个变体(唯一的变化是将文本的不透明度固定回0.3).如您所见,描边元素的黑色渗入文本(在顶行).

那么还有其他巧妙的技巧可以用来解决这个问题吗?我想可以在描边图层和未描边图层之间添加另一个伪元素,带有纯白色文本(或与背景匹配的文本),但我想在我 事先不知道背景的颜色...例如这是放置在任意用户选择的图像上.出于这个原因,我在上面的例子中将 bodybackground 设置为 none.

解决方案

这里有一个想法,你可以考虑 mix-blend-mode 和 text-shadow 的组合来近似这个想法.棘手的部分是调整阴影,以防您想要更大的笔触:

.text >跨度 {字体系列:无衬线;字体大小:60px;字体粗细:粗体;颜色:#fff;/*使用白色*//*在文本周围创建描边*/文字阴影:2px 0 0px #000,0 2px 0px #000,2px 2px 0px #000,-2px 0 0px #000,0 -2px 0px #000,-2px -2px 0px #000,-2px 2px 0px #000,2px -2px 0px #000;混合模式:变暗;/*一切都比白色更暗,所以我们总是看到背景*/}.文本 {显示:内联块;填充:20px;背景:线性渐变(向右,红色,蓝色);}

<div class="text"><span>这里有一些文字</span></div>

使用 CSS 变量可能会更容易调整:

.text >跨度 {字体系列:无衬线;字体大小:60px;字体粗细:粗体;颜色:#fff;/*使用白色*//*在文本周围创建描边*/文字阴影:var(--s,2px) 0 var(--c,0) #000,0 var(--s,2px) var(--c,0) #000,var(--s,2px) var(--s,2px) var(--c,0) #000,calc(-1*var(--s,2px)) 0 var(--c,0) #000,0 calc(-1*var(--s,2px)) var(--c,0) #000,calc(-1*var(--s,2px)) calc(-1*var(--s,2px)) var(--c,0) #000,calc(-1*var(--s,2px)) var(--s,2px) var(--c,0) #000,var(--s,2px) calc(-1*var(--s,2px)) var(--c,0) #000;混合模式:变暗;/*一切都比白色更暗,所以我们总是看到背景*/}.文本 {显示:内联块;填充:20px;背景:线性渐变(向右,红色,蓝色);背景尺寸:封面;背景位置:中心;}

<div class="text"><span>这里有一些文字</span></div><div class="text" style="--s:4px;--c:2px;background-image:url(https://picsum.photos/800/600?image=1069)"><span>这里有一些文字</span></div><div class="text" style="--s:6px;--c:4px;background-image:url(https://picsum.photos/800/600?image=1051)"><span>这里有一些文字</span></div>

如果你想要一个透明的文本颜色,你可以使用伪元素复制它:

.text >跨度 {字体系列:无衬线;字体大小:60px;字体粗细:粗体;位置:相对;显示:内联块;}.text >跨度::之前,.text >跨度::之后{内容:属性(数据文本);}.text >跨度::之前{颜色:#fff;/*使用白色*//*在文本周围创建描边*/文字阴影:var(--s,2px) 0 var(--c,0) #000,0 var(--s,2px) var(--c,0) #000,var(--s,2px) var(--s,2px) var(--c,0) #000,calc(-1*var(--s,2px)) 0 var(--c,0) #000,0 calc(-1*var(--s,2px)) var(--c,0) #000,calc(-1*var(--s,2px)) calc(-1*var(--s,2px)) var(--c,0) #000,calc(-1*var(--s,2px)) var(--s,2px) var(--c,0) #000,var(--s,2px) calc(-1*var(--s,2px)) var(--c,0) #000;混合模式:变暗;/*一切都比白色更暗,所以我们总是看到背景*/}.text >跨度::之后{位置:绝对;顶部:0;左:0;颜色:RGBA(0,255,0,0.4);}.文本 {显示:内联块;填充:20px;背景:线性渐变(向右,红色,蓝色);背景尺寸:封面;背景位置:中心;}

<div class="text"><span data-text="Some text here"></span>

<div class="text" style="--s:4px;--c:2px;background-image:url(https://picsum.photos/800/600?image=1069)"><span data-text="这里有一些文字"></span></div><div class="text" style="--s:6px;--c:4px;background-image:url(https://picsum.photos/800/600?image=1051)"><span data-text="这里有一些文字"></span></div>

I find it difficult to believe that there is no standard and simple (and browser-independent) way to put a stroke effect around the outside of text using CSS.

We do have -webkit-text-stroke but for some odd reason the stroke is centred around the border of the text rather than outside it, as bemoaned here.

So I'm trying to implement a workaround based on this idea, which places the stroked text in a pseudo element behind the original un-stroked text. I've demonstrated this in this jsfiddle, with the following code:

var jQueryAttr = function(selector, attr, setterFunction) {
  document.querySelectorAll(selector).forEach((el, i) => {
    el.setAttribute(attr, setterFunction.call(el, i, attr));
  });
};

jQueryAttr('.myclass', 'data-myclass', function(index, attr) {
  return this.innerHTML;
});

body {
  background: none;
}

.basic {
  color: rgba(186, 218, 85, 1);
  font: 2.5em Georgia, serif;
}

.myclass {
  position: relative;
  background: transparent;
  z-index: 0;
}

.myclass::before {
  content: attr(data-myclass);
  position: absolute;
  -webkit-text-stroke: 0.2em rgba(0, 0, 0, 1);
  z-index: -1;
}

.anotherclass {
  -webkit-text-stroke: 0.2em rgba(0, 0, 0, 1);
}

<p class="basic">Text without any stroke</p>
<p class="myclass basic">Text with outer stroke</p>
<p class="anotherclass basic">Without the trick applied</p>

This works fine, except that if the text itself has some transparency then you see the dark stroke underneath, as shown in this variant (the only change is to peg the opacity of the text back to 0.3). As you can see, the black from the stroked element is leaching through into the text (in the top line).

So is there another neat trick to use to overcome this problem? I guess it's possible to add another pseudo element between the stroked layer and the un-stroked layer, with a pure white text (or one to match the background), but I'd like to apply this technique in a context where I don't know the colour of the background in advance... e.g. where this is laid over an arbitrary user-selected image. For this reason, I've set the background of the body to none in the above example.

解决方案

Here is an idea where you can consider mix-blend-mode and a combination of text-shadow to approximate this. The tricky part is to adjust the shadow in case you want a bigger stroke:

.text > span {
  font-family:sans-serif;
  font-size:60px;
  font-weight: bold;
  color:#fff; /*use white*/
  /*create the stroke around text*/
  text-shadow:
    2px 0  0px #000,
    0 2px 0px #000,
    2px 2px 0px #000,
    -2px 0 0px #000,
    0 -2px 0px #000,
    -2px -2px 0px #000,
    -2px 2px 0px #000,
    2px -2px 0px #000;
  mix-blend-mode: darken; /*everything is more dark than white so we always see the background */
}
.text {
  display:inline-block;
  padding:20px;
  background:linear-gradient(to right,red, blue);
}

<div class="text"><span>Some text here</span></div>

Using CSS variable will probably make it easier to adjust:

.text > span {
  font-family:sans-serif;
  font-size:60px;
  font-weight: bold;
  color:#fff; /*use white*/
  /*create the stroke around text*/
  text-shadow:
    var(--s,2px) 0  var(--c,0) #000,
    0 var(--s,2px) var(--c,0) #000,
    var(--s,2px) var(--s,2px) var(--c,0) #000,
    calc(-1*var(--s,2px)) 0 var(--c,0) #000,
    0 calc(-1*var(--s,2px)) var(--c,0) #000,
    calc(-1*var(--s,2px)) calc(-1*var(--s,2px)) var(--c,0) #000,
    calc(-1*var(--s,2px)) var(--s,2px) var(--c,0) #000,
    var(--s,2px) calc(-1*var(--s,2px)) var(--c,0) #000;
  mix-blend-mode: darken; /*everything is more dark than white so we always see the background */
}
.text {
  display:inline-block;
  padding:20px;
  background:linear-gradient(to right,red, blue);
  background-size:cover;
  background-position:center;
}

<div class="text"><span>Some text here</span></div>

<div class="text" style="--s:4px;--c:2px;background-image:url(https://picsum.photos/800/600?image=1069)"><span>Some text here</span></div>

<div class="text" style="--s:6px;--c:4px;background-image:url(https://picsum.photos/800/600?image=1051)"><span>Some text here</span></div>

If you want a transparent color for the text you can duplicate it using pseudo element:

.text > span {
  font-family:sans-serif;
  font-size:60px;
  font-weight: bold;
  position:relative;
  display:inline-block;
}
.text > span::before,
.text > span::after {
  content:attr(data-text);
}
.text > span::before {
  color:#fff; /*use white*/
  /*create the stroke around text*/
  text-shadow:
    var(--s,2px) 0  var(--c,0) #000,
    0 var(--s,2px) var(--c,0) #000,
    var(--s,2px) var(--s,2px) var(--c,0) #000,
    calc(-1*var(--s,2px)) 0 var(--c,0) #000,
    0 calc(-1*var(--s,2px)) var(--c,0) #000,
    calc(-1*var(--s,2px)) calc(-1*var(--s,2px)) var(--c,0) #000,
    calc(-1*var(--s,2px)) var(--s,2px) var(--c,0) #000,
    var(--s,2px) calc(-1*var(--s,2px)) var(--c,0) #000;
  mix-blend-mode: darken; /*everything is more dark than white so we always see the background */
}
.text > span::after {
  position:absolute;
  top:0;
  left:0;
  color:rgba(0,255,0,0.4); 
}
.text {
  display:inline-block;
  padding:20px;
  background:linear-gradient(to right,red, blue);
  background-size:cover;
  background-position:center;
}

<div class="text"><span data-text="Some text here"></span></div>

<div class="text" style="--s:4px;--c:2px;background-image:url(https://picsum.photos/800/600?image=1069)"><span data-text="Some text here"></span></div>

<div class="text" style="--s:6px;--c:4px;background-image:url(https://picsum.photos/800/600?image=1051)"><span data-text="Some text here"></span></div>

这篇关于模拟外部笔画::before伪元素:透明文本问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆