如何正确 trim CSS 中输入范围轨道的边缘?

How to properly trim the edge of an input range track in CSS?

我正在尝试构建一个与此类似的滑块组件:

但是为了达到预期的效果,滑块拇指不会超出线条的边缘。

所以我用 width: calc(80% + 30px); 添加了一点额外的宽度,其中 30px 是拇指的宽度,并给我提供了拇指宽度的一半的悬垂。

但是当我尝试将可见轨道裁剪到 clip-path: polygon(15px -1000%, calc(100% - 15px) -1000%, calc(100% - 15px) 1000%, 15px 1000%); 的大小时,它也会裁剪拇指。

有没有办法在不剪切拇指的情况下正确剪切轨道?

这是我的代码(组织为 .svelte 组件)。

<script>
    export let name;
    let value = 3;
</script>

<style>
    input[type=range] {
        appearance: none;
        position: relative;
        background-color: #b3b3b3;
        width: calc(80% + 30px);
        height: 2px;
        padding: 0;
        top: -22px;
        clip-path: polygon(15px -1000%, calc(100% - 15px) -1000%, calc(100% - 15px) 1000%, 15px 1000%);
        border: none;
    }
    input[type=range]::-webkit-slider-thumb {
        appearance: none;
        width: 30px;
        height: 30px;
        border-radius: 50%;
        background: yellowgreen;
    }
    span {
        margin-left: calc(10% - 8px);
        margin-right: calc(10% - 8px);
        float: left;
        width: 16px;
        height: 16px;
        padding: 0;
        background: #b3b3b3;
        border-radius: 50%;
    }
    .tick-container {
        height: 16px;
        padding: 0;
        justify-content: left;
    }
</style>

<h2>{name}</h2>

<div class="tick-container">
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
</div>
<input on:input={slider => value = slider.target.value} type="range" min="1" max="5" value={value}>

我可能会单独绘制凹槽而不是尝试让它像这样工作。

还有:

  • 您可以 bind 输入 value
  • 有一个容器元素用于指示整体大小会很有帮助
  • Flexbox 结合 justify-content: space-between 可以轻松地 space 从一端到另一端的刻度。
  • 我会尽量避免使用特定大小并尽可能使用百分比来减少依赖性。

这样一个滑块组件的草图:

<script>
    export let value = 3;
</script>

<style>
    .slider {
        position: relative;
        width: 300px;
        height: 30px;
    }
    .track {
        margin: auto;
        width: calc(100% - 30px + 16px);
        position: relative;
        padding: 0;
        top: 50%;
        transform: translateY(-50%);
    }
    .ticks {
        display: flex;
        justify-content: space-between;
    }
    .tick {
        width: 16px;
        height: 16px;
        background: #b3b3b3;
        border-radius: 50%;
    }
    .groove {
        height: 2px;
        background: #b3b3b3;
        position: absolute;
        width: calc(100% - 16px);
        left: 8px;
        top: 50%;
        transform: translateY(-50%);
    }
    input {
        position: absolute;
        appearance: none;
        background: none;
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
        top: 0;
        left: 0;
        border: none;
    }
    input::-webkit-slider-thumb {
        appearance: none;
        width: 30px;
        height: 30px;
        border-radius: 50%;
        background: yellowgreen;
    }
</style>

<div class="slider">
    <div class="track">
        <div class="groove"></div>
        <div class="ticks">
            <span class="tick"></span>
            <span class="tick"></span>
            <span class="tick"></span>
            <span class="tick"></span>
            <span class="tick"></span>
        </div>
    </div>
    <input type="range" min="1" max="5" bind:value> 
</div>

REPL

这还可以improved/extended:

  • 导出 min/max 并通过 {#each}
  • 生成报价
  • 为刻度线和拇指colors/sizes使用自定义属性
  • 与其他浏览器兼容(::-webkit-slider-thumb 是 non-standard)