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
- Garanta a meta tag de viewport no
headde todas as páginas. - Junte os dois arquivos de CSS em um só: as regras comuns ficam fora de qualquer media query.
- 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.
- Escreva a regra do layout largo dentro de
@mediacom essa largura, emem. - 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.widthpara 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
resizesem 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
matchMediacom o mesmo valor do CSS. - Nenhum código decide layout por
screen.widthou 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?
Referência: http://forum.wmonline.com.br/topic/191806-verificar-resolucao-do-navegador-e-trocar-css/