Search code examples
cssresponsivetranslate-animation

Is it possible to round values in css? Or, how to solve half/sub-pixels on % translated layouts?


I have a curious problem. I built a flex/grid fullscreen responsive interface. I used % values. It works fine, but sometimes, randomly, by resizing the window a 1 px line appears between item (horizontal, vertical, or both). I think maybe that's because, using % values and being the elements liquid, the items size is not always perfect-pixel. Look:

enter image description here

How could I avoid that, still maintaining a responsive layout?

I managed to somewhat good by very little scaling the inner elements (images and rollover layers) like scale(1.005), but still it was not always perfect. The problem is that browsers can't round element sizes on fullscreen layouts, or something like that, don't know.

Just a little abstraction of my original code, just to add context. It's a 3 cols flex layout where 1 col is 50% width (the third one is off screen > the overall behaves like a 3 panels 'slideshow'). The second column, itself contains the grid on the picture:

/* HTML */

<div class="sections-list">
  <div class="section column-1"></div>

  <div class="section column-2">
    <div class="grid">
      <button type="button">a</button>
      <button type="button">b</button>
      <button type="button">c</button>
      <button type="button">d</button>
    </div>  
  </div>

  <div class="section column-3"></div>
</div>


/* SCSS */

.sections-list{
  display: flex;
  justify-content: flex-start;
  min-height: 100vh;

  translateX(-50%);
}

.section{
  flex-grow:1;
  min-width: 50%;
  box-sizing:border-box;
  min-height: 100vh;
}

.grid{
  display: grid;
  height: 100%;
  grid-template:
    "a   b" 50%
    "c   d" 50%
    / 50% 50%;

  button{
    display: block;
    position: relative;
    overflow: hidden;
    padding: 0;
    min-width: none;
    max-width: none;
    height: auto;

    &:nth-child(1){ grid-area: a; }
    &:nth-child(2){ grid-area: b; }
    &:nth-child(3){ grid-area: c; }
    &:nth-child(4){ grid-area: d; }
  }
}

Solution

  • So, it turns out the problem was caused by the 50% translation on the main element. That caused half pixels when window.width was odd.

    The solution to me was to recalculate and round the translation using a little javascript, css --properties and a fallback for legacy browsers. Here's some simplified code (and please look to the original's code too):

    :root{
      --half-window: -50%;
    }
    
    .sections-list{
      display: flex;
      justify-content: flex-start;
      min-height: 100vh;
    
      transform: translatex(-50%); // legacy
      transform: translatex(var(--half-window));
    }
    

    then:

    function round_half_window(){
      document.documentElement.style.setProperty('--half-window', -Math.round($(window).width()/2) + 'px');
    }
    
    $window.resize(_.debounce(function(){ round_half_window(); },500));
    round_half_window();