Skip to main content
Ben Nadel at CFUNITED 2009 (Lansdowne, VA) with: John Watson
Ben Nadel at CFUNITED 2009 (Lansdowne, VA) with: John Watson ( @wizputer )

Sanity Check: Chrome 63 Still Causes Blurry Borders With Percentage-Based CSS Translation

By on
Tags:

The other day, I looked at creating slightly off-center elements using CSS Flexbox and "spacer" flex-children with a 40/60 flex-basis split. Afterwards, in an offline conversation that I was having with Matt Vickers - one of our lead front-end developers at InVision - he suggested using a CSS transform with a -50% translateX / translateY. In the past, I've shied away from using CSS transforms for "centering" purposes because I've seen it cause blurry content in the Chrome browser. But, it's been a while since I've experimented with it. As such, I wanted to do a quick sanity check to see if it's still happening. And, unfortunately, it appears that Chrome still renders half-pixels (causing blurry content) with percentage-based CSS translations.

Run this demo in my JavaScript Demos project on GitHub.

To see this in action, all we have to do is setup an element with an odd height and a -50% CSS translateX / translateY transformation:

<!doctype html>
<html>
<head>
	<meta charset="utf-8" />

	<title>
		Sanity Check: Chrome 63 Still Causes Blurry Borders With Percentage-Based CSS Translation
	</title>

	<style type="text/css">

		div.popup {
			background-color: #FFFFFF ;
			border: 1px solid #000000 ;
			border-radius: 4px 4px 4px 4px ;
			box-sizing: border-box ;
			font-size: 18px ;
			left: 50% ;
			padding: 20px 20px 20px 20px ;
			position: absolute ;
			top: 50% ;

			/*
				In this case, the height of the pop-up is being explicitly set to an ODD
				pixel value (201px). This is causing the -50% translation to move the
				element to a half-pixel location in Chrome, which is, in turn, causing
				borders to become blurry (both on the element and on embedded elements).

				DATE: 2018-01-06.
			*/
			height: 201px ;
			width: 400px ;
			transform: translateX( -50% ) translateY( -50% ) ;
				-ms-transform: translateX( -50% ) translateY( -50% ) ;
				-webkit-transform: translateX( -50% ) translateY( -50% ) ;
		}

		form {
			margin: 25px 0px 25px 0px ;
		}

		input {
			border: 1px solid #000000 ;
			font-size: 18px ;
			padding: 4px 6px 4px 6px ;
		}

	</style>
</head>
<body ng-controller="AppController">

	<h1>
		Sanity Check: Chrome 63 Still Causes Blurry Borders With Percentage-Based CSS Translation
	</h1>

	<div class="popup">
		This pop-up is positioned in the middle of the page,
		with ( -50% , -50% ) CSS transform.

		<form>
			<input placeholder="I am an input..." />
		</form>

		... and contains an input with a border.
	</div>

</body>
</html>

The odd height value causes the -50% translation to move the element up to a half-pixel location. Of course, changing the height of the element to be an even pixel value would fix this in Chrome; however, having explicit height control over a content container is rarely a possibility (not without some sort of JavaScript-based intervention). That said, the issue is clearly illustrated when you see a side-by-side screenshot of the demo with both an odd and an even pixel height:

CSS transform with percentage-based translation can cause blurry borders in Chrome browser.

As you can see, the translateY(-50%) on the left causes the Div and Input borders to be blurry. And, the same demo on the right, with an even pixel height, causes no blurring at all.

You could argue that the difference is so slight that it's not worth worrying about. But, this blurry border situation is far too intense for my design OCD (Obsessive Compulsive Disorder) to handle. It's the very first thing that I see when I look at this page (and other pages that exhibit this behavior). So, for me personally, this potential blurring makes this particular approach to centering a non-starter; unless, I know exactly how tall the content container is going to be; or, I'm not using a percentage-based translation.

Want to use code from this post? Check out the license.

Reader Comments

15,674 Comments

@Guilherme,

It's frustrating, right? I've been trying to use Flexbox layouts more and more and have found them to be very useful, and with pretty solid support.

15,674 Comments

@Lorin,

Meh :( Seems like they could so easily just round the px value and make this work. Must be much more complicated than it is in my head.

1 Comments

I had make myself a JS function to change the CSS translateY by 0.5px on my modals, because whole content of a modal was blurry.

Its quite simple, but works fine for my needs.

	function fixBlurryChromeTranslateY(parent, elem) {
		if (parent.innerHeight % 2 && (elem.clientHeight || elem.offsetHeight) % 2) {
			elem.style.transform = 'translateY(calc(-50% + 0.5px))';
		} else {
			elem.style.transform = '';
		}
	}
1 Comments

Your, and mine, OCD needs backface-visibility: hidden; and a translateZ(1) if using percentages.

1 Comments

I ended up using:

position: absolute;
top: 50%;
-webkit-transform: translate3d(0,0,0);
transform: translateY(-50%);

I got this from here: https://github.com/mgcrea/angular-strap/issues/1234

On the parent container with the form. My whole form was blurry. This feels like it's an associated issue, but I don't know. Some good ideas in this thread at any rate just to try things out.

15,674 Comments

@Kat,

Another thing that I've become a huge fan of lately is using flexbox to center things. If you have a flex container, and the item inside it has margin:auto, then it will be centered vertically and horizontally. So, imagine that I had something like this:

<style type="text/css">
	.container {
		bottom: 0px ;
		display: flex ;
		left: 0px ;
		position: fixed ; 
		right: 0px ;
		top: 0px ;
	}
	.container form {
		margin: auto auto auto auto ;
	}
</style>

<div class="container">
	<form>
		<!-- .... more things ... -->
	</form>
</div>

... then, the container will cover the entire viewport and the form inside of it will be centered in the middle. I've started to use this approach more than translation; but, I just happen to be a huge fan of css flexbox, so I am a bit biased :D

15,674 Comments

@MiChAeLoKGB,

That's an interesting idea. If this were an Angular context, I could see putting something like that as an Attribute Directive right no the modal to perform the calculations in the background.

2 Comments

Seems to still be an issue in Chrome v76 for macOS.

This actually seems to affect images as well. The behavior we are seeing is compounded if the image has both an odd width and an odd height.

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel