On Mobile Safari on an iPhone 4 or iPhone4S, can you have a border of a div that is 0.5px wide?
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:
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.
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.
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:
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.
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/
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;
}
}
Apple added support for this in OSX Yosemite and iOS 8.
@media (-webkit-min-device-pixel-ratio: 2){
div {
border-width:0.5px;
}
}
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>");
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);
box-shadow: 1px 1px 0px 2px rgba(0, 0, 0, 0.5);
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');
}
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.
© 2022 - 2024 — McMap. All rights reserved.
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 .33333 – Triboluminescent