Nikita Vasilyev

CSS, Retina, and Physical Pixels

On retina screens CSS pixels don’t match device (physical) pixels. A device pixel ratio of 2 means one CSS pixel equals two device pixels. Here are few ways to draw a one-device-pixel border.

Half-pixel border

border: 0.5px solid black;

Cons:

  • Works only in Firefox and Safari 8 (introduced in OS X Yosemite).

border-image

border-width: 1px;
border-image: url(border.gif) 2 repeat;

border.gif is a 6×6 pixel image:


border-image.com
demonstrates how it’s sliced.

Pros:

  • It works!

Cons:

  • An external image. It’s only 51 bytes and it can be inlined using Data URI. You’d need to fire up Photoshop (or whatever you use) to change the border color, which isn’t very convenient.

Multiple background images

background:
	linear-gradient(180deg, black, black 50%, transparent 50%) top    left  / 100% 1px no-repeat,
	linear-gradient(90deg,  black, black 50%, transparent 50%) top    right / 1px 100% no-repeat,
	linear-gradient(0,      black, black 50%, transparent 50%) bottom right / 100% 1px no-repeat,
	linear-gradient(-90deg, black, black 50%, transparent 50%) bottom left  / 1px 100% no-repeat;

How to target physical pixels on retina screens with CSS” describes how to draw a line. Draw 4 lines and we have a border.

Pros:

  • No external images.

Cons:

  • Cumbersome syntax, although it can be abstracted out with CSS preprocessors.

Scale up and down

.retina-border-scale {
	position: relative;
}
.retina-border-scale:before {
	content: '';
	border: 1px solid black;
	transform: scale(0.5);
	transform-origin: 0 0;
	width: 200%;
	height: 200%;
	position: absolute;
	left: 0;
	top: 0;
	pointer-events: none;
}

Yes We Can Do Fraction of a Pixel” explains the method in great detail.

Pros:

  • Supports rounded-corners, although it looks unpleasant on retina.
  • No external images.

Cons:

  • Forces relative or absolute positioning; doesn’t work for <td>.

Are those non-retina backward compatible?

No, none of them are. Media queries to the rescue:

.thin-border {
	border: 1px solid rgba(0, 0, 0, 0.5);
}
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
	.thin-border {
		border-image: url(border.gif) 2 repeat;
	}
}

Browsers supported

I tested in Chrome 31, Safari 7, Firefox 26, and iOS 7 — all worked.

Published by
Nikita Vasilyev
· Updated