skip to Main Content

The following code displays fine on Chrome and Firefox, but on Safari (17, Mac+IpadOS) the bar baselines are changing.

Even weirder (and which makes me think it could be a rendering issue), it can be fixed by changing the height component by a few percent point (like 79% instead of 80%, or 58% instead of 60%).

Any idea on a proper fix?

signal {
  display: inline-block;
  height: 1em;
  width: 1.5em;
  overflow: visible;
  white-space: nowrap;
}

signal>i {
  width: 20%;
  margin-left: 1px;
  display: inline-block;
  height: 40%;
  background-color: #7daa49;
}

signal>i:nth-child(2) {
  height: 60%;
}

signal>i:nth-child(3) {
  height: 80%;
}

signal>i:nth-child(4) {
  height: 100%;
}
<signal class="q4"><i></i><i></i><i></i><i></i></signal>

Display on Chrome/Firefox (correct):

correct bars

Display on Safari (incorrect):

incorrect bars

Note that on Safari it’s not always the same bars who are misaligned, in the screenshot above it’s the first two ones, but in the original issue it is the ones in the middle.

2

Answers


  1. Yes you have a problem when for example 40% does not turn out to be a whole number of pixels.

    It is therefore going to be difficult to use em for this if you need a fully general solution.

    This snippet sets the height to 20px as a demo. 20px gives whole pixel heights. And the result is no misalignment.

    signal {
      display: inline-block;
      height: 20px;
      width: 1.5em;
      overflow: visible;
      white-space: nowrap;
    }
    
    signal>i {
      width: 20%;
      margin-left: 1px;
      display: inline-block;
      height: 40%;
      background-color: #7daa49;
    }
    
    signal>i:nth-child(2) {
      height: 60%;
    }
    
    signal>i:nth-child(3) {
      height: 80%;
    }
    
    signal>i:nth-child(4) {
      height: 100%;
    }
    <signal class="q4"><i></i><i></i><i></i><i></i></signal>

    Here is a different approach, making the signal element a grid.

    <style>
      signal {
        display: grid;
        grid-template-columns: repeat(4, 1fr);
        gap: 1px;
        height: 1em;
        width: 1.5em;
        overflow: visible;
        white-space: nowrap;
        position: relative;
      }
      
      signal>i {
        width: 100%;
        height: 100%;
        --h: 40%;
        background-image: linear-gradient(to top, #7daa49 0 var(--h), transparent var(--h) 100%);
      }
      
      signal>i:nth-child(2) {
        --h: 60%;
      }
      
      signal>i:nth-child(3) {
        --h: 80%;
      }
      
      signal>i:nth-child(4) {
        --h: 100%;
      }
    </style>
    <signal class="q4"><i></i><i></i><i></i><i></i></signal>

    Safari seems happier with that, at least on the version I have (IOS 16) and the height can go back to being based on em.

    Login or Signup to reply.
  2. The problem is due to rounding calculated sizes to integer pixel values, a problem which is always potentially there but becomes more obvious when your element is only a few pixels in size.

    My suggestion would be to use a flexbox to control the layout; it seems to render perfectly.

    .q4 {
      display: inline-flex;
      height: 1em;
      width: 1.5em;
      overflow: visible;
      white-space: nowrap;
      align-items: end;
      gap: 1px;
    }
    
    .q4>i {
      flex: 1 1 0;
      height: 40%;
      background-color: #7daa49;
    }
    
    .q4>i:nth-child(2) {
      height: 60%;
    }
    
    .q4>i:nth-child(3) {
      height: 80%;
    }
    
    .q4>i:nth-child(4) {
      height: 100%;
    }
    <div class="q4"><i></i><i></i><i></i><i></i></div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search