1

All my range <input> elements seem to have extra vertical space after them, preventing them from being packed tightly together vertically, and also preventing placing related elements (like text labels) closely after them vertically.

How do I get rid of this unwanted extra vertical space?

Here's an html+css snippet that demonstrates the problem; it attempts to remove all space between all elements (except for some 1px colored borders for debugging):

<!DOCTYPE html>
<html>
<head>
  <style>

    /*
      pack everything as tightly as possible,
      except some 1px colored borders for debugging
    */
    * {
      margin:0;
      border:10px solid black; /* make anything not covered by rules below look terrible */
      padding:0;
    }
    html { border:1px solid red; }
    body { border:1px solid orange; }
    hr { border:1px solid green; }
    table {
      border:1px solid cyan;
      border-spacing:0;
    }
    td { border: 1px solid blue; }
    div { border:1px solid magenta; }
    input {border:1px solid red; } /* the 1px matters but the red doesn't show?? */

  </style>
</head>
<body>

Three range &lt;input&gt;s separated by &lt;br&gt; (unwanted extra vertical space):
<br>
<input type="range">
<br>
<input type="range">
<br>
<input type="range">

<hr>

Table with three range &lt;input&gt;s in same cell, separated by &lt;br&gt; (unwanted extra vertical space):
<table>
  <tr>
    <td>
      <input type="range">
      <br>
      <input type="range">
      <br>
      <input type="range">
</table>

<hr>

Table with three range &lt;input&gt;s in different cells (unwanted extra vertical space):
<table>
  <tr><td><input type="range">
  <tr><td><input type="range">
  <tr><td><input type="range">
</table>

<hr>

Three &lt;div&gt;s, each with a range &lt;input&gt; inside (unwanted extra vertical space):
<div><input type="range"></div>
<div><input type="range"></div>
<div><input type="range"></div>

<hr>

Three range &lt;input&gt;s separated by &lt;div&gt;s with negative margins (hack to show desired spacing):
<br>
<input type="range">
<div style="margin-top:-5px; margin-bottom:-1px;"></div>
<input type="range">
<div style="margin-top:-5px; margin-bottom:-1px;"></div>
<input type="range">

<hr>

&lt;input&gt; elements of type other than range, to show that the border color (red) works as expected on most of them:
<br>
button:<input type="button" value="button value"></input>
checkbox:<input type="checkbox"></input>
color:<input type="color"></input>
date:<input type="date"></input>
datetime-local:<input type="datetime-local"></input>
email:<input type="email" value="email value"></input>
file:<input type="file"></input>
hidden:<input type="hidden"></input>
image:<input type="image"></input>
month:<input type="month"></input>
number:<input type="number" value="123"></input>
password:<input type="password" value="abc"></input>
radio:<input type="radio"></input>
range:<input type="range"></input>
reset:<input type="reset"></input>
search:<input type="search" value="search value"></input>
submit:<input type="submit"></input>
tel:<input type="tel" value="tel value"></input>
text:<input type="text" value="text value"></input>
time:<input type="time"></input>
url:<input type="url" value="url value"></input>
week:<input type="week"></input>

</body>
</html>

Here's the output of the above snippet in chrome 108.0.5359 on linux; notice that the range <input>s seem to be a bit more widely spaced vertically than necessary:

screenshot of the above code

Inspecting the elements, I observe:

  • This range <input> element is 18 pixels high (16 if I turn off the 1px debugging borders); this looks reasonable:

    inspecting the range input element: it's 18 pixels high

  • The <td> that contains the range <input> is 24 pixels high (22 if I turn off the 1px debugging borders), because it contains 6 pixels of mystery space at the bottom:

    inspecting the td element: it's 24 pixels high

More generally, there seems to be 6 pixels of mystery extra vertical space after each range <input> element. Where is this mystery extra vertical space coming from? Is there a way to get rid of it, without hard-coding the assumption that it's there and how big it is?

Also, less importantly, I'm curious why the border color (red) doesn't seem to have any effect on range <input> elements in the above snippet (the border-width is honored, but the border-color is not).

Don Hatch
  • 5,041
  • 3
  • 31
  • 48

2 Answers2

0

This is being caused by the default line-height (which is 1.2 times the current font size in chrome).

So the line break is actually breaking a new line at that size.

add a line-height of 0 to the td or div or any container it sits in

JSFiddle

Moishy
  • 3,560
  • 3
  • 23
  • 42
  • This works! Still, it's a bit mystifying-- why would a range input care about line-height (which has to do with vertical spacing ot lines of text)? Perhaps it has to do with this sentence from the doc https://developer.mozilla.org/en-US/docs/Web/CSS/line-height :"If the user's browser doesn't support type range, it will fall back and treat it as a text input." But that worries me-- it seemts to imply that there may be cases when the user's browser doesn't support type range, in which case it will turn into a text input, and then `line-height:0` will make it too small. – Don Hatch Jan 03 '23 at 04:40
  • The input by default is display inline block. The line height is the height of the line break you have in there. – Moishy Jan 03 '23 at 14:09
0

This is usually browser specific, but at least in chrome browser, the cause of the extra white space is actually because input has display: inline-block and if you change it to display: block, it won't have extra space.

<!DOCTYPE html>
<html>

<head>
  <style>
    /*
      pack everything as tightly as possible,
      except some 1px colored borders for debugging
    */
    
    * {
      margin: 0;
      border: 10px solid black;
      /* make anything not covered by rules below look terrible */
      padding: 0;
    }
    
    html {
      border: 1px solid red;
    }
    
    body {
      border: 1px solid orange;
    }
    
    hr {
      border: 1px solid green;
    }
    
    table {
      border: 1px solid cyan;
      border-spacing: 0;
    }
    
    td {
      border: 1px solid blue;
    }
    
    div {
      border: 1px solid magenta;
    }
    
    input {
      border: 1px solid red;
      display: block
    }
    /* the 1px matters but the red doesn't show?? */
  </style>
</head>

<body>

  Three range &lt;input&gt;s separated by &lt;br&gt; (unwanted extra vertical space):
  <br>
  <input type="range">
  <br>
  <input type="range">
  <br>
  <input type="range">

  <hr> Table with three range &lt;input&gt;s in same cell, separated by &lt;br&gt; (unwanted extra vertical space):
  <table>
    <tr>
      <td>
        <input type="range">
        <br>
        <input type="range">
        <br>
        <input type="range">
  </table>

  <hr> Table with three range &lt;input&gt;s in different cells (unwanted extra vertical space):
  <table>
    <tr>
      <td><input type="range">
        <tr>
          <td><input type="range">
            <tr>
              <td><input type="range">
  </table>

  <hr> Three &lt;div&gt;s, each with a range &lt;input&gt; inside (unwanted extra vertical space):
  <div><input type="range"></div>
  <div><input type="range"></div>
  <div><input type="range"></div>

  <hr> Three range &lt;input&gt;s separated by &lt;div&gt;s with negative margins (hack to show desired spacing):
  <br>
  <input type="range">
  <div style="margin-top:-5px; margin-bottom:-1px;"></div>
  <input type="range">
  <div style="margin-top:-5px; margin-bottom:-1px;"></div>
  <input type="range">

  <hr> &lt;input&gt; elements of type other than range, to show that the border color (red) works as expected on most of them:
  <br> button:
  <input type="button" value="button value"></input>
  checkbox:<input type="checkbox"></input>
  color:<input type="color"></input>
  date:<input type="date"></input>
  datetime-local:<input type="datetime-local"></input>
  email:<input type="email" value="email value"></input>
  file:<input type="file"></input>
  hidden:<input type="hidden"></input>
  image:<input type="image"></input>
  month:<input type="month"></input>
  number:<input type="number" value="123"></input>
  password:<input type="password" value="abc"></input>
  radio:<input type="radio"></input>
  range:<input type="range"></input>
  reset:<input type="reset"></input>
  search:<input type="search" value="search value"></input>
  submit:<input type="submit"></input>
  tel:<input type="tel" value="tel value"></input>
  text:<input type="text" value="text value"></input>
  time:<input type="time"></input>
  url:<input type="url" value="url value"></input>
  week:<input type="week"></input>

</body>

</html>

As for why the border is not applied to the range slider, it's caused by the appearance: auto, if you change that to appearance: none, it will have the borders shown:

<!DOCTYPE html>
<html>

<head>
  <style>
    /*
      pack everything as tightly as possible,
      except some 1px colored borders for debugging
    */
    
    * {
      margin: 0;
      border: 10px solid black;
      /* make anything not covered by rules below look terrible */
      padding: 0;
    }
    
    html {
      border: 1px solid red;
    }
    
    body {
      border: 1px solid orange;
    }
    
    hr {
      border: 1px solid green;
    }
    
    table {
      border: 1px solid cyan;
      border-spacing: 0;
    }
    
    td {
      border: 1px solid blue;
    }
    
    div {
      border: 1px solid magenta;
    }
    
    input {
      border: 1px solid red;
      appearance: none;
      display: block;
    }
    /* the 1px matters but the red doesn't show?? */
  </style>
</head>

<body>

  Three range &lt;input&gt;s separated by &lt;br&gt; (unwanted extra vertical space):
  <br>
  <input type="range">
  <br>
  <input type="range">
  <br>
  <input type="range">

  <hr> Table with three range &lt;input&gt;s in same cell, separated by &lt;br&gt; (unwanted extra vertical space):
  <table>
    <tr>
      <td>
        <input type="range">
        <br>
        <input type="range">
        <br>
        <input type="range">
  </table>

  <hr> Table with three range &lt;input&gt;s in different cells (unwanted extra vertical space):
  <table>
    <tr>
      <td><input type="range">
        <tr>
          <td><input type="range">
            <tr>
              <td><input type="range">
  </table>

  <hr> Three &lt;div&gt;s, each with a range &lt;input&gt; inside (unwanted extra vertical space):
  <div><input type="range"></div>
  <div><input type="range"></div>
  <div><input type="range"></div>

  <hr> Three range &lt;input&gt;s separated by &lt;div&gt;s with negative margins (hack to show desired spacing):
  <br>
  <input type="range">
  <div style="margin-top:-5px; margin-bottom:-1px;"></div>
  <input type="range">
  <div style="margin-top:-5px; margin-bottom:-1px;"></div>
  <input type="range">

  <hr> &lt;input&gt; elements of type other than range, to show that the border color (red) works as expected on most of them:
  <br> button:
  <input type="button" value="button value"></input>
  checkbox:<input type="checkbox"></input>
  color:<input type="color"></input>
  date:<input type="date"></input>
  datetime-local:<input type="datetime-local"></input>
  email:<input type="email" value="email value"></input>
  file:<input type="file"></input>
  hidden:<input type="hidden"></input>
  image:<input type="image"></input>
  month:<input type="month"></input>
  number:<input type="number" value="123"></input>
  password:<input type="password" value="abc"></input>
  radio:<input type="radio"></input>
  range:<input type="range"></input>
  reset:<input type="reset"></input>
  search:<input type="search" value="search value"></input>
  submit:<input type="submit"></input>
  tel:<input type="tel" value="tel value"></input>
  text:<input type="text" value="text value"></input>
  time:<input type="time"></input>
  url:<input type="url" value="url value"></input>
  week:<input type="week"></input>

</body>

</html>

Note that this is browser specific and different browser could have a different behaviors.

Damzaky
  • 6,073
  • 2
  • 11
  • 16
  • When I run your first snippet, the sliders inside the separate table cells do look better (so this is a usable solution, it seems)... but the ones that are just separated by
    look worse! https://i.stack.imgur.com/sFUG6.png And here is the output of your seconds snippet; the appearance:none seems to damage the slider's appearance (in addition to making the red border appear): https://i.stack.imgur.com/jPdRD.png
    – Don Hatch Jan 03 '23 at 02:07
  • @DonHatch I'm not sure what you're trying to accomplish here, I was just trying to answer for "what's causing this" and "how to get rid of it". If you really want to make it look better for the `
    `, you could tweak the `line-height` for that container, as for the appearance, of course it does break it, if you want to keep it while having a border on it, it's better to use the border on its parent
    – Damzaky Jan 03 '23 at 02:16
  • Thanks. "what I'm trying to accomplish here" (in addition to understanding) is ideally, to get rid of the unexpected extra space after the range input, in a way that's simple and usable anywhere I want to use a range input, with little or no additional consequences that require additional fiddling to fix. It looks to me like you've given two good ways of doing this: (1) make it display:block and wrap it in a single-cell table (2) (from your comment above, and also suggested by @Moishy 's answer) wrap it in a div with line-height:0. – Don Hatch Jan 03 '23 at 02:45
  • @DonHatch if you're aiming to make a standalone input range slider, i'd say keeping it `display: inline-block` is already the best since most inputs are like that, and if that's the case (since it's inline-block), you could just tweak the parent's line-height in which the input is placed, as for the border, I can't think of other ways than changing the `appearance` property and add your own background element (the line alike) for the input, maybe with pseudo `::before` – Damzaky Jan 03 '23 at 07:56