Issue
I am trying to build a slider component that looks similar to this:
But the slider thumb will not extend past the edge of the line for the desired effect.
So I add a little bit of extra width with width: calc(80% + 30px);
where the 30px is the width of the thumb and gives me a half of a thumb-width of overhang to work with.
But when I try to clip the visible track to size with clip-path: polygon(15px -1000%, calc(100% - 15px) -1000%, calc(100% - 15px) 1000%, 15px 1000%);
, it also clips the thumb.
Is there a way to clip the track properly without clipping the thumb?
This is my code (organized as a .svelte component).
<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}>
Solution
I would probably just draw the groove separately instead of trying to make it work like this.
Also:
- You can just
bind
thevalue
of the input. - It helps to have a container element which is used to dictate the overall size
- Flexbox in combination with
justify-content: space-between
can be used to easily space the ticks from end to end. - I would try to avoid specific sizes and use percentages where possible to decrease dependencies.
A sketch of such a slider component:
<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>
This could be further improved/extended:
- Export
min
/max
and generate the ticks via{#each}
- Use custom properties for the colors/sizes of the ticks and the thumb
- Make compatible with other browsers (
::-webkit-slider-thumb
is non-standard)
Answered By - H.B.
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.