Search code examples
htmlcsstwitter-bootstrapbootstrap-icons

Unsorted icon stack using bootstrap-icons


I'm using bootstrap-icons, which does not yet have an "unsorted" icon like this:

So I'd like to stack two separate icons to achieve that effect:

<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css" rel="stylesheet">

<span class="d-inline-block position-relative" style="height: 1rem; width: 1rem;">
  <i class="bi bi-caret-up position-absolute" style="font-size: 1rem; top: -5px;"></i>
  <i class="bi bi-caret-down position-absolute" style="font-size: 1rem; top: 5px;"></i>
</span>

Run that code snippet, and open it in your browser's devtools - you'll notice the parent wrapper does not properly fit the contents. The parent <span> is smaller than the individual <i> icons. So when used in a table header cell (and other places too), it sometimes looks weird.

How could I fix this?


Solution

  • I have fiddled with your code and learned that:

    • the main span (class .unsorted) has to clip excess character spacing with overflow: hidden
    • line-height is already set to 1 by bootstrap for icons.
    • by default bootstrap icons have vertical-align: -0.125rem causing a slight shift up. I circumvented this by making the icons (<i>) display: grid, which also positions the characters nicely inside .unsorted.
    • A reasonable up/down offset for the characters seems to be 27.35%.

    Additionally I introduced a few CSS custom properties to test various sizes of the combined character: sm, md, xl.

    I know too little of bootstrap to be any use with that, so I created a vanilla CSS solution that seems to work with your bootstrap code.

    snippet

    /* * { outline: 1px dashed } /* for debugging */
    
    body {
        margin: 0;
        min-height: 100vh;
        display: grid; place-items: center;
    }
    .unsorted { background-color: rgb(128,128,128,.4) }
    
    
    /********/
    /* DEMO */
    /********/
    /* A few sizes to test variations */
    .unsorted.sm { --button-size: 1em }
    .unsorted.md { --button-size: 5em }
    .unsorted.xl { --button-size: 9em }
    
    .unsorted {
        overflow: hidden; /* [MANDATORY] */
        font-size: 1rem;
    
        height: var(--button-size);
        width : var(--button-size);
    
        --icon-offset: 27.35%;
    }
    
    .unsorted i {
        display: grid; /* centers the characters */
        font-size: var(--button-size);
    }
    
    /* up/down offset, made to use positive numbers */
    .bi.bi-caret-up   { bottom: var(--icon-offset) }
    .bi.bi-caret-down { top   : var(--icon-offset) }
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css" rel="stylesheet">
    
    <div>
        <span class="d-inline-block position-relative unsorted xl">
          <i class="bi bi-caret-up position-absolute"  ></i>
          <i class="bi bi-caret-down position-absolute"></i>
        </span>
    
        <span class="d-inline-block position-relative unsorted md">
          <i class="bi bi-caret-up position-absolute"  ></i>
          <i class="bi bi-caret-down position-absolute"></i>
        </span>
    
        <span class="d-inline-block position-relative unsorted sm">
          <i class="bi bi-caret-up position-absolute"  ></i>
          <i class="bi bi-caret-down position-absolute"></i>
        </span>
    </div>