By writing this material I was prompted by the
article and the urgent need to adapt several of their sites to support Retina-displays. By adaptation, I mean the preparation of high-resolution images on the pages of the site.
Perhaps the best way to adapt today is the way c background-image in CSS. But it is difficult to apply to ordinary images in the tag. Therefore, I decided to determine for myself the list of necessary measures to achieve the result in a complex and continue the search for a solution. The following describes two methods, each of which is applicable to its tasks. The solutions shown do not claim to be discovered, rather it is an aggregation of existing methods described earlier by my colleagues in the web development workshop and small own additions.
Half measure or simple solutionApache SolutionNginx solutionHalf measure: background-image handler
If you do not want to bother with processing content images or you don’t have them in principle, use the method shown in the code below and don’t read the article further. For example, on one of the sites I do not fundamentally produce image processing in, but the interface elements (icons) are too striking. Therefore, you can use a simple but effective way:
')
.elem { background-image: url(elem.png); } @media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 144dpi) { .icon { background-image: url(elem@2x.png); } }
Of course, the class elem is given for example and you need to adapt this css to your needs. Well, do not forget about the preparation of an additional set of cutting images of site design. Of course, there will have to work, especially if the site design is full of images, but I am a supporter of a one-time execution of such work, especially if compared with various “crutches”.
Setting the Retina integrated support task
For myself, I defined the following criteria for solving the problem of a comprehensive website transfer to Retina support:
- the method should be universal and should include processing of all the images on the site without exception;
- the method should not lead to the pages being updated as a result of any redirect;
- the method should be as loyal to the user as possible; it should not upload the original image prepared for Retina to the user's browser.
Before describing the solution, I note that in all cases we assume that the server has copies of all the images that need to be replaced for Retina displays.
In addition to the design of the site, the actual task for me was to form a second set of content images on the server. In my case, users upload images to the site, so it was necessary to prepare the main image and its high resolution copy using server scripts.
I will not describe the mechanism for uploading and processing graphic files, since it takes into account the individual features of the project, but the bottom line is that you need to create a working image for the site and a copy optimized for Retina from the user-uploaded image, if the quality of the downloaded image this allows. For example, in this project, the maximum width of content images is 800px. Of course, if a user uploads an image with a width of 400px, only a copy of it that is 400px wide will be formed. But if the user loads an image with a width of at least 1600px, which happens quite often, we will be able to please visitors to the site from Retina.
At the same time, it should be noted that previously downloaded images cannot be saved in high resolution, and it is somehow wrong to reduce the height and width values ​​without the knowledge of the user. Therefore, the method should include work with existing @ 2x pictures, and without them.
Apache Solution
I will designate in advance that the solution is far from ideal, it is too expensive for a server resource and is not recommended for use. But, unfortunately, in cases of missing nginx or access to its configuration, an alternative is needed and it is described below.
The first step to the page template (well, or to one of your js files included) is to add a simple js script (
it is important that this code is executed before starting to load the page content and any CSS that contains the images that need to be changed ):
<script>document.cookie='resolution='+Math.max(screen.width,screen.height)+("devicePixelRatio" in window ? ","+devicePixelRatio : ",1")+'; path=/';</script>
JS code will form a cookie, by which the server script can understand with which display the user came to the site. The next step in many of the methods described is the redirect using js and the CMS scripts, analyzing resolution, give the correct version of the graphics. But we are not looking for easy ways and do not use redirect. Using .htaccess or apache config, install the cookie handler outside the CMS site scripts:
RewriteCond %{REQUEST_URI} ^/images #RewriteCond %{REQUEST_URI} !^/images/excluded RewriteCond %{HTTP_COOKIE} resolution=([^;,]+),2 RewriteCond %{REQUEST_URI} !@2x\.(jpe?g|gif|png)$ RewriteRule ([^.]+)\.(jpe?g|gif|png)$ $1@2x.$2 [L]
The first line of RewriteCond tells the script in which folder the image files being processed are located.
The second (commented out) line allows you to add an exception folder to the handler.
In the third line of the RewriteCond, we get rid of that self redirect by defining the cookie that was set when the page was loaded.
The fourth condition excludes from the processing already high-resolution images (with the fragment "@ 2x" at the end of the file name).
In the fifth line, we define a substitution for images of what format.
The advantages of the described method:
- the solution works for all images of the site;
- no redirect of the page;
- if there is no “resolution” cookie, the user will see the default content of the page.
Disadvantages:
- (in the opinion of the author of this method) the user’s way of connecting to the Internet and the possibility of pumping out images in high resolution is not taken into account;
- a significant drawback, from my point of view, in the need to use a redirect to the hi-res image by means of Apache;
- also, from my point of view, a significant problem is the lack of checking the presence of @ 2x images on the server.
For myself, I made an adjustment to the considered method in order to avoid problems with non-existent images.
In the .htaccess line
RewriteRule ([^.]+)\.(jpe?g|gif|png)$ $1@2x.$2 [L]
replaced by
RewriteRule ([^.]+)\.(jpe?g|gif|png)$ retina.php?img=$1@2x.$2
A simple php script determines the presence of the requested image on the server and displays it. If the image file is not found, the script returns the usual (not hi-res) image. Of course with checking the requested data:
<?php if (!empty($_GET['img']) && mb_substr_count($_GET['img'], '@2x')) { function isImg ($dress) { if (function_exists('exif_imagetype')) $type_file = exif_imagetype ($dress); else { $type_file = getimagesize ($dress); $type_file = $type_file[2]; }
Of course, this change increased the load on the server, but I did not see any other solution.
Nginx solution
Thanks to the help of
docomo and
progit , a much more elegant and correct, in my opinion, version of the problem solution appeared. If your server has nginx and there is access to its configuration, you can get rid of the unreasonably high load that the php script will give, and for one and the Apache itself, making an uncomplicated adjustment.
At the time of the description of this method, I changed a little and js for site templates.
So, the new js:
<script>if ("devicePixelRatio" in window && window.devicePixelRatio > 1) document.cookie='hires=1; path=/';</script>
Thus, cookie hires is set only if we need to create a set of high-resolution images.
The elegance of the method described above is preserved (on any site without alteration of the script code, substitution can be carried out for both background css and tag). But the lack of a way with the php script costs setting the nginx config:
if ($http_cookie ~ "hires" ) { set $hires 1; } location ~* ^(.+)@2x.(jpg|jpeg|gif|png)$ { try_files $uri $1.$2 =404; } location ~* ^.+.(jpg|jpeg|gif|png)$ { if ($hires = 1) { rewrite ^(.+).(jpg|jpeg|gif|png)$ $1@2x.$2; } }
Thus, nginx takes over all the work with statics.
And yes, thanks to
progit for an important clarification: With this approach, for all the pictures on the site, be sure to specify the width and height. For through attributes or via css-properties, and for background images you need to specify background-size: width height.
The method of solving the problem is based on the
Automatically serve retina artwork by Sam Sehnert method.
UP : Thanks to all Habrayusers, made changes to the comments.