Text color wave effect - mimic a block of colors flowing through text

I'm experimenting with creating a unique text effect where, upon hovering over the text, it appears as though a block of color is passing through it.

Inspired by the technique showcased in this first example (specifically for the word "Kukuri"), I utilized a :before pseudo-element in my SCSS code to achieve the desired color fill effect:

.text {
  position: relative;

  &:hover { 
    &:before {
      width: 100%;
    }
  } 

  &:before {
    content: 'HELLO'; // assuming our text is "HELLO"
    width: 0%;
    position: absolute;
    z-index: 2;
    overflow: hidden;
    color: red;
    transition: width 350ms ease-in-out;
    white-space: nowrap;
    width: 0%;
  }
}

Now, I am curious if it's achievable to animate the width of the :before element in reverse. Essentially, once it reaches 100% width and fills with color, I want the left side to gradually empty until it returns to 0% fill.

The ultimate aim is to incorporate this effect into a navigation menu, similar to how a block of color appears to move across menu items on hover:

https://i.sstatic.net/luCLb.png

For instance, hovering over the "About" item should trigger the fill color to wipe down while

Suggested Approaches

  1. One approach I attempted was translating the :before element, adjusting the left and right properties, and tweaking the transform-origin, but without success.

  2. I also explored using mix-blend-mode to create a rectangular mask that could potentially add color to the text. However, after some investigation, I discovered that mix-blend-mode only interacts effectively with text and not with rectangular divs featuring background colors.

Answer №1

You have the option to achieve this effect by overlaying a transparent layer on top of your element:

ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

ul li {
  display: inline-block;
  margin: 10px;
  position: relative;
  font-size: 30px;
  color: red;
  font-weight: bold;
  overflow: hidden;
}

ul li:before {
  content: "";
  position: absolute;
  height: 100%;
  width: 100%;
  background: rgba(255, 255, 255, 0.6);
  transition: 2s;
  z-index: 2;
}

ul.ver li:before {
  top: 0;
  left: -100%;
}

ul.hor li:before {
  top: -100%;
  left: 0;
}

ul.ver li:hover::before {
  left: 100%;
}

ul.ver.half li:hover::before {
  left: 0;
}

ul.hor li:hover::before {
  top: 100%;
}
ul.hor.half li:hover::before {
  top: 0;
}
<ul class="hor">
  <li>Home</li>
  <li>About</li>
</ul>
<ul class="hor">
  <li>Home</li>
  <li>About</li>
</ul>
<ul class="ver half">
  <li>Home</li>
  <li>About</li>
</ul>
<ul class="hor half">
  <li>Home</li>
  <li>About</li>
</ul>

Here is an alternative method using mix-blend-mode with text:

ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

ul li {
  display: inline-block;
  margin: 10px;
  position: relative;
  font-size: 30px;
  background-image: linear-gradient(to right, red, red);
  background-size: 200% 200%;
  background-repeat: no-repeat;
  font-weight: bold;
  overflow: hidden;
  transition: 1s;
}
ul.hor li {
  background-position: 0% 200%;
}
ul.ver li {
  background-position: 200% 0%;
}

ul li span {
  display: inline-block;
  color: black;
  background-color: white;
  mix-blend-mode: screen;
}

ul.hor li:hover {
  background-position: 0% -100%;
}
ul.ver li:hover {
  background-position:-100% 0%;
}
ul.hor.half li:hover {
  background-position: 0% 0%;
}
ul.ver.half li:hover {
  background-position:0% 0%;
}
<ul class="hor">
  <li><span>Home</span></li>
  <li><span>About</span></li>
</ul>
<ul class="ver">
  <li><span>Home</span></li>
  <li><span>About</span></li>
</ul>
<ul class="hor half">
  <li><span>Home</span></li>
  <li><span>About</span></li>
</ul>
<ul class="ver half">
  <li><span>Home</span></li>
  <li><span>About</span></li>
</ul>

Answer №2

One way to achieve this effect is by utilizing blend modes. Here's an example:

I have chosen to move the background of the pseudo element instead of moving the pseudo element itself. This helps avoid any side effects when the pseudo element overlaps with other elements.

It's important to note that I have set it up as a double slide (from black to red and back to black). You can customize this easily by adjusting the final background position.

.demo {
    background-color: yellow;
    margin: 10px;
    display: inline-block;
    font-size: 50px;
    padding: 10px;
    position: relative;
}

.demo:after {
    content: "";
    position: absolute;
    left: 0px;
    top: 0px;
    width: 100%;
    height: 100%;
    background-image: linear-gradient(to right, transparent 25%, red 25%, red 75%, transparent 75% );
    mix-blend-mode: lighten;
    background-size: 400% 100%;
    transition: background-position 2s linear;
    background-position: 100% 0%;
}

.demo:hover:after {
    background-position: 0% 0%;
}
<div class="demo">TEST1</div>
<div class="demo">TEST2</div>

To change the direction of movement to vertical, you'll need to adjust:

  • The gradient direction
  • Which image dimension is oversized
  • The background position change on hover

.demo {
    background-color: yellow;
    margin: 10px;
    display: inline-block;
    font-size: 50px;
    padding: 10px;
    position: relative;
}

.demo:after {
    content: "";
    position: absolute;
    left: 0px;
    top: 0px;
    width: 100%;
    height: 100%;
    background-image: linear-gradient(to top, transparent 25%, red 25%, red 75%, transparent 75% );
    mix-blend-mode: lighten;
    background-size: 100% 400%;   /* changed for vertical dimension */
    transition: background-position 2s linear;
    background-position: 0% 100%; /* changed to vertical position*/
}

.demo:hover:after {
    background-position: 0% 0%;
}
<div class="demo">TEST1</div>
<div class="demo">TEST2</div>

Answer №3

<div class="snippet" data-lang="html" data-hide="true" data-console="false" data-babel="true">
<div class="snippet-code">
<pre class="snippet-code-css lang-html prettyprint-override"><code>    .text {
text-transform: uppercase;
font-weight: 900;
overflow: hidden;
line-height: 0.75;
color: #c5c2b8;
    position:relative;
}
    .text:before {
    content: attr(data-letters);
    position: absolute;
    z-index: 2;
    overflow: hidden;
    color: red;
    white-space: nowrap;
    width: 0%;
        top:0;
    -webkit-transition: width 0.4s 0.3s;
    transition: width 0.4s 0.3s;
    }

    .text:hover:before {
    width: 100%;
    }
    <span class="text" href="#" data-letters="world">world</span>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Align the content of a collapsed bootstrap row vertically

In a row, I have two columns, each containing their own row. When the page width hits the 'xs' break-point, the left column's row will stack its columns on top of each other. The right column is taller than the left column, which leaves a l ...

Is there a way to showcase Laravel images on a live server efficiently?

After successfully developing a Laravel app on my local machine, complete with visible images, I encountered an issue upon deployment to the live server where the images were no longer displaying. My hosting setup involves a 'public_html' folder ...

Converting DateTime objects into JSON format for use in AJAX calls

When utilizing my AJAX method, it returns a view model that is serialized as a data structure using JavaScriptSerializer().Serialize(). Among this data are several nullable DateTime? properties. I recently discovered that these dates appear in JavaScript ...

Does the frame take precedence over the button?

const div = document.createElement('div'); // creating a dynamic div element div.setAttribute('id', "layer1"); // setting an id for the div div.className = "top"; // applying a customized CSS class div.style.position = "absolute"; // sp ...

Create a regex pattern that can accurately extract email addresses from a comma-del

Currently, I have a regular expression that validates a single email address. How can I modify this regex to accept a list of email addresses separated by commas? ^(([A-Za-z0-9]+_+)|([A-Za-z0-9]+\-+)|([A-Za-z0-9]+\.+)|([A-Za-z0-9]+\++))*[A- ...

Struggling to position an image and text side by side within a div using CSS

Is there a way to display a message inside a div with an icon positioned to the left? The desired outcome is for the icon to always be next to the text and aligned at the bottom-center of the div. I attempted using the :after pseudo element. However, set ...

Retrieve the text input from its respective radio button

There are two radio buttons, each accompanied by an input text field. When a user selects a radio button, they can also enter some corresponding text. My inquiry is: What is the best method to retrieve the entered text for the selected radio button? ...

Tips for effectively transmitting and managing a JSON object within an ASP.NET MVC controller

I am currently working on a project using ASP.NET MVC 4 and I'm facing an issue with sending a JSON object to a controller that is supposed to accept it. Here is the snippet of javascript and jQuery code I am using: var jsonObject = { "PlantShip ...

Tips for ensuring the accurate retrieval of prop values by waiting for the value to be set

Encountering an issue with the .toUpperCase() method within one of my components, resulting in the following error: TypeError: Cannot read properties of undefined (reading 'toUpperCase') This problem seems to stem from a race condition in fetc ...

Creating tube-like geometry in intervals using three.js

Is there a way in Tube Geometry(Three.js) to plot and render only a portion of the tube at a time, with the option to continue plotting from that point after a set interval or timer? ...

Add elements to an array with express, Node.js, and MongoDB

I'm currently learning about the MERN stack and I'm working on creating users with empty queues to store telephone numbers in E.164 format. My goal is to add and remove these numbers from the queue (type: Array) based on API requests. However, I ...

Some mobile web browsers are experiencing difficulties when trying to load a background video coded in html5

There is a full background HTML5 video set to autoplay on my website. However, there seems to be an issue with some iOS mobile devices using Safari as the video fails to load properly at times. The error message displayed is: https://i.stack.imgur.com/D4X ...

Replacing child routes with an Angular wildcard route

I'm facing an issue with integrating a module named "host" into the app-routing.module. The problem I encountered is that the wildcard route takes precedence over loading the Host component, leading to the display of the PageNotFoundComponent instead. ...

Unusual Display of Mantine Radio Button

I am currently using Mantine v7.0.0 in combination with Next.js v13.5.2 and Tailwind v3.3.3. In my setup, when I create <Radio /> elements, the svg of the element is appearing separately from the radio button instead of replacing it. This issue can b ...

How can I trigger the offcanvas opening in Bootstrap 5 through code?

I am having an issue with a bottom offcanvas on my webpage. I want to open it when a card is clicked, but despite trying to set the necessary attributes and using code from the documentation, it only shows the backdrop briefly before immediately dismissing ...

Reset jQuery validation when a button is clicked

I need assistance with a form validation issue. I am using jQuery validation methods to validate the controls on my form. However, I am facing difficulties in clearing the validation when clicking on 'cancel'. Below is the code snippet: <scr ...

Mastering the art of knowing when to implement asynchronous and synchronous programming techniques is essential for

As I explore asynchronous programming in JavaScript, I am faced with the challenge of integrating two email providers: Sendgrid and Mailgun. My goal is to send an email using one provider, and if any errors occur during the process, automatically resend th ...

Is it possible to send an AJAX request to a Django view that might result in a redirect?

Query I encountered an issue while attempting to access a specific Django view through AJAX. This particular view redirects users if they haven't authorized the site with Google. I suspect the problem arises from redirecting "within" a view requested ...

Why isn't my lightbox able to read this specific property?

A gallery was created using both lightgallery and cycle2. Cycle is a carousel plugin while lightgallery is a lightbox gallery. Clicking on an image in the carousel opens it in the lightbox. Everything worked perfectly until a category in the carousel was ...

What is the best way to hide a <tr> element when its child <td> elements are empty?

I am facing an issue with a dynamically generated table that may have 'n' rows. If all <td> elements within a <tr> are empty, I want to hide or delete the entire row. My challenge lies in parsing through each <td> element to ch ...