Search code examples
htmlcsssvgtailwind-cssjsx

Fixing Transparent Line Between Div with Clip-Path and Parent Div


A thin, transparent line appears between the triangular div and its parent div when zoomed. I believe this is likely caused by anti-aliasing in the browser. If there is a way to fix this, I would appreciate it. I have also tried using SVG instead of clip-path, but the issue persists.

<script src="https://cdn.tailwindcss.com"></script>

<div class="bg-red-500 h-[30rem] relative">
  <div class="w-1/2 h-10 md:h-20 bg-inherit absolute transform -translate-y-full [clip-path:polygon(0%0%,100%100%,0%100%)]"></div>
  <div class="w-1/2 h-10 md:h-20 bg-inherit absolute transform -translate-y-full right-0 [clip-path:polygon(100%0%,100%100%,0%100%)]"></div>
  <div class="w-1/2 h-10 md:h-20 bg-white absolute bottom-0 [clip-path:polygon(0%0%,100%100%,0%100%)]"></div>
  <div class="w-1/2 h-10 md:h-20 bg-white absolute bottom-0 right-0 [clip-path:polygon(100%0%,100%100%,0%100%)]"></div>
</div>

The line is more visible when viewed directly rather than from image btw enter image description here


Solution

  • Reproduce the problem only in Chrome, and I suspect this problem is caused by subpixel rendering inconsistencies.

    Seems like the issue only happens when the div's position is moved/pushed to a y-position with subpixels (such as a previous sibling with height:80vh and a screen height that can't be divided by 1.25). This is also the reason why zooming causes this problem to appear/disappear.

    For example, as shown below in Chrome the follow snippet will show the thin spaces in some specific screen size and zoom.

    <script src="https://cdn.tailwindcss.com"></script>
    
    <div class="h-[80vh] border-2 border-sky-500 m-2"></div>
    <footer>
      <div class="bg-red-500 h-[30rem] relative">
        <div id="top-left" class="w-1/2 h-10 md:h-20 bg-inherit absolute transform -translate-y-full [clip-path:polygon(0%0%,100%100%,0%100%)]">
        </div>
        <div class="w-1/2 h-10 md:h-20 bg-inherit absolute transform -translate-y-full right-0 [clip-path:polygon(100%0%,100%100%,0%100%)]">
        </div>
        <div class="w-1/2 h-10 md:h-20 bg-white absolute bottom-0 [clip-path:polygon(0%0%,100%100%,0%100%)]"></div>
        <div class="w-1/2 h-10 md:h-20 bg-white absolute bottom-0 right-0 [clip-path:polygon(100%0%,100%100%,0%100%)]">
        </div>
      </div>
    </footer>

    If subpixel rendering is indeed the problem in your case, this can be fixed by forcing the use of GPU rendering such as using will-change-transform as shown below. (Using a tiny rotate forces subpixel rendering as well, which is setting --tw-rotate in this case.)

    <script src="https://cdn.tailwindcss.com"></script>
    
    <div class="h-[80vh] border-2 border-sky-500 m-2"></div>
    <footer>
      <div class="bg-red-500 h-[30rem] relative will-change-transform">
        <div id="top-left" class="w-1/2 h-10 md:h-20 bg-inherit absolute transform -translate-y-full [clip-path:polygon(0%0%,100%100%,0%100%)]">
        </div>
        <div class="w-1/2 h-10 md:h-20 bg-inherit absolute transform -translate-y-full right-0 [clip-path:polygon(100%0%,100%100%,0%100%)]">
        </div>
        <div class="w-1/2 h-10 md:h-20 bg-white absolute bottom-0 [clip-path:polygon(0%0%,100%100%,0%100%)]"></div>
        <div class="w-1/2 h-10 md:h-20 bg-white absolute bottom-0 right-0 [clip-path:polygon(100%0%,100%100%,0%100%)]">
        </div>
      </div>
    </footer>

    Or, you can simply move the four triangles 1px closer to the edge as a quick solution without any performance disadvantage:

    <script src="https://cdn.tailwindcss.com"></script>
    
    <div class="h-[80vh] border-2 border-sky-500 m-2"></div>
    <footer>
      <div class="bg-red-500 h-[30rem] relative">
        <div id="top-left" class="w-1/2 h-10 md:h-20 bg-inherit absolute transform -translate-y-full [clip-path:polygon(0%0%,100%100%,0%100%)] top-px">
        </div>
        <div class="w-1/2 h-10 md:h-20 bg-inherit absolute transform -translate-y-full right-0 [clip-path:polygon(100%0%,100%100%,0%100%)] top-px">
        </div>
        <div class="w-1/2 h-10 md:h-20 bg-white absolute bottom-0 [clip-path:polygon(0%0%,100%100%,0%100%)] bottom-[-1px]"></div>
        <div class="w-1/2 h-10 md:h-20 bg-white absolute bottom-0 right-0 [clip-path:polygon(100%0%,100%100%,0%100%)] bottom-[-1px]">
        </div>
      </div>
    </footer>

    Or, just use clip-path or SVG to draw the same shape instead of using transform:

    .clipped {
      height: calc(100% + var(--h));
      top: calc(-1 * var(--h));
      clip-path: polygon(0 0, 50% var(--h), 100% 0, 100% calc(100% - var(--h)), 50% 100%, 0 calc(100% - var(--h)));
    }
    <script src="https://cdn.tailwindcss.com"></script>
    
    <div class="h-[80vh] border-2 border-sky-500 m-2"></div>
    <footer>
      <div class="h-[30rem] relative">
        <div class="clipped bg-red-500 relative [--h:2.5rem] md:[--h:5rem]"></div>
      </div>
    </footer>