dtech
dtech

Reputation: 14060

css transform, jagged edges in chrome

I've been using CSS3 transform to rotate images and textboxes with borders in my website.

The problem is that the border look jagged in Chrome, like a (low-resolution) game without Anti-Aliasing. In IE, Opera and FF it looks much better because AA is used (which is still clearly visible but not that bad). I can't test Safari because I don't own a Mac.

The rotated photo and text itself look fine, it is only the border that looks jagged.

The CSS I use is this:

.rotate2deg {
    transform: rotate(2deg);
    -ms-transform: rotate(2deg); /* IE 9 */
    -webkit-transform: rotate(2deg); /* Safari and Chrome */
    -o-transform: rotate(2deg); /* Opera */
    -moz-transform: rotate(2deg); /* Firefox */
}

Is there any way I can fix this, e.g. by forcing Chrome to use AA?

Example below:

Jagged Edges example

Upvotes: 204

Views: 138680

Answers (15)

j.j.
j.j.

Reputation: 2090

In 2024 I have this problem with Chromium and rotated images with a light border on a dark background. My findings and solutions are:

filter: brightness(1);

works perfectly with Chrome desktop. Works not on high resolution devices, e.g. smartphones.

outline: solid transparent;

kind of works on desktop and smartphones. On desktop not as well as filter: brightness(1).

Using both is not perfect for desktop, as it works poor like outline: solid transparent.

So my final solution uses outline for high resolution devices only:

#Chromium img {

    /* for desktop-Chromium */
    filter: brightness(1);              
    
    /* for smartphone/tablet */
    @media (min-resolution: 1.1dppx) {  

        outline: solid 1px transparent;

    }   /* CSS nesting works this way since Chromium 120 */

}

Edit: This depends on graphics hardware. Chrome has a flag
chrome://flags/#ignore-gpu-blocklist.
This affects older desktop computers as well as three of my smartphones (including new ones).

Upvotes: 0

Alvaro
Alvaro

Reputation: 41595

In my case none of the provided solutions worked on Chrome in 2024.

Noe of these:

  • outline: 1px solid transparent;,
  • -webkit-backface-visibility
  • box-shadow: 0 0 1px rgba(255,255,255,0);

But somehow, applying a radius border did!

border-radius: 1px;

Upvotes: 0

Vít Zadina
Vít Zadina

Reputation: 552

For safari 16.2 any of mention solution doesn't work. But I tried rotation and it fix the issue.

 transform: "rotatex(360deg)"

In my case I have problem with video element.

Upvotes: 0

Neven
Neven

Reputation: 4142

In case anyone's searching for this later on, a nice trick to get rid of those jagged edges on CSS transformations in Chrome is to add the CSS property -webkit-backface-visibility with a value of hidden. In my own tests, this has completely smoothed them out.

-webkit-backface-visibility: hidden;

Upvotes: 411

doğukan
doğukan

Reputation: 27371

I've tried all the solutions here and didn't work in my case. But using

will-change: transform;

fixes the jagged issue.

Upvotes: 16

Callam
Callam

Reputation: 1009

Adding a 1px transparent border will trigger anti-aliasing

outline: 1px solid transparent;

Alternatively, add a 1px transparent box-shadow.

box-shadow: 0 0 1px rgba(255,255,255,0);

Upvotes: 28

chaser7016
chaser7016

Reputation: 595

Adding the following on the div surrounding the element in question fixed this for me.

-webkit-transform-style: preserve-3d;

The jagged edges were appearing around the video window in my case.

Upvotes: 2

Nicholas McCreath
Nicholas McCreath

Reputation: 11

Just thought that we'd throw in our solution too as we had the exact same problem on Chrome/Windows.

We tried the solution by @stevenWatkins above, but still had the "stepping".

Instead of

-webkit-backface-visibility: hidden;

We used:

-webkit-backface-visibility: initial;

For us this did the trick 🎉

Upvotes: 1

Kiryl
Kiryl

Reputation: 180

For canvas in Chrome (Version 52)

All listed answers is about images. But my issue is about canvas in chrome (v.52) with transform rotate. They became jagged and all this methods can't help.

Solution that works for me:

  1. Make canvas larger on 1 px for each side => +2 px for width and height;
  2. Draw image with offset + 1px (in position 1,1 instead of 0,0) and fixed size (size of image should be 2px less than size of canvas)
  3. Apply required rotation

So important code blocks:

// Unfixed version
ctx.drawImage(img, 0, 0, 335, 218);
// Fixed version
ctx.drawImage(img, 1, 1, 335, 218);
/* This style should be applied for fixed version */
canvas {
  margin-left: -1px;
  margin-top:-1px;
}        
<!--Unfixed version-->
<canvas width="335" height="218"></canvas>
<!--Fixed version-->
<canvas width="337" height="220"></canvas>

Sample: https://jsfiddle.net/tLbxgusx/1/

Note: there is a lot of nested divs because it is simplified version from my project.


This issue is reproduced also for Firefox for me. There is no such issue on Safari and FF with retina.

And other founded solution is to place canvas into div of same size and apply following css to this div:

overflow: hidden;
box-shadow: 0 0 1px rgba(255,255,255,0);
// Or
//outline:1px solid transparent;

And rotation should be applied to this wrapping div. So listed solution is worked but with small modification.

And modified example for such solution is: https://jsfiddle.net/tLbxgusx/2/

Note: See style of div with class 'third'.

Upvotes: 0

Pegues
Pegues

Reputation: 1773

I've been having an issue with a CSS3 gradient with -45deg. The background slanted, was badly jagged similar to but worse than the original post. So I started playing with both the background-size. This would stretch out the jaggedness, but it was still there. Then in addition I read that other people are having issues too at 45deg increments so I adjusted from -45deg to -45.0001deg and my problem was solved.

In my CSS below, background-size was initially 30px and the deg for the background gradient was exactly -45deg, and all keyframes were 30px 0.

    @-webkit-keyframes progressStripeLTR {
        to {
            background-position: 60px 0;
        };
    }

    @-moz-keyframes progressStripeLTR {
        to {
            background-position: 60px 0;
        };
    }

    @-ms-keyframes progressStripeLTR {
        to {
            background-position: 60px 0;
        };
    }

    @-o-keyframes progressStripeLTR {
        to {
            background-position: 60px 0;
        };
    }

    @keyframes progressStripeLTR {
        to {
            background-position: 60px 0;
        };
    }

    @-webkit-keyframes progressStripeRTL {
        to {
            background-position: -60px 0;
        };
    }

    @-moz-keyframes progressStripeRTL {
        to {
            background-position: -60px 0;
        };
    }

    @-ms-keyframes progressStripeRTL {
        to {
            background-position: -60px 0;
        };
    }

    @-o-keyframes progressStripeRTL {
        to {
            background-position: -60px 0;
        };
    }

    @keyframes progressStripeRTL {
        to {
            background-position: -60px 0;
        };
    }

    .pro-bar-candy {
        width: 100%;
        height: 15px;

        -webkit-border-radius:  3px;
        -moz-border-radius:     3px;
        border-radius:          3px;

        background: rgb(187, 187, 187);
        background: -moz-linear-gradient(
                        -45.0001deg,
                        rgba(187, 187, 187, 1.00) 25%,
                        transparent 25%,
                        transparent 50%,
                        rgba(187, 187, 187, 1.00) 50%,
                        rgba(187, 187, 187, 1.00) 75%,
                        transparent 75%,
                        transparent
                    );
        background: -webkit-linear-gradient(
                        -45.0001deg,
                        rgba(187, 187, 187, 1.00) 25%,
                        transparent 25%,
                        transparent 50%,
                        rgba(187, 187, 187, 1.00) 50%,
                        rgba(187, 187, 187, 1.00) 75%,
                        transparent 75%,
                        transparent
                    );
        background: -o-linear-gradient(
                        -45.0001deg,
                        rgba(187, 187, 187, 1.00) 25%,
                        transparent 25%,
                        transparent 50%,
                        rgba(187, 187, 187, 1.00) 50%,
                        rgba(187, 187, 187, 1.00) 75%,
                        transparent 75%,
                        transparent
                    );
        background: -ms-linear-gradient(
                        -45.0001deg,
                        rgba(187, 187, 187, 1.00) 25%,
                        transparent 25%,
                        transparent 50%,
                        rgba(187, 187, 187, 1.00) 50%,
                        rgba(187, 187, 187, 1.00) 75%,
                        transparent 75%,
                        transparent
                    );
        background: linear-gradient(
                        -45.0001deg,
                        rgba(187, 187, 187, 1.00) 25%,
                        transparent 25%,
                        transparent 50%,
                        rgba(187, 187, 187, 1.00) 50%,
                        rgba(187, 187, 187, 1.00) 75%,
                        transparent 75%,
                        transparent
                    );
        background: -webkit-gradient(
                        linear,
                        right bottom,
                        right top,
                        color-stop(
                            25%,
                            rgba(187, 187, 187, 1.00)
                        ),
                        color-stop(
                            25%,
                            rgba(0, 0, 0, 0.00)
                        ),
                        color-stop(
                            50%,
                            rgba(0, 0, 0, 0.00)
                        ),
                        color-stop(
                            50%,
                            rgba(187, 187, 187, 1.00)
                        ),
                        color-stop(
                            75%,
                            rgba(187, 187, 187, 1.00)
                        ),
                        color-stop(
                            75%,
                            rgba(0, 0, 0, 0.00)
                        ),
                        color-stop(
                            rgba(0, 0, 0, 0.00)
                        )
                    );

        background-repeat: repeat-x;
        -webkit-background-size:    60px 60px;
        -moz-background-size:       60px 60px;
        -o-background-size:         60px 60px;
        background-size:            60px 60px;
        }

    .pro-bar-candy.candy-ltr {
        -webkit-animation:  progressStripeLTR .6s linear infinite;
        -moz-animation:     progressStripeLTR .6s linear infinite;
        -ms-animation:      progressStripeLTR .6s linear infinite;
        -o-animation:       progressStripeLTR .6s linear infinite;
        animation:          progressStripeLTR .6s linear infinite;
        }

    .pro-bar-candy.candy-rtl {
        -webkit-animation:  progressStripeRTL .6s linear infinite;
        -moz-animation:     progressStripeRTL .6s linear infinite;
        -ms-animation:      progressStripeRTL .6s linear infinite;
        -o-animation:       progressStripeRTL .6s linear infinite;
        animation:          progressStripeRTL .6s linear infinite;
        }

Upvotes: 2

chris
chris

Reputation: 597

Chosen answer (nor any of the other answers) didn't work for me, but this did:

img {outline:1px solid transparent;}

Upvotes: 8

mhhorizon
mhhorizon

Reputation: 1359

If you are using transition instead of transform, -webkit-backface-visibility: hidden; does not work. A jagged edge appears during animation for a transparent png file.

To solve it I used: outline: 1px solid transparent;

Upvotes: 133

dtech
dtech

Reputation: 14060

You might be able to mask the jagging using blurred box-shadows. Using -webkit-box-shadow instead of box-shadow will make sure it doesn't affect non-webkit browsers. You might want to check Safari and the mobile webkit browsers though.

The result is somewhat better, but still a lot less good then with the other browsers:

with box shadow (underside)

Upvotes: 1

Aron
Aron

Reputation: 3571

For me it was the perspective CSS property that did the trick:

-webkit-perspective: 1000;

Completely illogical in my case as I use no 3d transitions, but works nonetheless.

Upvotes: 0

Zypherone
Zypherone

Reputation: 211

Try 3d transform. This works like a charm!

/* Due to a bug in the anti-liasing*/
-webkit-transform-style: preserve-3d; 
-webkit-transform: rotateZ(2deg);

Upvotes: 21

Related Questions