What caused the 1px problem?
In mobile Web development, the border is set to 1 pixel in the UI design draft. If border:1px appears in the front end during the development process, it will be found in the test that 1px is thicker in Retina models, which is the classic 1px pixel problem in mobile.
For the iphone6, for example, the width of the screen is 375px, and the designer’s artwork is usually 750px, which is 2x. In this case, the designer drew a 1px border on the artwork. 1px border problem arises.
For the designer it’s 1px relative to 750px (physical pixels), for you it’s 1px relative to 375px (CSS pixels), so you should actually border:0.5px.
How to solve it?
plan | advantages | disadvantages |
---|---|---|
0.5 px implementation | Code is simple, use CSS | Older IOS and Android devices are not supported |
Border – image | Compatible with all current models | Changing the color is not convenient |
Viewport + REM implementation | A set of code for all pages | Just like the 0.5px, the model is not compatible |
Pseudo-element + transform implementation | Compatible with all models | Rounded corners are not supported |
Box-shadow simulation border implementation | Compatible with all models | Box-shadow is not in the box model |
SVG implementation | Simple implementation, can achieve rounded corners | Need to learnsvg grammar |
0.5 px implementation
.border-1px { border: 1px solid # 999 }
@media screen and (-webkit-min-device-pixel-ratio: 2) {
.border-1px { border: 0.5 px. solid # 999}}If DPR =2 and DPR =3, the border is the same
@media screen and (-webkit-min-device-pixel-ratio: 3) {
.border-1px { border: 0.333333 px. solid # 999}}Copy the code
However, in IOS7 and below and other systems like Android, 0.5px will be displayed as 0px. So we need to check with JS whether the browser can handle the 0.5px border
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);
}
Copy the code
- Pros: Simple, no side effects
- Cons: Support iOS 8+, Android to be compatible
Use a border-image implementation
Based on media query, judge different device pixel ratios to give different border-images:
.border-1px{
border-bottom: 1px solid # 000;
}
@media only screen and (-webkit-min-device-pixel-ratio:2) {.border_1px{
border-bottom: none;
border-width: 0 0 1px 0;
border-image: url(../img/1pxline.png) 0 0 2 0stretch; }}Copy the code
Disadvantages: replacing the color requires replacing the picture, the rounded corners are blurred
Viewport + REM implementation
Set the scaling to make the CSS pixels equal to the actual physical pixels.
const scale = 1 / window.devicePixelRatio;
const viewport = document.querySelector('meta[name="viewport"]');
if(! viewport) { viewport =document.createElement('meta');
viewport.setAttribute('name'.'viewport');
window.document.head.appendChild(viewport);
}
viewport.setAttribute('content'.'width=device-width,user-scalable=no,initial-scale=' + scale + ',maximum-scale=' + scale + ',minimum-scale=' + scale);
// Set the root font size
var docEl = document.documentElement;
var fontsize = 10 * (docEl.clientWidth / 320) + 'px';
docEl.style.fontSize = fontsize;
// Use rem in CSS
Copy the code
Disadvantages:
- The document is modified through JS, so there is a performance impact
- Will be used for all in the project
rem
Unit of the object to be affected. If it is an old project, all the CSS styles will be changed (not suitable for old project retrofits)
Pseudo-element + transform implementation
Why pseudo-elements? Because the pseudo-elements ::after or ::before are independent of the current element, they can be scaled independently without affecting the scaling of the element itself
Based on media query, different devices are judged to scale the pixel alignment lines:
.border-1px:before{
content: ' ';
position: absolute;
top: 0;
height: 1px;
width: 100%;
background-color: # 999;
transform-origin: 50% 0%;
}
@media only screen and (-webkit-min-device-pixel-ratio:2) {.border-1px:before{
transform: scaleY(0.5); }}@media only screen and (-webkit-min-device-pixel-ratio:3) {.border-1px:before{
transform: scaleY(0.33); }}Copy the code
Note that if you want rounded corners, you need to add border-RADIUS to the pseudo-class as well
Advantages: Good compatibility, no side effects, recommended
Box-shadow simulation border implementation
box-shadow: 0 -1px 1px -1px # 999.1px 0 1px -1px # 999.0 1px 1px -1px # 999,
-1px 0 1px -1px # 999;
Copy the code
Disadvantages: Borders are shaded and light in color, compatibility issues as well, Safari does not support box-shadow Settings below 1px.
SVG implementation
Because SVG is vector graphics, 1px corresponds to 1px in physical pixels
You can use postCSs-write-SVG with PostCSS:
@svg border-1px {
height: 2px;
@rect {
fill: var(--color, black);
width: 100%;
height: 50%; }}.svg {
border: 1px solid transparent;
border-image: svg(border_1px param(--color #00b1ff)) 2 2 stretch;
}
Copy the code
The compiled:
.svg { border: 1px solid transparent; border-image: url("data:image/svg+xml; charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='2px'%3E%3Crect fill='%2300b1ff' width='100%25' height='50%25'/%3E%3C/svg%3E") 2 2 stretch; }
Copy the code
- Advantages: Simple implementation, can achieve rounded corners,
- Weakness: Need to learn
svg
grammar
conclusion
In conclusion, it is recommended to use:
- Pseudo-element + transform implementation
- SVG implementation
- New projects can be tried
viewport
plan
Solve the 1px problem of mobile Retina display
Three minutes a day, advance one