Programação Por Equipe DevBras

Capa do artigo: Trocar o layout pela largura da tela com media query, não com script de resolução

Trocar o layout pela largura da tela com media query, não com script de resolução

Troque o script que mede a tela uma vez por media query no CSS, use matchMedia só quando o JavaScript precisa saber, e o layout passa a acompanhar giro, zoom e janela dividida.

O portal do bairro tem um script no topo que lê screen.width, decide entre desktop.css e mobile.css e escreve a tag de estilo na página. Funciona no teste. Aí uma leitora abre no tablet em pé, gira para deitado, e a página continua com a coluna espremida até ela recarregar. Outro leitor dá zoom de 200% no notebook e recebe o layout de desktop com letras gigantes saindo pela lateral. A resposta curta: a decisão de layout pela largura mora no CSS, em media queries, que o navegador reavalia sozinho a cada mudança de tamanho, giro ou zoom. Script só entra quando o JavaScript precisa reagir ao tamanho, e aí ele usa matchMedia, que avisa quando a condição muda.

A troca costuma apagar código: some o script de detecção, somem dois arquivos de CSS quase iguais e some o bug do giro.

Por que medir a tela no script falha

O primeiro erro é a medida. screen.width é o tamanho do monitor ou da tela do aparelho, não o espaço da página. Numa janela dividida ao meio, o monitor continua com 1920 pixels e a página tem 960. O valor certo para layout é a largura da janela de visualização, a viewport, que é exatamente o que a media query usa.

O segundo erro é o momento. O script lê uma vez, no carregamento. Tudo que acontece depois, giro do aparelho, redimensionamento da janela, zoom de acessibilidade, fica de fora. Já a media query não é uma leitura: é uma condição que o navegador mantém viva e reaplica quando a viewport muda.

O zoom merece destaque. Quando a pessoa aumenta o zoom do navegador para 200%, a viewport medida em pixels CSS cai pela metade. Um notebook com 1280 pixels de janela passa a se comportar como uma tela de 640. Com media query, essa pessoa recebe o layout de uma coluna, que é justamente o que ela precisa para ler sem rolar para o lado. Com o script de resolução, ela fica presa no layout largo.

Por fim, nada disso funciona no celular sem a meta tag de viewport. Sem ela, o navegador móvel finge ter uma tela larga, perto de 980 pixels, e reduz a página inteira para caber, e a sua media query para telas estreitas nunca dispara.

Como trocar o script por media query

  1. Garanta a meta tag de viewport no head de todas as páginas.
  2. Junte os dois arquivos de CSS em um só: as regras comuns ficam fora de qualquer media query.
  3. Escolha o ponto de quebra pelo conteúdo: estreite a janela devagar e anote a largura em que o layout de duas colunas começa a ficar ruim.
  4. Escreva a regra do layout largo dentro de @media com essa largura, em em.
  5. Apague o script de detecção e teste girando, redimensionando e dando zoom, sem recarregar.

No portal, a página tem o texto da notícia e uma barra lateral com as mais lidas. O texto fica confortável até perto de 70 caracteres por linha; a barra lateral precisa de uns 18em para os títulos não quebrarem em quatro linhas. Somando texto, barra e espaço entre eles, as duas colunas só cabem a partir de uns 56em. Abaixo disso, empilha.

<meta name="viewport" content="width=device-width, initial-scale=1">
/* estilo.css */
.pagina {
  display: grid;
  gap: 2em;
  max-width: 70em;
  margin: 0 auto;
  padding: 0 1em;
}

.noticia {
  max-width: 70ch;
}

@media (min-width: 56em) {
  .pagina {
    grid-template-columns: minmax(0, 1fr) 18em;
  }
}

Sem a media query, a grade tem uma coluna só e a barra lateral desce para baixo da notícia. A partir de 56em, entra a segunda coluna. Usar em no ponto de quebra tem uma vantagem: em media queries, o em se refere ao tamanho de fonte padrão do navegador, então quem configurou letra maior no sistema também recebe o layout empilhado mais cedo.

Se você escreve o CSS partindo do celular, como no guia de CSS mobile-first, a regra base é a estreita e as queries só acrescentam, que é exatamente o formato acima.

Quando o componente depende do espaço dele, não da tela

Às vezes o cartão de notícia aparece largo no corpo da página e estreito na barra lateral, na mesma tela. Media query olha a viewport e não resolve isso. Para esse caso existem as container queries, suportadas pelos navegadores atuais: o elemento pai declara container-type: inline-size e o filho usa @container (min-width: 30em) para mudar conforme a largura do pai. Use quando o mesmo componente vive em lugares de largura diferente.

Quando o JavaScript precisa saber a largura

Há casos legítimos: um carrossel que mostra três itens no largo e um no estreito, ou um menu que precisa fechar quando a tela cresce. Mesmo aí, não leia a largura em todo evento de resize. Use matchMedia com a mesma condição do CSS e escute o evento change, que só dispara quando a condição vira.

const largo = window.matchMedia('(min-width: 56em)');

function aplicarModo(e) {
  document.body.dataset.modo = e.matches ? 'largo' : 'estreito';
  if (e.matches) {
    fecharMenuMovel();
  }
}

aplicarModo(largo);
largo.addEventListener('change', aplicarModo);

function fecharMenuMovel() {
  const botao = document.querySelector('#botao-menu');
  if (botao) botao.setAttribute('aria-expanded', 'false');
}

A função roda uma vez no carregamento, com o estado atual, e depois só quando a página cruza os 56em. Manter o número igual ao do CSS é o que evita o estado estranho em que o CSS mostra duas colunas e o script acha que está no celular.

O menu que abre e fecha, aliás, é estado, não resolução: ele é controlado por um botão com aria-expanded. A largura só decide se o botão aparece.

Erros comuns

  • Usar screen.width para decidir layout. Janela dividida e monitor grande com janela pequena recebem o layout errado.
  • Esquecer a meta tag de viewport. O celular renderiza como desktop reduzido e nenhuma query estreita dispara.
  • Manter dois CSS completos e escolher um no script. Toda correção precisa ser feita duas vezes, e uma das versões sempre fica para trás.
  • Escolher ponto de quebra pelo celular da moda. O aparelho do ano que vem tem outra largura; o conteúdo continua quebrando no mesmo lugar.
  • Detectar navegador ou sistema no lugar da largura. O mesmo navegador roda no telefone, no tablet e no monitor de 27 polegadas.
  • Ler a largura em todo resize sem necessidade. O código roda dezenas de vezes por segundo enquanto a janela é arrastada.

Checklist

  • Todas as páginas têm a meta tag de viewport.
  • Existe um único arquivo de CSS para o layout, com media queries.
  • Estreitar a janela devagar muda o layout sem recarregar.
  • Girar o celular muda o layout na hora.
  • Zoom de 200% no desktop leva ao layout de uma coluna, sem rolagem lateral.
  • O script, se existe, usa matchMedia com o mesmo valor do CSS.
  • Nenhum código decide layout por screen.width ou por nome de navegador.

Tabelas largas têm um problema próprio nesse cenário, tratado em tabela que quebra no celular. Abra o seu site, dê zoom de 200% sem recarregar e responda: o layout mudou, ou você está rolando para o lado para ler uma linha?

Avalie este artigo

Referência: http://forum.wmonline.com.br/topic/191806-verificar-resolucao-do-navegador-e-trocar-css/