2

I recently came across this dribbble/landing page concept with hollow/filled text.

enter image description here

First off I'm not entirely sure if this concept could be recreated in CSS. A bit of Google did lead me to CSS text masks, but I wasn't able to find any post that can really recreate this effect.

How would I be able to reconstruct the hollow/filled text, depending if the background behind the text has an image or not?

4

1 回答 1

5
  • 它可以在纯 HTML+CSS 中完成(没有任何 SVG)。

    • 它也可以在纯 SVG 中完成。
      • 仅 SVG 选项会更简单,因为 SVG 具有更强大的混合和遮罩功能,这些功能(还)不能被 HTML 元素(CSS 框)使用。
  • 我决定为 HTML+CSS 做这件事,因为我觉得这是一个挑战。

    • 这个 HTML 版本是动画的,文本是完全可选择的。
    • 这个 HTML+CSS 版本可以通过使用mask-image: element(#target)进一步简化,意味着我们不需要纯掩码文本,不幸的是 Chrome 似乎还不支持element()(但 Firefox 支持)。
  • 一个小问题是轮廓与同一浏览器和计算机中的纯白色文本(至少在 Windows 10 上的 Chrome 中,我的计算机版本为96dpi,但在 192dpi(2x,又名Retina)中)不完全对齐看起来很完美。text-strokeHelvetica

  • 以下是它在我的机器上以 96dpi 显示动画中不同点的方式:

  • 下面的示例实现适用于以下浏览器(在撰写本文时):

    • 铬 98
    • 边缘 98
    • 火狐 97
    • macOS Safari 技术预览(第 137 版)
      • 有点适用于 macOS Safari 15.2,但由于某种原因你必须先点击它。
      • 它在 iOS Safari 15.1 中不起作用(只有轮廓文本可见,纯文本根本不呈现)。
      • 因为它确实可以在 Safari Preview 浏览器中使用,所以它应该可以在 iOS Safari 和 macOS Safari 的下一次更新中使用。

 body {
background-color: #dbdac2;
--solid-white: linear-gradient(white,white);
 }
#container,
#container > #div1 {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;

    background-size:
        153px 302px,
        148px 302px,
        154px 302px;

    background-position:
        131px 94px,
        309px 28px,
        480px 94px;

    background-repeat:
        no-repeat,
        no-repeat,
        no-repeat;

    animation: moveImages 2s infinite;
    animation-direction: alternate;
}

#container {
    border: 1px solid white;
    position: relative;
    width: 711px;
    height: 440px;

    /* These are the 3 photo images, rendered as separate background-image layers: */
    background-image:
        url( "https://i.stack.imgur.com/hmwyh.png" ),
        url( "https://i.stack.imgur.com/JeHEg.png" ),
        url( "https://i.stack.imgur.com/pVgz6.png" );
    }
    #container p {
        margin: 0;
        position: static;
        padding-top: 192px;
        padding-left: 62px;
        overflow: hidden;

        font-family: Helvetica;
        font-size: 99px;
        letter-spacing: -2px;
        font-weight: 600;
    }
        #container > #pStroke {
            text-stroke: 1px white;
            -webkit-text-stroke: 1px white;
            color: transparent;
        }

        #container > #div1 {
            /* #div1's background-image layers must match #container's: */
            background-image:
                var(--solid-white),
                var(--solid-white),
                var(--solid-white);

            -webkit-background-clip: text;
            background-clip: text;
            color: transparent;
        }

@keyframes moveImages {
    /* The `@keyframes from {}` rule is optional, btw. */
    to {
        background-size:
            53px 302px,
            58px 302px,
            154px 302px;

        background-position:
            431px 94px,
            209px 28px,
            280px 194px;
    }
}
<div id="container">

  <div id="div1">
    <p id="pWhite">Fashion Give<br />Impression.</p>
  </div>
  
  <p id="pStroke">Fashion Give<br />Impression.</p>

</div>

解释:

  • div#container元素有一个background-image属性设置为 3 个不同的源图像(使用 meme 图像代替您发布的示例中的时尚照片)。

    • 这些图像可以通过background-sizebackground-position属性独立定位和缩放。
  • 另一个元素 ( )通过定位#div1覆盖并具有相同的和属性,但使用单个纯白色背景图像(来自 a )而不是照片,然后这 3 个白色背景图像层被'inner ' 的文本使用.div#containerabsolutebackground-sizebackground-positionlinear-gradient(white,white)#div1<p>background-clip: text;

    • 这个例子必须使用background-image: linear-gradient(or background-image: url("1x1px-white.png");) 代替,background-color: white;因为它需要在 3 个单独的层中重复,而background-color: white;不能用于在背景中定义一个矩形区域,也不能有多个 background-color层(即使是半透明的)。
    • 该示例还必须使用 DOM 文本来屏蔽白色矩形 - 而不是使用白色矩形来屏蔽 DOM 文本 - 因为 CSS-in-HTML 不支持任何类型的反转文本屏蔽,否则这会容易得多. 但是,我相信这在 SVG 中很容易实现。
    • #div1<p>元素用于通过仅使用其内部padding而不是position: absolute;因为定位的文本不能与 一起使用来正确定位文本background-clip: text;,不幸的是。
  • 带有文本副本的另一个<p>元素用于描边文本(带有text-stroke: 1px white;)

  • 虽然文本内容在 HTML 源代码中重复,但幸运的是,不需要在 CSS 中重复 3 幅图像(以及它们各自的白色蒙版)的更精细的大小和位置信息;感谢 CSS 的选择器是如何工作的(两者都由一个 CSS 规则设置它们的和#container属性)。#div1background-sizebackground-position

可能的替代方法:

  • 代替对background-image纯白色部分使用重复的相同大小的层,可以使用单个(但非常复杂)clip-path跟踪 3 个框(就像像蚀刻草图一样绘制的单线),#pWhite但这不是可行的动画.

  • 我认为最好的方法是这样的:

    • 对 3 张照片使用 3 个单独<img />的元素(而不是background-image)并absolute在新的<div id="images">.
    • 然后纯白色文本<p>(在 的同级元素中div#images)将被定位absolute并用div#imagesz-indexmask-image: element(#images);
    • element()但据我所知,Chrome 似乎不支持在 HTML+CSS 中使用,只有 Firefox 支持。
    • 描边文本将作为重复<p>元素保留在div#images.
    • 这种方法的另一个优点是<img/>元素可以定位,transform: translate而不是必须经过,background-position否则position: absolute会产生更好的性能和帧速率。
  • 不过,我想不出任何不需要复制文本内容的方法——至少在 CSS 的content:属性允许元素从其他元素复制文本之前。

于 2022-02-19T19:18:44.690 回答