css 如何增加伪元素的可单击区域而不改变其显示大小?

mwg9r5ms  于 2023-06-07  发布在  其他
关注(0)|答案(1)|浏览(117)

UPD 2:检查解决方案的标记答案。有一个小错误,与透明度的IOS,我遇到了这可能会或可能不会有在您的情况下。如果你也有同样的经历,请阅读标记答案上的评论。干杯!
UPD:如果你想在上下文中看到它,请查看github repo:https://github.com/LitvinenkoD/activity-generator-based-on-Bored-API
以下是GitHub Pages上的工作版本https://litvinenkod.github.io/activity-generator-based-on-Bored-API/
我正在使用<input type="range">编写一个最小/最大范围选择器。
我希望选择器的拇指在视觉上是小的,但有大的可点击区域的用户体验的目的。
这就是我需要的视觉效果

而这是我想要的引擎盖下的可点击区域

我尝试使用伪元素,但::-moz-range-thumb::-webkit-slider-thumb本身已经是伪元素,因此无法在它们上面添加隐藏的伪元素。
还有一个选项是添加一个不可见的边框,然后执行background-clip: padding-box;,但这会改变输入表单的功能,因为它会将拇指视为实际上更大,并且会影响它们之间的范围。
是否有一个解决方案可以在我的项目中使用?只要我能实现我想要的功能,我就可以做50行的东西。
在此处添加代码:
HTML

<div class="slider">
        <input type="range" class="slider__min-selector" min="0" max="10" step="1">
        <input type="range" class="slider__max-selector" min="0" max="10" step="1">
        
        <div class="slider__background-range-box">
          <div class="slider__range_visualizer"></div>
        </div>
      </div>

<!-- Adds selected values visualization -->
      <div class="range-selector__supporting-text | flexbox-container">
        <p class="range-selector__min-text">0</p>
        <p class="range-selector__max-text">10</p>
      </div>
    </div>

CSS

input[type="range"]::-moz-range-thumb{

  // Removing standard look
  -moz-appearance: none;
  border: none;

  // Styling
  background-color: #F0F0F0;
  cursor: pointer;


  // Visual size I need
  height: 1em;
  width: 1em;
  border-radius: 50%;
  

  // Needed for the thumb to be clickable
  pointer-events: auto;



  // I used the line below to demonstrate
  // the clickable area size I need

  border: 10px solid transparent;

  // Adding this element allows me to hide
  // the border, but the browser treats
  // the element as it was actually larger
  background-clip: padding-box;
}

JS

export class RangeSelector{
  constructor(range_selector_min_tip, range_selector_max_tip, range_visualizer, current_range, sliders_min_gap, range_selector_min_text_visualizer, text_max){
    this.range_selector_min_tip = range_selector_min_tip
    this.range_selector_max_tip = range_selector_max_tip
    this.range_visualizer = range_visualizer

    // This array dynamically updates and always stores the value of min and max selectors
    this.current_range = current_range

    // Minimum acceptable distance between selectors
    this.min_selectors_gap = sliders_min_gap

    this.range_selector_min_text_visualizer = range_selector_min_text_visualizer
    this.text_max = text_max

  }

  // Sets values of the actual tips equal to the values we initialized before
  initializeSlider(){
    this.range_selector_min_tip.value = this.current_range[0]
    this.range_selector_max_tip.value = this.current_range[1]
  }

  // Updates the colored gap between two slider tips
  adjustRangeVisualizer(){
    const left = this.current_range[0] * 10
    const right = 100 - this.current_range[1] * 10
  
    this.range_visualizer.style.left = left + "%"
    this.range_visualizer.style.right = right + "%"
  }

  updateRangeText(){
    this.range_selector_min_text_visualizer.innerText = this.range_selector_min_tip.value
    this.text_max.innerText = this.range_selector_max_tip.value
  }
}
cgfeq70w

cgfeq70w1#

我发现了一个最CSS的方法:使用radial-gradient()创建一个thumb并根据<input>的值修改其位置。

input[type="range"]::-webkit-slider-thumb {
  height: var(--touch-size);
  width: var(--touch-size);
  background: radial-gradient(
    circle at
      calc(
        (100% - var(--thumb-size)) / 10 * var(--value) +
        var(--thumb-size) / 2
      )
      50%,
    #f0f0f0 calc(var(--thumb-size) / 2),
    transparent calc(var(--thumb-size) / 2)
  );
}

需要一点JS来修改内联自定义属性:

inputs.forEach((element, isMax) => {
  element.addEventListener('input', () => {
    element.style.setProperty('--value', element.value);
  });
});

试试看:

const visualizer = document.querySelector('.slider__range_visualizer');
const inputs = document.querySelectorAll('input[type="range"]');

inputs.forEach((element, isMax) => {
  element.addEventListener('input', () => {
    const value = element.value;
    element.style.setProperty('--value', value);

    const property = isMax ? 'right' : 'left';
    const percentage = (isMax ? 10 - value : value) * 10;
    visualizer.style[property] = percentage + '%';
  });
});
:root {
  --thumb-size: 20px;
  --touch-size: 70px;
}

input[type="range"]::-webkit-slider-thumb {
  height: var(--touch-size);
  width: var(--touch-size);
  
  background: radial-gradient(
    circle at
      calc(
        (100% - var(--thumb-size)) / 10 * var(--value) +
        var(--thumb-size) / 2
      )
      50%,
    #f0f0f0 calc(var(--thumb-size) / 2),
    transparent calc(var(--thumb-size) / 2)
  );
  
  /* Just to visualize the actual size */
  outline: 1px solid black;
}

input[type="range"]::-moz-range-thumb {
  height: var(--touch-size);
  width: var(--touch-size);
  
  background: radial-gradient(
    circle at
      calc(
        (100% - var(--thumb-size)) / 10 * var(--value) +
        var(--thumb-size) / 2
      )
      50%,
    #f0f0f0 calc(var(--thumb-size) / 2),
    transparent calc(var(--thumb-size) / 2)
  );
  
  /* Just to visualize the actual size */
  outline: 1px solid black;
}

/* Original styles */

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

.slider {
  position: relative;
  margin: 2em 1em;
  width: 500px;
}

.slider input[type="range"] {
  position: absolute;
  top: 0;
  left: 0;
  appearance: none;
  width: 100%;
  background: none;
  transform: translateY(-50%);
  pointer-events: none;
  z-index: 2;
}

input[type="range"]::-webkit-slider-thumb {
  appearance: none;
  pointer-events: auto;
  cursor: pointer;
  border-radius: 50%;
}

input[type="range"]::-moz-range-thumb {
  appearance: none;
  pointer-events: auto;
  cursor: pointer;
  border-radius: 50%;
}

.slider__background-range-box,
.slider__range_visualizer {
  height: .25em;
  border-radius: .25em;
}

.slider__background-range-box {
  width: 100%;
  position: relative;
  transform: translateY(-50%);
  background-color: grey;
}

.slider__range_visualizer {
  position: absolute;
  left: 0;
  right: 0;
  background-color: pink;
}
<div class="slider">
  <input type="range" class="slider__min-selector" min="0" max="10" step="1" value="0" style="--value: 0;">
  <input type="range" class="slider__max-selector" min="0" max="10" step="1" value="10" style="--value: 10;">
  <div class="slider__background-range-box">
    <div class="slider__range_visualizer"></div>
  </div>
</div>

关于许可的说明:“* 原始样式 *”部分是从您的项目中复制的,到目前为止还没有许可证。为了回答这个问题,我必须要求您在CC BY-SA 4.0或兼容许可证下发布上述代码。如果您拒绝这样做,您可以将此答案标记为侵犯版权。

相关问题