DEV Community

Mohamed Idris
Mohamed Idris

Posted on

Why Chrome Draws a Dark Line on Your CSS Scalloped Edge (and How to Fix It)

You've built a scalloped (wavy) edge using a repeating radial-gradient on a pseudo-element. It looks perfect in Firefox. You open Chrome, and there's a faint dark line running along the entire edge.

Scalloped edge with a 1px dark line visible in Chrome

This is a Chrome sub-pixel rendering bug, and it comes down to one thing: what transparent actually means in CSS.

The Setup

A typical scalloped edge uses a repeating radial gradient to punch semi-circular cutouts into a solid strip:

.element::after {
  content: '';
  position: absolute;
  width: 14px;
  height: 100%;

  background: radial-gradient(
    ellipse 10px 8px at 0 50%,
    transparent 99%,
    #1a3a2a 100%
  );
  background-size: 14px 20px;
  background-repeat: repeat-y;
}
Enter fullscreen mode Exit fullscreen mode

The center of each ellipse is transparent (the cutout), the outside is your solid color. The 99% → 100% creates a near-hard stop with just enough room for anti-aliasing.

Why Chrome Shows a Line

transparent in CSS is rgba(0, 0, 0, 0) — transparent black.

When Chrome interpolates between transparent and your color at that gradient boundary, it mixes through black. Even though the transition space is tiny, Chrome renders a visible sub-pixel line of the intermediate color:

transparent = rgba(0, 0, 0, 0)   ← black at zero alpha
your color  = rgba(26, 58, 42, 1)

Chrome blends through that black → dark line artifact
Enter fullscreen mode Exit fullscreen mode

Firefox handles this boundary more gracefully — no visible artifact.

What Didn't Work: color-mix()

The intuitive fix is to replace transparent with a zero-opacity version of your actual color so Chrome blends between the same hue:

background: radial-gradient(
  ellipse 10px 8px at 0 50%,
  color-mix(in srgb, #1a3a2a 0%, transparent) 99%,
  #1a3a2a 100%
);
Enter fullscreen mode Exit fullscreen mode

In theory, this eliminates the black-channel bleed. In practice, the line persisted — Chrome's sub-pixel rendering still produced a visible artifact at the gradient boundary.

What Works: CSS Masks

The fix is to separate color from shape. Instead of using the gradient for both, make the background a flat solid color and move the shape into a mask-image.

Option 1: Gradient Mask

The quickest change — move the same gradient from background to mask-image:

.element::after {
  content: '';
  position: absolute;
  width: 14px;
  height: 100%;

  /* Flat color — nothing to interpolate */
  background: #1a3a2a;

  /* Shape defined by mask alpha channel only */
  mask-image: radial-gradient(
    ellipse 10px 8px at 0 50%,
    transparent 99%,
    #000 100%
  );
  mask-size: 14px 20px;
  mask-repeat: repeat-y;
}
Enter fullscreen mode Exit fullscreen mode

CSS masks only read the alpha channel. The gradient transitions from alpha 0 to alpha 1 — a pure opacity operation with no color data for Chrome to mix through. No color mixing → no dark line.

Option 2: SVG Mask (More Control)

If you need precise control over scallop shape — like elongated bumps or specific aspect ratios — an inline SVG mask gives you that:

.element::after {
  content: '';
  position: absolute;
  width: 20px;
  height: 100%;

  background-color: inherit;

  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'
    width='20' height='28'%3E%3Cdefs%3E%3Cmask id='m'%3E%3Crect width='20'
    height='28' fill='white'/%3E%3Cellipse cx='0' cy='14' rx='10' ry='12'
    fill='black'/%3E%3C/mask%3E%3C/defs%3E%3Crect width='20' height='28'
    mask='url(%23m)' fill='white'/%3E%3C/svg%3E");
  mask-size: 20px 28px;
  mask-repeat: repeat-y;
}
Enter fullscreen mode Exit fullscreen mode

Here's the decoded SVG for clarity:

<svg xmlns="http://www.w3.org/2000/svg" width="20" height="28">
  <defs>
    <mask id="m">
      <rect width="20" height="28" fill="white"/>
      <ellipse cx="0" cy="14" rx="10" ry="12" fill="black"/>
    </mask>
  </defs>
  <rect width="20" height="28" mask="url(#m)" fill="white"/>
</svg>
Enter fullscreen mode Exit fullscreen mode

White areas are visible, the black ellipse is cut out. You can tweak rx and ry independently to control scallop width and height, or swap in a <path> for non-circular shapes. Both approaches fix the Chrome line for the same reason: flat background color + mask handles shape through alpha only.

Scalloped edge without the 1px line after the SVG mask fix

Summary

Approach Result in Chrome
transparent keyword in gradient Dark line (blends through black)
color-mix() to 0% opacity Still a line (sub-pixel rendering)
mask-image (gradient or SVG) with solid background Clean

If you have a radial-gradient scalloped edge showing a line in Chrome, move the shape to mask-image and set background to your solid color. Use a gradient mask for a quick fix, or an SVG mask when you need precise control over the scallop shape. Either way, masks eliminate color interpolation entirely — which is the root cause.

Top comments (0)