Skip to content

Oliver's Blog

Hiding multiline text by vertically shifting it out of the text box

Tags:
  • CSS

A CSS only approach to a visual effect that is difficult to explain but not too difficult to realise.

When creating the new website for Hamburg based Make Studio I was challenged with implementing this effect as part of the view transition:

At first it didn't look too difficult, but actually implementing it wasn't straight forward. I wanted to accomplish this without using JS. Otherwise it would have been kind of easy with GSAP or by splitting the lines of text in individual HTML-elements. But it's those challenges I especially enjoy.

First I thought I could use text-decoration: underline for it. I tried setting it to 0px, make it the same colour as the background, shift it above the text and then simultaneously transition the underline to 1lh (line-height) and translate the text up 1lh. But the underline is behind the text, so you can't cover the text with it. When using text-decoration-style: overline or line-through (which is in front of the text) you can't use text-underline-offset. text-overline-offset doesn't exist (maybe it should!?).

What I finally came up with is using a linear gradient as text colour (kind of). Well actually, you set the gradient for the background and use a transparent text colour. Then you also set -webkit-background-clip: text;

When using a gradient for multiline text and you want to repeat the gradient for every line, you need to use display: inline.

The gradient consists of two colours. The initial text colour and the background colour. To have sharp edges in a gradient, you need four stops. The first one at 0%, the last one at 100%. The two in between have at first 0% and then change to 100%.

All you need to do now is trigger the transition to change the position of the gradient stops and translate up the text.

Unfortunately transitioning gradients doesn't work out of the box. You need to work around this by using registered custom properties and translate those.

Here is my code:

<div class="shift-text-wrapper">    
	<p>
		Deep Down<br>
		the Rabbit Hole…
	</p> 
</div>
/* register the custom properties */
@property --middle1{
    syntax: "<percentage>";
    inherits: false;
    initial-value: 0%;
}

@property --middle2{
    syntax: "<percentage>";
    inherits: false;
    initial-value: 0%;
}

.shift-text-wrapper{
    transition: 0.4s translate ease-out;
}

p{
    transition: 0.4s ease-out;
    
    /* use the custom property names 
       as transition-property values */
    transition-property: --middle1, --middle2;
}

p{
    display: inline;

    --middle1: 0%;
    --middle2: 0%;

    -webkit-background-clip: text;
    color: transparent;
    background-image: linear-gradient(
        180deg,
        white 0%, 
        white var( --middle1 ), 
        black var( --middle2 ), 
        black 100%
    );
}


.hide-text{
    p{
        --middle1: 100%;
        --middle2: 100%;
    }

    .shift-text-wrapper{
        translate: 0 -1lh;
    }
}

Try it out: click the text to trigger the transition

Deep Down
the Rabbit Hole…