Tips on how to target the center of a slider thumb with a pointer using CSS and jQuery

One of the features I have implemented is to display the price range and the most repeated price (Mode). In order to illustrate this, I used the range input type but deactivated it so that users cannot move it.

Below you will find my HTML, CSS, and JS code which should provide more clarity on the issue:

<div class="range">
    <div class="sliderValue">
        <span class="show" style="left: ${pinPostion}%;">${mostCommonMaxPrice}</span>
    </div>
    <div class="field">
        <div class="value left">${lowestMinPrice}</div>
        <input type="range" min="${lowestMinPrice}" max="${highestMaxPrice}" value="${mostCommonMaxPrice}" disabled>
        <div class="value right">${highestMaxPrice}</div>
    </div>
</div>
.range{
  height: 40px;
  width: 130px;
  background: #fff;
  border-radius: 10px;
  padding: 0 32.5px 0 22.5px;
}
.field{
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  position: relative;
}
.field .value{
  position: absolute;
  font-size: 12px;
  color: #4638D2;
  font-weight: 600;
}
.field .value.left{
  left: -15px;
}
.field .value.right{
  right: -21.5px;
}
.range input{
  -webkit-appearance: none;
  width: 100%;
  height: 3px;
  background: #ddd;
  border-radius: 5px;
  outline: none;
  border: none;
  z-index: 2222;
}
.range input::-webkit-slider-thumb{
  -webkit-appearance: none;
  width: 10px;
  height: 10px;
  background: #4638D2 !important;
  border-radius: 50%;
  background: #4638D2;
  border: 1px solid #4638D2;
}
 
.range input::-moz-range-progress{
  background: #4638D2;
}
.sliderValue{
  position: relative;
  width: 100%;
  align-items: center;
}
.sliderValue span{
  font-size: 8px;
  position: absolute;
  height: 22.5px;
  width: 22.5px;
  /*transform: translateX(-70%) scale(0);*/
  font-weight: 600;
  top: -15px;
  line-height: 27.5px;
  z-index: 2;
  color: #fff;
  text-align: center;
}
.sliderValue span.show{
  transform: translateX(-70%) scale(1.3);
}
.sliderValue span:after{
  position: absolute;
  content: '';
  height: 100%;
  width: 100%;
  background: #4638D2;
  border: 3px solid #fff;
  z-index: -1;
  left: 50%;
  transform: translateX(-50%) rotate(45deg);
  border-bottom-left-radius: 50%;
  box-shadow: 0px 0px 8px rgba(0,0,0,0.1);
  border-top-left-radius: 50%;
  border-top-right-radius: 50%;
}
const pinPostion = (((mostCommonMaxPrice - lowestMinPrice)/(highestMaxPrice - lowestMinPrice)) * 100) + lowestMinPrice;

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

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

The challenge I am facing is getting the bubble displaying the mode number to accurately point at the slider thumb position. It works well when the percentage is at 100, but for other values, the positioning goes off. I have tried calculating the percentage and passing it as a variable, but it still doesn't align correctly. I am unsure if the issue lies in my CSS or the equation I am using. I would greatly appreciate any help or suggestions on resolving this problem. Thank you!

Answer №1

After researching, I stumbled upon a code example here that utilizes a similar approach to yours for manually calculating the position of the Value Bubble. Here is how it works:

const allRanges = document.querySelectorAll(".range-wrap");
allRanges.forEach(wrap => {
  const range = wrap.querySelector(".range");
  const bubble = wrap.querySelector(".bubble");

  range.addEventListener("input", () => {
    setBubble(range, bubble);
  });
  setBubble(range, bubble);
});

function setBubble(range, bubble) {
  const val = range.value;
  const min = range.min ? range.min : 0;
  const max = range.max ? range.max : 100;
  const newVal = Number(((val - min) * 100) / (max - min));
  bubble.innerHTML = val;

  // Custom adjustments based on the UI thumb size
  bubble.style.left = `calc(${newVal}% + (${8 - newVal * 0.15}px))`;
}
.range-wrap {
  position: relative;
  margin: 0 auto 3rem;
}
.range {
  width: 100%;
}
.bubble {
  background: red;
  color: white;
  padding: 4px 12px;
  position: absolute;
  border-radius: 4px;
  left: 50%;
  transform: translateX(-50%);
}
.bubble::after {
  content: "";
  position: absolute;
  width: 2px;
  height: 2px;
  background: red;
  top: -1px;
  left: 50%;
}

body {
  margin: 2rem;
}
<div class="range-wrap">
  <input type="range" class="range">
  <output class="bubble"></output>
</div>

<div class="range-wrap">
  <input type="range" class="range" min="20" max="940">
  <output class="bubble"></output>
</div>

<div class="range-wrap" style="width: 75%;">
  <input type="range" class="range" min="50" max="60" step="2">
  <output class="bubble"></output>
</div>

<div class="range-wrap" style="width: 55%;">
  <input type="range" class="range" min="-20" max="20">
  <output class="bubble"></output>
</div>

This resource was found at https://css-tricks.com/value-bubbles-for-range-inputs/

Answer №2

It appears that the pinpoint position is not properly aligned to the center of its tip, as it does not take into account the border width.

For example, in this scenario, the pinpoint should be perfectly centered:

variable value
lowestMinPrice 0
highestMaxPrice 100
mostCommonMaxPrice 50
const pinPostion = (((mostCommonMaxPrice - lowestMinPrice)/(highestMaxPrice - lowestMinPrice)) * 100) + lowestMinPrice;
pinPostion = (((50 - 0)/(100 - 0)) * 100) + 0;
pinPostion = 50

The appearance of the pinpoint is achieved through a rotated element with border radius. Removing the radius will result in the following look.

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

If we also remove the transform property, the appearance changes further.

https://i.sstatic.net/6xPO3.png

Even after applying the calculations from your sample code, the pinpoint seems to be slightly misaligned.

.range {
  height: 40px;
  width: 130px;
  background: #fff;
  border-radius: 10px;
  padding: 0 32.5px 0 22.5px;
}

.field {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  position: relative;
}

.field .value {
  position: absolute;
  font-size: 12px;
  color: #4638D2;
  font-weight: 600;
}

.field .value.left {
  left: -15px;
}

.field .value.right {
  right: -21.5px;
}
/* More CSS styles... */
<div class="range">
  <div class="sliderValue">
    <span class="show" style="left: 50%;">50</span>
  </div>
  <div class="field">
    <div class="value left">0</div>
    <input type="range" min="0" max="100" value="50" disabled>
    <div class="value right">100</div>
  </div>
</div>

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

Exploring the World of Infinite Scrolling with React.js and Material_ui

I am currently working on a project using react.js As part of this project, I need to implement a board with infinite scroll similar to Facebook I have a specific question regarding this implementation. When scrolling the board and loading more posts li ...

Issue with router failing to load default route upon application startup

I've been grappling with this issue for the past day and a half and have not made any progress. My goal is to load my angular app and have it default to a specific page when bootstrapped, but it keeps redirecting to a different route. The intended de ...

The keyboard fails to open when trying to input text on a WKWebView

Is there a way to programmatically open the keyboard in a WkWebView for tel text input after a JavaScript function call? I want the keyboard to display for efficiency reasons when a certain input is activated, but it doesn't gain focus automatically. ...

Looking for a way to locate the point where objects intersect in three.js?

My goal is to load 20 objects with random positions in a way that they do not intersect. How can I detect and check for intersections between these objects? for (var i = 0; i < 20; i++) { // Create a material var textureLoader = new ...

What specific CSS selector should be targeted in order to modify the appearance of this button?

I'm attempting to alter the appearance of a button within my Wordpress site, but I've hit a roadblock in identifying the correct element to modify. So far, I've tried targeting: .input#chained-quiz-action-1, however, the button stubbornly re ...

Can I change the names of the data retrieved from this API?

I'm looking to customize the names fetched from an external API in my <span>{{stats.team.name}}</span>. Currently, the output displays full club names like: Manchester City FC Manchester United FC Wolverhampton Wanderers FC Instead, ...

Can you explain the distinction between these two concepts in JavaScript?

I've come across an issue while assigning PHP values to JavaScript. var a = <?php echo 39; ?> JavaScript is throwing an error that says "Uncaught SyntaxError: Unexpected token ILLEGAL". However, when I assign PHP values in a slightly different ...

I am currently working on creating a shopping cart that includes a delete button for removing items with just a click

I am currently working on developing a shopping cart feature that includes a remove button to delete items when clicked. I have achieved this using the filter method. However, I am facing an issue where after deleting an item and then adding it back, the ...

Wait for the reaction from react router history to go back

After clicking the submit button in a form, I need to navigate backwards using history.goBack. However, if there is no previous page in the history, I want to redirect to a screen displaying a thank you message using history.replace. const handleSubmit = ( ...

Begin by introducing a fresh attribute to a JSON entity

Looking for help with modifying JSON data: var myVar = { "9":"Automotive & Industrial", "1":"Books", "7":"Clothing" }; I need to insert a new element at the beginning of the array, resulting in this: var myVar = { "5":"Electroni ...

Trying to retrieve a value from a map in TypeScript and getting the error "map.get is not a function"

I am currently facing an issue with my map implementation where I have strings set as keys and values. However, when attempting to retrieve a value using a key, I encounter an error. Below is the code snippet that I am working with: let map:Map<string, ...

Stop the iframe video when the modal is closed

I'm currently developing a website that incorporates the code showcased in this tutorial to launch a modal window featuring an iframe for playing YouTube or Vimeo videos. The issue arises when, as mentioned in the comments on the tutorial page, there ...

What is the best way to achieve a live text update in a div element using JavaScript?

Here's a code snippet I'm working with: <textarea id="input" onkeydown="pressed()"></textarea> <div id="output"></div> <script> function pressed() { var input = document.getElementById('input').value; ...

By default, the first table row is displayed when using table grouping in AngularJS

I am attempting to display only the first tr in the table and hide all other tr elements by default. I have tried using ng-show and ng-hide but it does not seem to be working as expected. This is not originally my plunker; I used it for reference on group ...

Using the box-sizing property to give two inline-block elements a width of 50% each

Within my parent div with a padding of 20px, I am trying to make two span tags each occupy 50% of the parent div's width and align on the same line. Despite using box-sizing: border-box, the issue persists. HTML <div> <span>foo</span ...

What is the best way to eliminate the space underneath a graph?

Despite trying multiple solutions, I'm still struggling to remove the excess blue space below the graph that appears when clicking the submit button. Any insights into what might be causing this issue? JSFIDDLE Below are the CSS styles related to t ...

Split a JavaScript string at a mathematical operator while ensuring that the operator is still included in

Hello there, I am attempting to break down a string of text into an array whenever a '+' or '-' is present. First of all, I am looking for a way to split at the plus sign and ensure it is included in the array. I have experimented with ...

Problem with roles assigned through reactions on Discord

I've been working on a discord bot reaction roles command and everything seems to be going smoothly, except for one issue that I'm facing. After booting up the bot and running the command to create the embed, everything works fine. However, when ...

How can I implement conditional cell rendering on the MUI Datagrid depending on the checkboxSelection?

I need help creating a dynamic cellRender function in a datagrid that will remove a number counter component from a row when its checkbox is checked. Is it possible to achieve this using params? If not, what alternative approaches could I take? const colu ...

Can node.js be run on a server alongside another JavaScript file?

I have developed a small web application on my personal server. It consists of a few HTML, CSS, and JavaScript files. I am looking to incorporate Node.js with the following simple code: var mysql = require('mysql'); var fs = require('fs&apos ...