In mobile terminal Web development, the border is set as 1 pixel in the UI design draft. If border:1px appears in the front end development process, the test will find that 1px is relatively thick in retina display models, which is the classic 1px pixel problem on mobile terminal.

1px questions are frequently asked in actual interviews, especially in big factories. This article discusses several 1px problem solutions.

1px The cause of the problem

The 1px problem refers to the fact that on some Retina models, the 1px of the mobile page can become very thick and look like more than 1px.

The reason is simple — 1px in CSS is not the same as 1px on mobile devices. The proportional relationship between them has a special property to describe:

// Device pixel ratio
window.devicepixelRatio = Physical pixels of the device/CSS pixelsCopy the code

How many device pixels a physical pixel equals depends on the screen nature of the mobile device (Retina or not) and the user’s zoom ratio.

Try opening your Chrome browser, starting mobile debug mode, and then trying to output the devicePixelRatio value on the console. Here I selected the iPhone6/7/8 series models, the output is 2:

This means that the 1px CSS pixel I set will be rendered with 2 physical pixels on the mobile, so it will look bigger than 1px.

The solution

There are many solutions to the 1px problem. Set out from practical point of view nevertheless, suggest everybody to master 3 ~ 4 kinds of ok, understand other method to go.

plan advantages disadvantages
Write directly 0.5 px The code is simple IOS and Android devices are not supported
Use pictures instead of borders Compatible with all models Modify color and do not support rounded corners
Background gradient Compatible with all models More code and do not support rounded corners
Box-shadow simulates border implementation Compatible with all models Borders and shadows cannot be implemented
Pseudo-elements zoom in and then zoom out Simple and practical Disadvantages are not obvious
Set viewPort to resolve the problem One set of code applies to all pages Disadvantages are not obvious

1. Write 0.5px directly

At WWDC, for ios8+ devices with DPR=2, the 1px scheme is given, and when written at 0.5px, a border with a physical pixel width is displayed. So on iOS, you can write it like this

Border: 0.5 px solid # E5E5E5Copy the code

Although the problem is solved, the practicality is not high. First of all, we have to consider that the IOS system needs the version 8 or above, and the Android system has incompatible problems.

2. Use pictures instead of borders

border: 1px solid transparent;
border-image: url('xxx.jpg') 2 repeat;
Copy the code

Although the problem is solved, but the late style adjustment will make people crash, such as color adjustment UI small friends re-upload the image, and then need to modify the code, or direct file replacement involves the image cache problem, if there is a need to have a border rounded corner is completely impossible to handle.

3. The background gradient

background-position: left top; background-image: - its - gradient (linear, left bottom, left, top, color - stop (0.5, transparent), color - stop (0.5, # e0e0e0), to (# e0e0e0));Copy the code

There is a lot of code, and the displayed border is actually inside the original border space. If the element background color changes, the border line will also disappear. Finally, it doesn’t fit the rounded corners.

4. Box-shadow simulated border implementation

box-shadow: 0-1px 1px 1px #e5e5e5, // Top line 1px 0 1px -1px #e5e5e5, // right line 0 1px 1px -1px #e5e5e5, // bottom line -1px 0 1px -1px #e5e5e5; / / the left lineCopy the code

After all, the shadow is the same as the border, but if you have a border and a shadow style, you can’t have your cake and eat it.

5. Fake elements zoom in and then zoom out

This approach will be more feasible and more compatible.

Append a ::after pseudo-element to the target element, make it absolute and spread over the target element, then set its width and height to twice that of the target element, and border to 1px. Then, with the help of CSS animation effects, the entire pseudo element is reduced to 50% of its original size. At this point, the width and height of the pseudo-element is just right to align with the original target element, and the border is reduced to half of 1px, indirectly achieving the effect of 0.5px.

.hairline{
  position: relative;
  &::after{
    content: ' ';
    position: absolute;
    top: 0;
    left: 0;
    height: 1px;
    width: 100%;
    transform: scaleY(0.5);
    transform-origin: 0 0; background-color: #EDEDED; }}Copy the code

At present, most mobile terminal UI uses this scheme, which is compatible with all models.

6. Set viewPort to resolve the problem

Using viewport+ REM + JS implementation, border 1px directly write automatic conversion.

<! DOCTYPEhtml>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" id="WebViewport" content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
        <title>Document</title>
        <style type="text/css"></style>
    </head>
    <body>
        <script type="text/javascript">
            let viewport = document.querySelector('meta[name=viewport]')
            // Set the viewPort according to the device pixel
            if (window.devicePixelRatio == 1) {
                viewport.setAttribute('content'.'width=device-width,initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no')}if (window.devicePixelRatio == 2) {
                viewport.setAttribute('content'.'width = device - width, initial - scale = 0.5, the maximum - scale = 0.5, the minimum - scale = 0.5, user - scalable = no')}if (window.devicePixelRatio == 3) {
                viewport.setAttribute('content'.'width = device - width, initial - scale = 0.3333333333333333, the maximum - scale = 0.3333333333333333, Minimum - scale = 0.3333333333333333, user - scalable = no ')}function resize() {
                let width = screen.width > 750 ? '75px' : screen.width / 10 + 'px'
                document.getElementsByTagName('html') [0].style.fontSize = width
            }
            window.onresize = resize
        </script>
    </body>
</html>
Copy the code

This way, the advantages are obvious, compatible with all models, directly write 1PX simple and convenient!

conclusion

The best new project to use is to set viewport to solve the problem, this method is good compatibility, convenient to write later, followed by more methods is the pseudo element method. Other background images, the shadow method is still not flexible, and compatibility is not good.

Refer to the article

  • A tale of two viewports
  • Unlock the core of the front-end interview system
  • Hand wash H5 page terminal adaptation
  • 1 px project