htmlcssflexbox

How can I keep the ticks on my range slider from shifting on small screens?


I have a slider that works well, but if I shrink the screen below 400px the tick marks under the slider do not adjust correctly. I believe the issue is with the max-width of the input[type=range] (24rem) and .tick-marks (19rem). But, I need the smaller width to properly align the button on the ruler with the tick marks.

This is good (window > 400px):

enter image description here

This is wrong (window < 400px):

enter image description here

body {
  display: flex;
  font-family: Dosis;
  font-size: 1rem;
  background: #ffffff;
  height: 100vh;
}

.rangeWrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: auto;
  flex: 0;
  padding: 1rem;
  gap: 1.1rem;
}

input[type=range] {
  display: flex;
  width: 100%;
  max-width: 23rem;
  height: 1.5rem;
  appearance: none;
  /* Standard property */
  -webkit-appearance: none;
  /* Webkit-based browsers */
  background: linear-gradient(180deg, #8f813d, #706048, #7A702A);
  border-radius: 1.5rem;
  outline: 2px ridge hsl(45, 80%, 35%);
  outline-offset: 1rem;
  box-shadow: 0 3px 2px -1px rgba(255, 255, 255, 0.25) inset, 0 0 10px 0 rgba(0, 0, 0, 0.5), 0 0 10px 2px rgba(0, 0, 0, 0.25), 0 8px 4px -3px rgba(0, 0, 0, 0.15);
}

input[type=range]::-webkit-slider-runnable-track,
input[type=range]::-moz-range-track {
  background: #222;
  width: 24rem;
  height: 0.25rem;
  border-radius: 3rem;
  cursor: pointer;
  box-shadow: 0 1px 1px 0 rgba(255, 255, 255, 0.25), 0 2px 2px 0 rgba(255, 255, 255, 0.15);
  border: 1px solid rgba(0, 0, 0, 0.25);
}

input[type=range]::-webkit-slider-runnable-track {
  background: #222;
  width: 24rem;
  height: 0.25rem;
  margin: 0 0.5rem;
}

input[type=range]::-webkit-slider-thumb,
input[type=range]::-moz-range-thumb {
  width: 3rem;
  height: 3rem;
  background: radial-gradient(#444 45%, #555 50%, #222 55%, #8C7853 57.5%, #8C7853 100%), conic-gradient(#4b4b4b 10deg, #777 45deg, #5b5b6b 70deg, #9f9f9f 105deg, #444 140deg, #AAA 185deg, #666 210deg, #999 245deg, #777 285deg, #9f9f9f 320deg, #4b4b4b);
  background-blend-mode: overlay;
  box-shadow: 0 0 1px 1px rgba(255, 255, 255, 0.35) inset, 0 1px 1px 1px rgba(255, 255, 255, 0.25) inset, 0 0 2px 2px rgba(0, 0, 0, 0.15) inset, 0 1px 1px 1px rgba(0, 0, 0, 0.35), 0 3px 2px 1px rgba(0, 0, 0, 0.25), 0 6px 4px 3px rgba(0, 0, 0, 0.15);
  border-radius: 1.5rem;
  cursor: pointer;
}

input[type=range]::-webkit-slider-thumb {
  transform: translatey(-1.375rem);
  width: 3rem;
  height: 3rem;
  background: radial-gradient(#444 45%, #555 50%, #222 55%, #8C7853 57.5%, #8C7853 100%), conic-gradient(#4b4b4b 10deg, #777 45deg, #5b5b6b 70deg, #9f9f9f 105deg, #444 140deg, #AAA 185deg, #666 210deg, #999 245deg, #777 285deg, #9f9f9f 320deg, #4b4b4b);
  background-blend-mode: overlay;
  box-shadow: 0 0 1px 1px rgba(255, 255, 255, 0.35) inset, 0 1px 1px 1px rgba(255, 255, 255, 0.25) inset, 0 0 2px 2px rgba(0, 0, 0, 0.15) inset, 0 1px 1px 1px rgba(0, 0, 0, 0.35), 0 3px 2px 1px rgba(0, 0, 0, 0.25), 0 6px 4px 3px rgba(0, 0, 0, 0.15);
  border-radius: 1.5rem;
  cursor: pointer;
  -webkit-appearance: none;
}

datalist {
  display: flex;
  justify-content: space-between;
  color: hsl(45, 80%, 35%);
  width: 25rem;
  line-height: 1.75;
  transform: translatey(1.4rem);
}

datalist>option {
  z-index: 1;
  display: flex;
  position: relative;
  padding: 0 0.25rem;
  border: 1px solid hsl(45, 80%, 35%);
  border-radius: 0.5rem;
  text-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.25);
  box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.25);
}

datalist>option:before {
  content: '';
  display: inline-block;
  position: relative;
  left: 50%;
  height: 1rem;
  width: 1px;
  background: hsl(45, 80%, 35%);
  transform: translatey(-100%);
}

label {
  text-align: center;
  margin-bottom: .5rem;
  font-size: 1.2rem;
  position: relative;
  top: -.6rem;
}

.container {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
}

.slider-container {
  width: 100%;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  padding-top: 0.5rem;
}

.tick-marks {
  display: flex;
  justify-content: space-between;
  width: 100%;
  max-width: 19rem;
  position: relative;
  margin-top: 1.1rem;
}

.tick {
  position: absolute;
  text-align: center;
  transform: translateX(-50%);
  white-space: nowrap;
}

.tick::before {
  content: "";
  display: block;
  width: 1px;
  height: 10px;
  background: hsl(45, 80%, 35%);
  position: absolute;
  top: -12px;
  left: 50%;
}
<body>
  <div class="container">
    <div class="slider-container">
      <input type="range" id="Sets 2" min="1" max="10" value="1" list="Sets 2_ticks">
      
      <div class="tick-marks"><span class="tick" style="left:0%">1</span><span class="tick" style="left:11%">2</span><span class="tick" style="left:22%">3</span><span class="tick" style="left:33%">4</span><span class="tick" style="left:44%">5</span><span class="tick" style="left:55%">6</span>
        <span class="tick" style="left:66%">7</span><span class="tick" style="left:77%">8</span><span class="tick" style="left:88%">9</span><span class="tick" style="left:100%">10</span>
      </div>
</body>


Solution

  • You're kind of defeating the purpose of flexbox with your absolutely positioned ticks and the lateral translations.

    I also added z-index to the input so it wasn't behind the ticks, which seemed to violate physics.

    body {
      padding-top: 1rem;
    }
    
    input[type=range] {
      display: flex;
      width: 100%;
      max-width: 23rem;
      height: 1.5rem;
      appearance: none;
      background: linear-gradient(180deg, #8f813d, #706048, #7A702A);
      border-radius: 1.5rem;
      outline: 2px ridge hsl(45, 80%, 35%);
      outline-offset: 1rem;
      box-shadow: 0 3px 2px -1px rgba(255, 255, 255, 0.25) inset, 0 0 10px 0 rgba(0, 0, 0, 0.5), 0 0 10px 2px rgba(0, 0, 0, 0.25), 0 8px 4px -3px rgba(0, 0, 0, 0.15);
      z-index: 1;
    }
    
    input[type=range]::-webkit-slider-runnable-track,
    input[type=range]::-moz-range-track {
      background: #222;
      width: 24rem;
      height: 0.25rem;
      border-radius: 3rem;
      cursor: pointer;
      box-shadow: 0 1px 1px 0 rgba(255, 255, 255, 0.25), 0 2px 2px 0 rgba(255, 255, 255, 0.15);
      border: 1px solid rgba(0, 0, 0, 0.25);
    }
    
    input[type=range]::-webkit-slider-runnable-track {
      background: #222;
      width: 24rem;
      height: 0.25rem;
      margin: 0 0.5rem;
    }
    
    input[type=range]::-webkit-slider-thumb,
    input[type=range]::-moz-range-thumb {
      width: 3rem;
      height: 3rem;
      background: radial-gradient(#444 45%, #555 50%, #222 55%, #8C7853 57.5%, #8C7853 100%), conic-gradient(#4b4b4b 10deg, #777 45deg, #5b5b6b 70deg, #9f9f9f 105deg, #444 140deg, #AAA 185deg, #666 210deg, #999 245deg, #777 285deg, #9f9f9f 320deg, #4b4b4b);
      background-blend-mode: overlay;
      box-shadow: 0 0 1px 1px rgba(255, 255, 255, 0.35) inset, 0 1px 1px 1px rgba(255, 255, 255, 0.25) inset, 0 0 2px 2px rgba(0, 0, 0, 0.15) inset, 0 1px 1px 1px rgba(0, 0, 0, 0.35), 0 3px 2px 1px rgba(0, 0, 0, 0.25), 0 6px 4px 3px rgba(0, 0, 0, 0.15);
      border-radius: 1.5rem;
      cursor: pointer;
    }
    
    input[type=range]::-webkit-slider-thumb {
      transform: translatey(-1.375rem);
      width: 3rem;
      height: 3rem;
      background: radial-gradient(#444 45%, #555 50%, #222 55%, #8C7853 57.5%, #8C7853 100%), conic-gradient(#4b4b4b 10deg, #777 45deg, #5b5b6b 70deg, #9f9f9f 105deg, #444 140deg, #AAA 185deg, #666 210deg, #999 245deg, #777 285deg, #9f9f9f 320deg, #4b4b4b);
      background-blend-mode: overlay;
      box-shadow: 0 0 1px 1px rgba(255, 255, 255, 0.35) inset, 0 1px 1px 1px rgba(255, 255, 255, 0.25) inset, 0 0 2px 2px rgba(0, 0, 0, 0.15) inset, 0 1px 1px 1px rgba(0, 0, 0, 0.35), 0 3px 2px 1px rgba(0, 0, 0, 0.25), 0 6px 4px 3px rgba(0, 0, 0, 0.15);
      border-radius: 1.5rem;
      cursor: pointer;
      -webkit-appearance: none;
    }
    
    datalist {
      display: flex;
      justify-content: space-between;
      color: hsl(45, 80%, 35%);
      width: 25rem;
      line-height: 1.75;
      transform: translatey(1.4rem);
    }
    
    datalist>option {
      z-index: 1;
      display: flex;
      position: relative;
      padding: 0 0.25rem;
      border: 1px solid hsl(45, 80%, 35%);
      border-radius: 0.5rem;
      text-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.25);
      box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.25);
    }
    
    datalist>option:before {
      content: '';
      display: inline-block;
      position: relative;
      left: 50%;
      height: 1rem;
      width: 1px;
      background: hsl(45, 80%, 35%);
      transform: translatey(-100%);
    }
    
    label {
      text-align: center;
      margin-bottom: .5rem;
      font-size: 1.2rem;
      position: relative;
      top: -.6rem;
    }
    
    .container {
      display: flex;
      flex-direction: column;
      align-items: center;
      width: 100%;
    }
    
    .slider-container {
      width: 100%;
      max-width: 24rem;
      text-align: center;
      display: flex;
      flex-direction: column;
      align-items: center;
      padding-top: 0.5rem;
    }
    
    .tick-marks {
      display: flex;
      justify-content: space-around;
      width: calc(100% - 3.0rem);
      position: relative;
      margin-top: 1.1rem;
    }
    
    .tick {
      position: relative;
      flex-basis: 10%;
      text-align: center;
      white-space: nowrap;
    }
    
    .tick::before {
      content: "";
      display: block;
      width: 1px;
      height: 10px;
      background: hsl(45, 80%, 35%);
      position: absolute;
      top: -12px;
      left: 50%;
    }
    <body>
      <div class="container">
        <div class="slider-container">
          <input type="range" id="Sets 2" min="1" max="10" value="10" list="Sets 2_ticks">
    
          <div class="tick-marks">
            <span class="tick">1</span>
            <span class="tick">2</span>
            <span class="tick">3</span>
            <span class="tick">4</span>
            <span class="tick">5</span>
            <span class="tick">6</span>
            <span class="tick">7</span>
            <span class="tick">8</span>
            <span class="tick">9</span>
            <span class="tick">10</span>
          </div>
        </div>
      </div>
    
      <div class="container" style="width: 200px; margin: 1rem auto 0;">
        <div class="slider-container">
          <input type="range" id="Sets 2" min="1" max="10" value="1" list="Sets 2_ticks">
    
          <div class="tick-marks">
            <span class="tick">1</span>
            <span class="tick">2</span>
            <span class="tick">3</span>
            <span class="tick">4</span>
            <span class="tick">5</span>
            <span class="tick">6</span>
            <span class="tick">7</span>
            <span class="tick">8</span>
            <span class="tick">9</span>
            <span class="tick">10</span>
          </div>
        </div>
      </div>
    </body>