Step-by-step tutorial on designing an input slider to dynamically adjust the CSS :before linear-gradient values

Is there a way to achieve a gradient effect using pseudo-element :before on an image that can be customized by adjusting a slider input? I've been trying to implement this feature with the following code, but have not been successful so far.

var sliderValue = $('#range');

sliderValue.oninput = function(){
    var val1 = this.value;
    var val2 = 100-val1;     
    $('<style> #filter:before{linear-gradient(to top, rgba(255,255,255,1) '+val1+'%,rgba(0,0,0,0) '+val2+'%);}</style>').appendTo("#filter");
};
.slider
{
    -webkit-appearance:none;
    appearance:none;
    width: 100%;
    height: 10px;
    max-width: 400px;
    background-color: #ccc;
    margin: 0;
    padding: 0;
    outline: none;
    border-radius: 10px;
    cursor: pointer;
}
#filter {
    position:relative;
    float: left;
    max-height: 480px; 
    
}

#filter:before {
    content: "";
    position:absolute;
    top:0;
    left: 0;
    right: 0;
    bottom: 0;
    width:320px;
    height:100%;
    background: linear-gradient(to top, rgba(255,255,255,1) 15%,rgba(0,0,0,0) 22%);
    z-index: 1;
}
<div class="container">
   <input type="range" min="0" max="100" value="0" class="slider" id="range">    
   <div id="filter">  
    <img id="previewImg" src="img/dummy_320x480_ffffff_d002e2.png" alt="Placeholder" style="height: 100%; width:320px;">
   </div>
</div>  
<script src="https://code.jquery.com/jquery-3.6.3.min.js" integrity="sha256-pvPw+upLPUjgMXY0G+8O0xUf+/Im1MZjXxxgOcBQBXU=" crossorigin="anonymous"></script>

Answer №1

If you want the gradient to work properly, there are some adjustments that need to be made in the code:

  1. Ensure you are selecting the input element using jQuery's $(...) function instead of document.getElementById(...).
  2. Link the input element's oninput function to jQuery's input event.
  3. Normalize the slider value from 0 to 1 rather than 0 to 100.
  4. Make sure the gradient CSS declaration uses the correct notation for the color values (e.g., rgba(255,255,255,1) should be rgba(255,255,255,1.0)).

After making these changes, your code should look something like this:

HTML:

<div class="container">
  <input type="range" min="0" max="100" value="0" class="slider" id="range">    
  <div id="filter">
    <img id="previewImg" src="img/dummy_320x480_ffffff_d002e2.png" alt="Placeholder" style="height: 100%; width:320px;">
  </div>
</div>

jQuery:

var sliderValue = $('#range');
sliderValue.on('input', function() {
  var val1 = this.value / 100;
  var val2 = 1 - val1;
  $('<style> #filter:before {background: linear-gradient(to top, rgba(255,255,255,1.0) ' + val1*100 + '%, rgba(0,0,0,0) ' + val2*100 + '%);}</style>').appendTo("#filter");
});

CSS:

.slider {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 10px;
  max-width: 400px;
  background-color: #ccc;
  margin: 0;
  padding: 0;
  outline: none;
  border-radius: 10px;
  cursor: pointer;
}

#filter {
  position: relative;
  float: left;
  max-height: 480px; 
}

#filter:before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  width: 320px;
  height: 100%;
  background: linear-gradient(to top, rgba(255,255,255,1.0) 15%, rgba(0,0,0,0) 22%);
  z-index: 1;
}

Remember that the tag is meant for declaring CSS styles in the HTML page header and not for dynamically creating styles in jQuery. In the provided code snippet, we used the appendTo method to insert the dynamically generated CSS style into the #filter element.

Answer №2

There are a few issues with the code you provided:

  • Instead of appending the new style to every input, I have created an HTML element for the style that gets updated with the correct content on every input event;
  • The color was not displaying properly, so I changed rgba(0,0,0,0) to rgba(0,0,0,.1) to ensure it is visible;
  • The #filter div was overlapping the slider, preventing activation. By removing the float left property, this issue has been resolved.

var sliderValue = $('#range'),
    filterStyle = $('#filter-before');
    
sliderValue.on('input', function() {
  var val1 = this.value;
  var val2 = 100 - val1;
  filterStyle.html('#filter:before{background: linear-gradient(to top, rgba(255,255,255,1) ' + val1 + '%,rgba(0,0,0,.1) ' + val2 + '%);}');
});
.slider {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 10px;
  max-width: 400px;
  background-color: #ccc;
  margin: 0;
  padding: 0;
  outline: none;
  border-radius: 10px;
  cursor: pointer;
}

#filter {
  position: relative;
  max-height: 480px;
  width: 200px;
  height: 200px;
}

#filter:before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  width: 320px;
  height: 100%;
  background: linear-gradient(to top, rgba(255, 255, 255, 1) 15%, rgba(0, 0, 0, 0) 22%);
  z-index: 1;
}
<style id="filter-before"></style>
<div class="container">
  <input type="range" min="0" max="100" class="slider" id="range">
  <div id="filter">
    <img id="previewImg" src="img/dummy_320x480_ffffff_d002e2.png" alt="Placeholder" style="height: 100%; width:320px;">
  </div>
</div>
<script src="https://code.jquery.com/jquery-3.6.3.min.js" integrity="sha256-pvPw+upLPUjgMXY0G+8O0xUf+/Im1MZjXxxgOcBQBXU=" crossorigin="anonymous"></script>

Answer №3

It has been pointed out in previous responses that there were several issues with your original code, mainly revolving around the attempts to append a <style> element to the document upon each input event triggered on the sliderValue element. Unfortunately, the sliderValue Object was a jQuery Object devoid of an oninput method.

To associate an event-handler with a jQuery Object, you should utilize the on() method:

sliderValue.on('<eventName>', function(){
  // functionality
});

Instead of delving into improved jQuery practices covered by others, I wanted to demonstrate how this could be accomplished using vanilla JavaScript and CSS custom-properties (with explanatory notes included in the code):

// utility functions for brevity:
const D = document,
  get = (selector, context = D) => context.querySelector(selector),
  getAll = (selector, context = D) => [...context.querySelectorAll(selector)];
  
// triggering an input-event once an event-handler is bound:
let inputEvent = new Event('input'),
    updateGradient = (evt) => {
        let updated = evt.currentTarget,
            target = get(updated.dataset.updates);
        
        target.style.setProperty(`--${updated.name}`, updated.value)
},
updaters = getAll('input[data-updates]');

updaters.forEach(
  (el) => {
    el.addEventListener('input', updateGradient);
    el.dispatchEvent(inputEvent);
  });
:root {
  --spacing: 1rem;
}

*,
::before,
::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html,
body {
  font-family: system-ui;
  font-size: 16px;
  font-weight: 400;
  min-block-size: 100%;
  padding-block: var(--spacing);
}

main {
  block-size: 100%;
  border: 1px solid #000;
  display: grid;
  gap: var(--spacing);
  inline-size: clamp(30rem, 80%, 1200px);
  margin-inline: auto;
}

form {
  display: grid;
  gap: var(--spacing);
  padding: var(--spacing);
}

label {
  display: flex;
  gap: var(--spacing);
}

.labelText {
  flex-grow: 1;
  text-align: end;
}

.labelText::after {
  content: ':';
}

label > input {
  flex-basis: 70%;
}

.preview {
  --color1: rgba(255 255 255 / 1);
  --color2: rgba(0 0 0 / 1);
  --stop: 50;
  aspect-ratio: 2;
  background-image:
    linear-gradient(
      180deg,
      var(--color1, lightskyblue)
      calc(var(--stop) * 1%),
      var(--color2, lime)
      calc(var(--stop) * 1%)
    );
}
<main>
  <form action="#" method="post">
    <label>
      <span class="labelText">Color 1</span>
      <input type="color" name="color1" value="#000000" data-updates=".preview">
    </label>
    <label>
      <span class="labelText">Color 2</span>
      <input type="color" name="color2" value="#ff9900" data-updates=".preview">
    </label>
    <label>
      <span class="labelText">Gradient stop (%)</span>
      <input type="range" name="stop" min="0" max="100" value="25" data-updates=".preview">
    </label>
    <button type="submit">Submit</button>
  </form>
  <div class="preview"></div>
</main>

View JS Fiddle demo.

References:

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

Disappear text gradually while scrolling horizontally

There is a need to create a special block that displays fading text on horizontal scroll. However, the problem is that the block is situated on a non-uniform background, making the usual solution of adding a linear gradient on the sides unsuitable. Click ...

What is the best way to create a unique shadow effect for a container in Flutter?

I am facing a challenge with my screen layout that uses GridView.builder with crossAxisCount: 3. In the itemBuilder, I am returning a Container with shadows on the left, right, and bottom, but so far, I have not been able to achieve the desired outcome. H ...

Updating Angular UI-Router to version 1.0 causes issues with resolving data inside views

After upgrading my Angular UI-Router to version 1.0, I came across an interesting statement in the migration guide: We no longer process resolve blocks that are declared inside a views While it makes sense to move all resolve blocks to the parent state ...

Running the `npm start` command in Angular tends to be quite time-consuming

When I use Visual Studio Code to run Angular projects, my laptop seems to take a longer time when running the server through npm start compared to others. Could this delay be related to my PC specifications, or is there something I can do to improve it? ...

JavaScript Array join() method returns an empty string

As a beginner in the world of javascript, I am just starting to dip my toes into it. In the past, I have used join() without any issues, but now I am facing a problem where this join is returning an empty string. Upon inspecting myArray, the data seems t ...

Looking for Protractor CSS functionalities nodes

I tried the code below but am having trouble locating the "Login" text using Protractor: <div _ngcontent-c2="" class="align-center"> <img _ngcontent-c2="" alt="Autoprax" class="ap-logo" src="/images/apLogoSmall.svg" style="width: 100%"> ...

Learning how to dynamically update a value in Angular based on user input

My goal is to dynamically change the output value based on user input using Angular. I have successfully implemented the functionality to increment the value, but unfortunately, when the input changes, the outputed value remains static. Below is my curren ...

npm: Generating debug and production builds while ensuring accurate dependency management

I am in the process of developing a single page application using TypeScript along with various other dependencies such as jQuery, immutable, lodash, and React. Each resulting module is integrated into the project using requirejs. My goal is to generate t ...

Guide to declaring variables using jQuery

Currently tackling a school project, I stumbled upon some online example solutions and managed to decipher most of the code. However, there is one line that has me puzzled. var $newTweet = $('<div class=tweet></div>'); My assumption ...

How to use Vue v-bind to fetch an array object from a different array iteration

I am currently working on a project where I have developed a table component that is utilized across multiple pages with different configurations. Each table has its own configuration stored in a separate file, containing keys, titles, and size classes for ...

Unexpected behavior encountered when running Angular 8 radio button checked function

I have an Angular 8 web app with some unique logic implemented as shown below: HTML: <div *ngFor="let item of selectedItems;"> <input type="radio" [(ngModel)]="mySelectedItem" [value]="item.key" (ngModelChange)="setCh ...

Issue: angular2-cookies/core.js file could not be found in my Angular2 ASP.NET Core application

After spending 2 hours searching for the source of my error, I have decided to seek help here. The error message I am encountering is: "angular2-cookies/core.js not found" I have already installed angular2-cookie correctly using npm. Below is the code ...

Tips for customizing text field appearance in Safari and Chrome

I haven't had a chance to test it on IE yet. My goal is to create a unique style for the background image and text box shape, along with borders, for the search bar on my website, [dead site]. If you check it out on Firefox or Opera and see the sear ...

What is the preferred method for writing `*zoom: 1;` in CSS?

Trying to create my code, I decided to borrow some CSS files from older code. However, upon running yarn build I encountered several errors like: ▲ [WARNING] Expected identifier but found "*" [css-syntax-error] <stdin>:122:2: 122 │ * ...

Incorporating <span> elements into a comma-separated list using Jquery on every other item

When I receive a comma-separated list of items from a database and insert them into a table cell, I want to apply alternating styles to make it easier for users to distinguish between them. For example: foo, bar, mon, key, base, ball I'm looking to ...

The tag (p) is not located in a valid position

I am currently working with the following code snippet: <p class="pHelp"> xxxxx <a href="#components">Form components</a> yyyyy </p> This particular line is located within a long chain of nested HTML tags inside html/body/a/a/a/a/ ...

Encountering a problem when trying to use event.target.value in an Angular TypeScript application

Here is the code from my app.component.html : <h1>Password Generator</h1> <div> <label>Length</label> </div> <input (input)="onChangeLength($event.target.value)"/> <div> <div> <input ...

Is there a Wordpress floating bar similar to the one seen on 9gag?

After browsing through some posts on stackoverflow, I noticed that my website is not responding as expected. You can check out my site here: To troubleshoot, you can examine the source code and utilize Firebug to inspect the css and javascript being used ...

Is the navigation bar offset causing an issue?

After struggling with my navigation menu in Google Chrome, I finally found a solution. However, the nav bar is now offset on one page but not on another. For the aligned main site view, visit , and for the left-offset forum view, visit . This is the HTML ...