Tela com DPI alto

Introdução

As telas HiDPI são ótimas, elas deixam tudo mais suave e limpo. Mas eles também apresentam um novo conjunto de desafios para os desenvolvedores. Neste artigo, vamos analisar os desafios únicos de exibir imagens na tela no contexto de telas HiDPI.

A propriedade devicePixelRatio

Vamos começar do início. Antes de termos telas HiDPI, um pixel era um pixel (se ignorarmos o zoom e a escala por um tempo) e era isso. Não era preciso mudar nada. Se você definir algo como 100 px de largura, é só isso que vai existir. Em seguida, os primeiros aparelhos móveis HiDPI começaram a aparecer com a propriedade devicePixelRatio um pouco enigmática no objeto de janela e disponível para uso em consultas de mídia. Essa propriedade nos permitiu entender a proporção de como os valores em pixels (que chamamos de valor lógico de pixel) em, digamos, o CSS seria convertido para o número real de pixels que o dispositivo usaria na renderização. No caso de um iPhone 4S, que tem um devicePixelRatio de 2, um valor lógico de 100 px equivale a um valor de dispositivo de 200 px.

Isso é interessante, mas o que isso significa para nós, desenvolvedores? No início, percebemos que nossas imagens estavam sendo aprimoradas por esses dispositivos. Estávamos criando imagens com a largura lógica de pixel de nossos elementos e, quando desenhadas, elas eram aprimoradas pelo devicePixelRatio e ficavam desfocadas.

Uma imagem sendo redimensionada e desfocada devido ao devicePixelRatio
Figura 1: uma imagem sendo ampliada e desfocada devido ao devicePixelRatio

A solução real para isso tem sido criar imagens escalonadas verticalmente pelo devicePixelRatio e usar CSS para reduzi-las na mesma quantidade, e o mesmo vale para o canvas!

function setupCanvas(canvas) {
  // Get the device pixel ratio, falling back to 1.
  var dpr = window.devicePixelRatio || 1;
  // Get the size of the canvas in CSS pixels.
  var rect = canvas.getBoundingClientRect();
  // Give the canvas pixel dimensions of their CSS
  // size * the device pixel ratio.
  canvas.width = rect.width * dpr;
  canvas.height = rect.height * dpr;
  var ctx = canvas.getContext('2d');
  // Scale all drawing operations by the dpr, so you
  // don't have to worry about the difference.
  ctx.scale(dpr, dpr);
  return ctx;
}

// Now this line will be the same size on the page
// but will look sharper on high-DPI devices!
var ctx = setupCanvas(document.querySelector('.my-canvas'));
ctx.lineWidth = 5;
ctx.beginPath();
ctx.moveTo(100, 100);
ctx.lineTo(200, 200);
ctx.stroke();