Obtendo as dimensões / dpi / densidade de pixels da tela física no Chrome no Android

88

Questão

Existe uma maneira segura de obter as dimensões físicas realmente corretas da tela no Chrome, no Android? Se necessário, as versões antigas do Chrome e do Android podem ser deixadas de fora do escopo.

Pesquisa anterior

Existem inúmeras questões sem saída no stackoverflow sobre como obter as dimensões reais da tela física de um dispositivo de dentro de javascript (ou css). Parece que não há convergência entre a padronização da API html e as implementações reais do navegador, sem mencionar que a implementação do navegador depende da API do sistema operacional que, por sua vez, depende do hardware que fornece as informações corretas.

A propósito, algumas respostas anteriores são misteriosas (ano de 2011 e semelhantes) ao assumir uma certa densidade de pixels que prevalecia naquele momento e, portanto, inúteis. Outros estão relacionados ao webkit, enquanto o Chrome blink pode ter substituído o webkit no chrome (?).

Eu gostaria de explorar a existência de uma solução simples, restringindo as coisas apenas ao Chrome no Android.

Nota

Trata-se de uma solução javascript (ou css) dentro do navegador, não uma solução para um aplicativo nativo.

matanster
fonte
21
Isso é simplesmente errado. Minha interface de usuário deseja saber coisas como o tamanho que um botão deve ter conforme o usuário o vê. você pode estar pensando demais como um desenvolvedor de código nisso;)
matanster
12
O tamanho de um botão, por exemplo, não deve ser uma porcentagem da janela de visualização - mas grande o suficiente para ser tocado. Não tenho certeza de como isso faz sentido para um design de alta qualidade.
matanster
16
@matt está absolutamente correto. Um dos aspectos mais importantes da UX / IU da Web, especialmente em um mundo de dedos gordos, é garantir que os botões sejam apropriados para o ponteiro - neste caso, um dedo - e também do tamanho adequado para a distância de visualização da tela ao olho. Esse novo domínio de dispositivos móveis complicou o assunto, então a detecção do tamanho físico da tela é ainda mais importante.
Jason T Featheringham
7
Estou 100% com você @matt. Não entendo por que o Mozilla e o Google não podem simplesmente nos dar uma propriedade JavaScript como window.screenDensityaquela que contém os pixels físicos por polegada do dispositivo que você e eu, Matt, podemos tirar daí. window.screenHeighte window.screenWidthem milímetros físicos seria bom também.
trusktr
7
@Kinlan O tamanho físico da tela é importante em geral. É por isso que o desenvolvimento nativo é mais poderoso do que o desenvolvimento web no momento. Em um ambiente nativo, posso fazer um botão de 1 (mundo real) polegada de largura, em todos os dispositivos modernos, por exemplo. Isso não é possível atualmente em um ambiente da web, pelo que eu sei. Eu perdi alguma coisa?
trusktr

Respostas:

118

Você não pode realmente obter as dimensões físicas reais ou o DPI real e, mesmo se pudesse, você não pode fazer nada com eles.

Esta é uma história muito longa e complexa, então me perdoe.

A web e todos os navegadores definem 1px como uma unidade chamada pixel CSS. Um pixel CSS não é um pixel real, e sim uma unidade considerada 1/96 de polegada com base no ângulo de visão do dispositivo. Isso é especificado como um pixel de referência .

O pixel de referência é o ângulo visual de um pixel em um dispositivo com uma densidade de pixels de 96dpi e a uma distância de um braço do leitor. Para um comprimento nominal de braço de 28 polegadas, o ângulo visual é, portanto, cerca de 0,0213 graus. Para leitura no comprimento do braço, 1px corresponde a cerca de 0,26 mm (1/96 polegada).

Em 0,26 mm de espaço, podemos ter muitos pixels de dispositivos reais.

O navegador faz isso principalmente por motivos legados - a maioria dos monitores tinha 96 dpi quando a web nasceu - mas também por consistência, nos "velhos tempos" um botão de 22 pixels em uma tela de 15 polegadas a 800x600 teria o dobro do tamanho de um botão de 22 pixels em um monitor de 15 polegadas em 1600x1200. Neste caso, o DPI da tela é na verdade 2x (duas vezes a resolução horizontalmente, mas no mesmo espaço físico). Esta é uma situação ruim para a web e aplicativos, então a maioria dos sistemas operacionais inventou muitas maneiras de abstrair valores de pixel em unidades independentes de dispositivo (DIPS no Android, PT no iOS e CSS Pixel na web ).

O navegador Safari do iPhone foi o primeiro (até onde sei) a introduzir o conceito de janela de visualização. Isso foi criado para permitir que aplicativos de estilo desktop completo sejam renderizados em uma tela pequena. A janela de visualização foi definida para ter 960 px de largura. Isso basicamente ampliou a página 3x (o iphone tinha originalmente 320px), então 1 pixel CSS é 1/3 de um pixel físico. Ao definir uma janela de visualização, você pode fazer com que este dispositivo corresponda a 1 pixel CSS = 1 pixel real a 163dpi.

Ao usar uma janela de visualização em que a largura é "largura do dispositivo", você não precisa mais definir a largura da janela de visualização por dispositivo para o tamanho de pixel CSS ideal, o navegador faz isso por você.

Com a introdução de dispositivos de DPI duplo, os fabricantes de telefones celulares não queriam que as páginas móveis parecessem 50% menores, então eles introduziram um conceito chamado devicePixelRatio (primeiro no webkit móvel, eu acredito), que os permite manter 1 pixel CSS em cerca de 1 / 96º de polegada, mas permite que você entenda que seus ativos, como imagens, podem precisar ter o dobro do tamanho. Se você olhar para a série do iPhone, todos os seus dispositivos dizem que a largura da tela em pixels CSS é de 320 px , embora saibamos que isso não é verdade.

Portanto, se você criou um botão para ter 22 pixels no espaço CSS, a representação na tela física é a proporção de pixels do dispositivo de 22 *. Na verdade, eu digo isso, não é exatamente isso porque a proporção de pixels do dispositivo nunca é exata também, os fabricantes de telefones configuram um bom número como 2.0, 3.0 em vez de 2.1329857289918 ....

Resumindo, os pixels CSS são independentes do dispositivo e não precisamos nos preocupar com os tamanhos físicos das telas e as densidades de exibição, etc.

A moral da história é: não se preocupe em entender o tamanho físico do pixel da tela. Você não precisa disso. 50px deve ser praticamente o mesmo em todos os dispositivos móveis, pode variar um pouco, mas o Pixel CSS é nossa forma independente de dispositivo para construir documentos e IUs consistentes

Recursos:

Kinlan
fonte
1
@matt será o mesmo em tablets. Como acontece com os retina mac books. O objetivo é que o "Pixel CSS" seja relativamente uniforme em todas as plataformas, especialmente se você definir a largura da janela de visualização = largura do dispositivo.
Kinlan
14
Você disse "você não pode fazer nada com eles." Discordo. Com essa informação, seria capaz de definir uma fonte que sempre tem 16 pontos (16/72 segundos de uma polegada do mundo real) de altura. Isso é inestimável e uma das razões pelas quais o desenvolvimento nativo continua a ser mais poderoso do que o desenvolvimento web.
trusktr de
8
Na verdade, um uso perfeitamente razoável para o tamanho real da tela em pixels é renderizar uma imagem de fundo com a resolução apropriada.
WhyNotHugo
2
"50px deve ser praticamente igual em todos os dispositivos móveis", prove isso usando, por exemplo, um telefone 1200x1920 de 4 polegadas e um tablet de 1000x600 10 polegadas um ao lado do outro.
iloveregex
6
Também discordo com "você não pode fazer nada com eles.": Você pode detectar se o dispositivo é um telefone ou tablet de forma confiável e assumir que o usuário pode facilmente apontar para o topo da tela com o dedo ou não.
Brian Cannard
11

Com base na resposta de Matt, fiz um teste:

// on Macbook Pro Retina (2880x1800, 15.4"), is the calculated diagonal size
// approximately 15.4? Let's see...

var svgEl = document.createElementNS("http://www.w3.org/2000/svg", "svg");
var screenWidthMillimeters = svgEl.screenPixelToMillimeterX * 2880;
var screenHeightMillimeters = svgEl.screenPixelToMillimeterY * 1800;
var screenDiagonalMillimeters = Math.sqrt(Math.pow(screenWidthMillimeters, 2) + Math.pow(screenHeightMillimeters, 2)); // pythagorean theorem
var screenDiagonalInches = (screenDiagonalMillimeters / 10 / 2.54); // (mm / 10mm/cm) / 2.54cm/in = in

console.log("The calculated diagonal of the screen is "+screenDiagonalInches+" inches. \nIs that close to the actual 15.4\"?");

Esta é a saída:

The calculated diagonal of the screen is 35.37742738560738 inches. 
Is that close to the actual value of 15.4?

Não.

Portanto, parece ainda não haver maneira de obter valores físicos reais em um navegador da web.

Trusktr
fonte
Não sei a que resposta você está se referindo (não vejo um "Matt" em lugar nenhum), mas recebo NaN devido ao fato de svgEl.screenPixelToMillimeterXaparentemente não ter sido definido.
Michael
6

Você pode criar qualquer elemento de página e definir sua largura usando unidades físicas reais. Por exemplo

<div id="meter" style="width:10cm"></div>

E então obtenha sua largura em pixels. Por exemplo, o código html abaixo (eu usei JQuery) mostra a largura da tela do dispositivo em centímetros

<script>
var pixPer10CM = $('#meter').width();
var CMPerPix = 10 / pixPer10CM;
var widthCM = screen.width * CMPerPix;

alert(widthCM);
</script>
Mike
fonte
Uau, nunca imaginei que você pudesse fazer isso com css. Quão preciso é isso? Como seu navegador conhece as dimensões físicas de sua tela? A compatibilidade do navegador com caniuse.com está em algum lugar? Eu não consigo encontrar.
Jake Wilson
4
O site do W3C diz: "No passado, o CSS exigia que as implementações exibissem unidades absolutas corretamente, mesmo em telas de computador. Mas como o número de implementações incorretas superava o número correto e a situação parecia não melhorar, o CSS abandonou esse requisito em 2011. Atualmente , as unidades absolutas devem funcionar corretamente apenas na saída impressa e em dispositivos de alta resolução. CSS não define o que significa "alta resolução". Mas como as impressoras de baixo custo hoje em dia começam em 300 dpi e as telas de alta resolução estão em 200 dpi, o corte está provavelmente em algum lugar no meio. "
Mike,
1
Acho que esse navegador, como qualquer outro aplicativo nativo, pode obter resolução do dispositivo por meio da API do sistema operacional, fornecida ao sistema operacional pelo driver do dispositivo. A precisão depende dessas informações.
Mike,
Mas a resolução do dispositivo não é igual às dimensões físicas reais. Um laptop de 14 "e um laptop de 15" podem ter a mesma resolução.
Jake Wilson,
6
Não! Você não pode. 10cm em Css terão tamanhos diferentes na realidade. É pura questão de sorte se realmente tiver 10 cm, 12 cm ou 7 cm. Aqui está minha demonstração do jsfiddle com base nessa solução que retorna valores errados, já que os navegadores sempre se comportam como se tivessem pixels por polegada (dpi): jsfiddle.net/Lzsm3zo9
Dariusz Sikorski
5

Você pode obter essas informações com WURFL:

Propriedades de exibição do dispositivo

Os atributos são chamados de:

resolution_(width|height)

physical_display_(width|height)

Versão longa:

A melhor e mais confiável estratégia para conseguir isso é enviar user agent stringdo navegador para um banco de dados semelhante WURFL(ou outro) atualizado que pode fornecer as informações necessárias.

String do agente do usuário

Esta é uma informação que todos os navegadores modernos podem fornecer; ele expõe informações sobre o dispositivo e seu sistema operacional. Simplesmente não é significativo o suficiente para seu aplicativo sem a ajuda de um dicionário como o WURFL.

WURFL

Este é um banco de dados comumente usado para detectar propriedades de dispositivos.

Com ele, você pode ser capaz de oferecer suporte preciso à maioria dos dispositivos populares do mercado. Eu postaria uma demonstração do código, mas uma está disponível para download no WURFLsite. Você pode encontrar tal demo na pasta de exemplos / demo que é baixada com a biblioteca.

Baixar WURFL

Aqui estão mais informações e explicações sobre como verificar o tamanho físico e a resolução: http://www.scientiamobile.com/forum/viewtopic.php?f=16&t=286

AturSams
fonte
3

Como complemento à resposta “não há uma boa solução para este problema”, basta verificar as unidades que você pode usar no CSS https://www.w3schools.com/cssref/css_units.asp

Unit    Description
cm      centimeters
mm      millimeters
in      inches (1in = 96px = 2.54cm)
px *    pixels (1px = 1/96th of 1in)
pt      points (1pt = 1/72 of 1in)
pc      picas (1pc = 12 pt)

* Pixels (px) are relative to the viewing device.
For low-dpi devices, 1px is one device pixel (dot) of the display.
For printers and high resolution screens 1px implies multiple device pixels.

Com esta descrição, parece que há uma solução. cm, mme inseria usado para desenhar algo com o mesmo tamanho, independentemente do tamanho e da resolução da tela. Com isso em mente, você pode esperar que pelo menos um de px, ptou pcpossa ser usado para desenhar no nível do pixel, para qualquer precisão que você gostaria de usar (caso contrário, qual é o ponto em ter milhões de pixels, certo?). Bem não. Todas as unidades são frações de uma unidade métrica, tornando todas essas unidades apenas escalas diferentes. E o pior da história é o fato de que nada disso é preciso. Basta brincar com o exemplo w3schools (desenhe uma linha de 20 cm e meça com uma régua).

Então, no final: - não há maneira de desenhar algo com dimensões físicas precisão (que deve ser o caso com cm, mm, ine, finalmente, pte pc). - não há como desenhar algo com o mesmo tamanho, independentemente do tamanho e da resolução da tela (o que deveria ser o caso pelo menos px).

Este é um problema de implementação (o tamanho real da tela não está sendo usado) e um problema de design (por que deveria pxser independente do tamanho da tela enquanto já existem tantas unidades para isso).

Tom
fonte
2

Abordei esse problema com um de meus projetos da web http://www.vinodiscover.com. A resposta é que você não pode saber com certeza qual é o tamanho físico, mas pode obter uma estimativa. Usando JS e / ou CSS, você pode encontrar a largura e a altura da janela de visualização / tela e a densidade de pixels usando consultas de mídia. Por exemplo: iPhone 5 (326 ppi) = 320px por 568px e densidade de 2,0 pixels, enquanto um Samsung Galaxy S4 (441ppi) = 360px x 640px e densidade de 3,0 pixels. Efetivamente, uma densidade de 1.0 pixel é de cerca de 150 ppi.

Diante disso, defino meu CSS para mostrar 1 coluna quando a largura for inferior a 284 px, independentemente da densidade de pixels; em seguida, duas colunas entre 284 px e 568 px; em seguida, 3 colunas acima de 852 px. É muito mais simples do que parece, já que os navegadores agora fazem os cálculos de densidade de pixels automaticamente.

http://www.quirksmode.org/blog/archives/2010/04/a_pixel_is_not.html

Apollo Clark
fonte
3
No desenvolvimento nativo, você pode obter o valor exato. +1 para nativo, -1 para web.
trusktr de
Você pode obter o tamanho físico exato no Android?
Apollo Clark
2

Em resposta à resposta de zehelvion sobre o uso do WURFL para encontrar a resolução, também vale a pena mencionar que o WURFL também está disponível como um snippet de JavaScript .

Na edição gratuita oferecida em wurfl.io , você não obterá informações sobre a tela e a resolução (apenas o nome do dispositivo, formato e celular / não móvel), mas há também uma versão comercial com mais recursos disponíveis aqui .

Jonarnes
fonte
3
Sugiro que isso esteja nos comentários a essa resposta em particular.
darkgaze de
1
esta é uma solução ridiculamente complicada para algo que deveria ser fornecido nativamente pelo navegador.
Michael
2

Pixels CSS não são realmente nossos "pixels independentes de dispositivo". A plataforma da Web consiste em vários tipos de dispositivos. Embora o pixel CSS pareça bastante consistente em dispositivos portáteis, será 50% maior em um monitor de desktop típico de 96 dpi. Veja minha pergunta . Isso realmente não é ruim em alguns casos, por exemplo, as fontes devem ser maiores em uma tela maior, já que a distância até o olho é maior. Mas as dimensões dos elementos da interface do usuário devem ser bastante consistentes. Digamos que seu aplicativo tenha uma barra superior, você prefere que ela tenha a mesma espessura em desktops e celulares; por padrão, ela será 50% menor, o que não é bom, porque os elementos tocáveis ​​devem ser maiores. A única solução alternativa que encontrei é aplicar estilos diferentes com base no DPI do dispositivo.

Você pode obter o DPI da tela em JavaScript com window.devicePixelRatio. Ou consulta CSS:

@media  only screen and (-webkit-min-device-pixel-ratio: 1.3),
    only screen and (-o-min-device-pixel-ratio: 13/10),
    only screen and (min-resolution: 120dpi)
    {
     /* specific styles for handhelds/ high dpi monitors*/
    }

Não sei como aplicar isso funcionaria em um monitor de desktop de alto dpi. Talvez os elementos sejam muito pequenos. É realmente uma pena que a plataforma web não ofereça nada melhor. Eu acho que a implementação do dip não seria muito difícil.

Maciej Krawczyk
fonte
não, você não pode. consultas de mídia estão fazendo essa porcaria estúpida de "assumir 96dpi", ou seja, eles estão mentindo para você sobre o que é leitura de DPI.
Michael
1

Percebi em seus comentários que você estava realmente preocupado com o tamanho que os botões e assim por diante aparecem para o visualizador.

Eu estava tendo o mesmo problema, até que descobri que bastava adicionar uma metatag ao cabeçalho HTML para definir a escala inicial:

<meta name="viewport" content="width=device-width, initial-scale=1">

Dan Kennedy
fonte
0

Largura do elemento JqueryMobile

$(window).width();   // returns width of browser viewport
$(document).width(); // returns width of HTML document

JqueryMobile Altura do elemento

$(window).height();   // returns height of browser viewport
$(document).height(); // returns height of HTML document

Boa Sorte Danny117

danny117
fonte
3
Essas são dimensões virtuais, que nem sempre são dimensões físicas do mundo real.
trusktr de
Obrigado, eu não sabia disso
danny117 01 de
0

Usando a função getPPI () ( Web móvel: como obter o tamanho físico do pixel? ), Para obter um id de uma polegada, use esta fórmula:

var ppi = getPPI();
var x   = ppi * devicePixelRatio * screen.pixelDepth / 24;
$('#Cubo').width (x);
$('#Cubo').height(x);

<div id="Cubo" style="background-color:red;"></div>
Pilo
fonte
5
porque pixelDepth ?! não é pixelDepth relacionado à profundidade de cor, caso em que eu me pergunto como isso é relevante para o cálculo aqui ....
matanster
0

Heh gostaria de poder responder a isso, mas geeks que criam APIs não fornecem as necessidades básicas e coisas abstratas um pouco demais às vezes.

A propósito, eu tenho 40 anos de experiência em design de interface de usuário e software e tenho me esforçado para ter exatamente isso pelo que parece uma eternidade, desde antes dos dias dos drivers "VESA" :).

Para a tela de toque, eu tinha uma coisa que chamei de "fingerSize ()" que era o número de pixels de 1 cm (muito próximo ao diâmetro da área média de toque do dedo), mas o datmum da raiz é "dpcm".

A outra coisa que você deseja para uma tela é o "ângulo de visão". O tipo de dispositivo de tela para visualização e função de toque define muito bem a distância de visualização.

    (Not code but I wanted fixed width font)

    Hand held - Phone/Tablet         25cm 
    Touch screen / Desktop Monitor   40cm         ( seated or standing at a counter
                                                    with partially extended arm )
    "Personal" Touch kiosk        50cm -> 80cm ( a bit further away standing 
                                                 extended arms and standing back 
                                                 to view )
    Presentation Screen.          any distance ( angle of view derived from pixel
                                                 width of device. An ideal conventional cinema 
                                                 seat (as opposed to imax or immersive) 
                                                 you want about 50 degrees
                                                 between edges of the screen. from viewer POV )

    So what you want universally available is:

    device usage type.
    finger size in pixels (dots per CM)
    pixel dimensions of display.

    Then internally, when laying out and drawing you want the size/shape of a pixel 
    for the current transform. 

Isso é o que tentamos fornecer em nossas APIs. Mas, infelizmente, é difícil conseguir em muitos casos.

Peter
fonte
-1

Você pode obter uma estimativa aproximada do tamanho, mas não é precisa.

Juntei um exemplo que testei em alguns dispositivos para ver quais foram os resultados. Meu iPhone 6 retorna valores cerca de 33% maiores. Meu monitor de mesa de 27 "no meu Mac relatou como um monitor de 30".

var $el = document.createElement('div');
$el.style.width = '1cm';
$el.style.height = '1cm';
$el.style.backgroundColor = '#ff0000';
$el.style.position = 'fixed';
$el.style.bottom = 0;
document.body.appendChild($el);
var screenDiagonal = Math.sqrt(Math.pow((window.screen.width / $el.offsetWidth), 2) + Math.pow((window.screen.height / $el.offsetHeight), 2));
var screenDiagonalInches = (screenDiagonal / 2.54);
var str = [
  '1cm (W): ' + $el.offsetWidth + 'px',
  '1cm (H): ' + $el.offsetHeight + 'px',
  'Screen width: ' + window.screen.width + 'px',
  'Screen height: ' + window.screen.height + 'px',
  'Browser width: ' + window.innerWidth + 'px',
  'Browser height: ' + window.innerHeight + 'px',
  'Screen available width: ' + window.screen.availWidth + 'px',
  'Screen available height: ' + window.screen.availHeight + 'px',
  'Screen width: ' + (window.screen.width / $el.offsetWidth).toFixed(2) + 'cm',
  'Screen height: ' + (window.screen.height / $el.offsetHeight).toFixed(2) + 'cm',
  'Screen diagonal: ' + screenDiagonal.toFixed(2) + 'cm',
  'Screen diagonal: ' + screenDiagonalInches.toFixed(2) + 'in',
  'Device Pixel Ratio: ' + (window.devicePixelRatio || 1)
].join('\n');
var $pre = document.createElement('pre');
$pre.innerHTML = str;
document.body.appendChild($pre);

http://codepen.io/kus/full/xOAPYB/

Kus
fonte
1
Meu 40 polegadas relatado como um 22 polegadas.
RobotRock
Não é preciso para mim também. Acho que o problema é devido window.devicePixelRatio. É 1 em uma tela Apple Thunderbolt e 2 em um Macbook Pro Touchbar 15 ". Este valor é sempre um número inteiro? Isso não faria sentido, pois é uma proporção. Outros elementos: stackoverflow.com/questions/16385573/…
Tom
Pode não ter sido muito bom em 2016, mas relata um tamanho de tela de 45 "para meu PC desktop (o tamanho real é 40") e 10 "para meu Galaxy S10 +, que são próximos o suficiente para diferenciar entre diferentes escalas versões de IUs e documentos. Não sei por que você prefixou todas as variáveis ​​com $.
Alexander Gräf