Can you have a 0.5px border on a Retina Display?
Asked Answered
O

10

10

On Mobile Safari on an iPhone 4 or iPhone4S, can you have a border of a div that is 0.5px wide?

Ohl answered 27/12, 2011 at 1:55 Comment(0)
P
8

I wrote an overview of different techniques:

Half-pixel border

border: 0.5px solid black;

Cons:

  • Works only in Firefox and Webkit Nightly.

border-image

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

border.gif is a 6×6 pixel image:

border image explained

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

Mentioned here already by Priit Pirita.

Peacemaker answered 8/1, 2014 at 7:58 Comment(0)
T
9

Use border-width: 0.5px

Safari 8 (in both iOS and OS X) brings border-width: 0.5px. You can use that if you’re ready to accept that current versions of Android and old versions of iOS and OS X will just show a regular border (a fair compromise in my opinion).

You can’t use this directly though, because browsers that don’t know about 0.5px borders will interpret it as 0px. No border. So what you need to do is add a class to your <html> element when it is supported:

if (window.devicePixelRatio && devicePixelRatio >= 2) {
  var testElem = document.createElement('div');
  testElem.style.border = '.5px solid transparent';
  document.body.appendChild(testElem);
  if (testElem.offsetHeight == 1)
  {
    document.querySelector('html').classList.add('hairlines');
  }
  document.body.removeChild(testElem);
}
// This assumes this script runs in <body>, if it runs in <head> wrap it in $(document).ready(function() {   })

Then, using retina hairlines becomes really easy:

div {
  border: 1px solid #bbb;
}

.hairlines div {
  border-width: 0.5px;
}

Best of all, you can use border-radius with it. And you can use it with the 4 borders (top/right/bottom/left) as easily.

Source: http://dieulot.net/css-retina-hairline

Tl answered 18/9, 2014 at 10:30 Comment(4)
on a 3x screen with border: .5px it sometimes gives me a hairline pixel on 3 sides and no pixel on the fourth side :-/ Which is very odd since .5 is greater than .33333Triboluminescent
3x screens are now quite common - such as all current iPhone models (except XR)Triboluminescent
@Triboluminescent can you share some more references on 3x screen? I'm facing the exact same issue you mentioned above, that pixel is not shown on one edge, but shown on other 3 edgeRaimundo
I never found a solution to getting a reliable hairline border. Of course even if you can get a 1 device pixel border you need to remember the line gets thinner between 1x, 2x and 3x screens so even if there is a way to do it - it wouldn't be a perfect solution. I guess that's probably why there's no easy way to do it. Higher DPI is meant to improve clarity - not ruin your design by making lines almost invisible!Triboluminescent
P
8

I wrote an overview of different techniques:

Half-pixel border

border: 0.5px solid black;

Cons:

  • Works only in Firefox and Webkit Nightly.

border-image

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

border.gif is a 6×6 pixel image:

border image explained

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

Mentioned here already by Priit Pirita.

Peacemaker answered 8/1, 2014 at 7:58 Comment(0)
S
6

Yes. Use scale. The style below will give you hairline

 .transform-border-hairline {
     border-bottom: 1px #ff0000 solid;
     transform: scaleY(0.5);
 }

When you need all sides, then the best way is to repliacte the DIV with :after or :before CSS pseudoclass, apply border to that pseudoclass, make it twice the size and then scale it with transform:scale down to half.

pre:before {
    position: absolute;
    top: 0;
    left: 0;
    width: 200%;
    height: 200%;
    border: 1px #999 solid;
    content: "";
    transform: scale(0.5);
    -webkit-transform: scale(0.5);
    transform-origin: 0 0;
    -webkit-transform-origin: 0 0;
}

More specificly (and all those tricks in use too) here http://atirip.com/2013/09/22/yes-we-can-do-fraction-of-a-pixel/

Scever answered 25/9, 2013 at 6:32 Comment(0)
V
4

I use CSS custom properties for this. It is much more elegant (IMHO).

:root {
    --hair:1px;
}

.myDiv {
    border: var(--hair) solid #CCC;
}

@media (-webkit-min-device-pixel-ratio:2),(min-resolution:192dpi),(min-resolution:2dppx) {
    :root {
        --hair:0.5px;
    }
}
Vondavonni answered 4/2, 2020 at 10:0 Comment(2)
I would like to know if in 2023 still exists the danger that browsers “not knowing about 0.5px" interpret it as 0px. I have the feeling that nowadays one can safely use it without any concerns. Or queries or else. But I am not sure.Ketonuria
I just tested it on my Macbook Pro (macOS Sonoma 14.4), which has a retina screen. Using Chrome (v123), a border of 0.5px shows up very thin on the retina screen, and when I moved the window over to the normal non-retina screen (1080p external display), it showed up as a 1px border.Valval
E
2

Apple added support for this in OSX Yosemite and iOS 8.

@media (-webkit-min-device-pixel-ratio: 2){
    div {
        border-width:0.5px;
    }
}
Elegiac answered 11/6, 2014 at 18:36 Comment(0)
D
2

Also I've found this method working (iOS7):

    background: repeat-x top left url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='1' height='1'><rect fill='#ff0000' x='0' y='0' width='1' height='0.5'/></svg>");
Donnettedonni answered 11/7, 2014 at 22:21 Comment(0)
V
1

With CSS that can be done using box-shadow and spread radius. The approach is explained here: http://bradbirdsall.com/mobile-web-in-high-resolution

This is copied from the link above:

box-shadow: inset 0 0 1px #000,
            inset 0 1px 0 #75c2f8,
            0 1px 1px -1px rgba(0, 0, 0, .5);
Vienna answered 20/11, 2012 at 21:37 Comment(1)
This didn't work for me. Is it possible that this was a bug that got fixed in more recent versions of iOS?Armagnac
T
1
box-shadow: 1px 1px 0px 2px rgba(0, 0, 0, 0.5);
Thoroughbred answered 13/2, 2022 at 19:25 Comment(0)
D
0

Sharing a Sass/SCSS + Compass mixin I wrote and I've been using:

@mixin hairline($color, $side: 'top') {
  &:before {
    content: ' ';
    display: block;
    @if $side == 'top' {
      width: 100%;
      height: 1px;
    }
    @else if $side == 'bottom' {
      width: 100%;
      height: 1px;
    }
    @else {
      width: 1px;
      height: 100%;
    }
    position: absolute;
    #{$side}: 0;
    background-color: $color;
    @media (-webkit-min-device-pixel-ratio: 2) {
      @if $side == 'top' {
        @include transform(scaleY(0.5));
      } @else if $side == 'bottom' {
        @include transform(scaleY(0.5));
      } @else {
        @include transform(scaleX(0.5));
      }
    }
  }
}

CSS example:

.my-element-where-i-need-a-retina-bottom-border {
  @include hairline(red, 'bottom');
}
Dimple answered 28/7, 2014 at 2:48 Comment(0)
B
-1

I'm not sure what you mean exactly. If you are asking if you can draw a border of 1 px on an iPhone 4 which would be 1/2 the physical size of the border on an iphone3G, then yes. CoreGraphics uses points instead of pixels. As you can see by the following method, you can specify a float:

void CGContextSetLineWidth (
   CGContextRef c,
   CGFloat width
);

Since 1point != 1px, you can specify 1px on an iPhone4 by specifying 0.5point.

Read up on it here

Bilski answered 27/12, 2011 at 2:3 Comment(2)
Also worth noting: on a non-Retina display, partial points may get rounded up in ways you cannot predict. Or rather, you can safely assume it will get rounded up to a full screen-pixel but the color will probably be an average of the colors that were present on a Retina display. For instance, a double border line of a thin red and thin blue lines on Retina might become a purple 1px (screen) line on an iPhone 3GS. I wouldn't count on this as set in stone, though. Always better to just provided Retina and non-Retina assets if you plan to support both devices, so you know how things will degrade.Persnickety
I just mean in the browser with css :)Ohl

© 2022 - 2024 — McMap. All rights reserved.