O atributo lang pode ter apenas um idioma associado a ele. Isso significa
que o atributo <html>
só pode ter um idioma, mesmo que haja vários
na página. Defina lang
como o idioma principal da página.
<html lang="ar,en,fr,pt">...</html>Não há suporte para vários idiomas.
<html lang="ar">...</html>Defina apenas o idioma principal da página. Nesse caso, o idioma é o árabe.
Links
Assim como os botões, os links têm o nome acessível principalmente pelo conteúdo de texto. Um bom truque ao criar um link é inserir o texto mais significativo no próprio link, em vez de preencher palavras como "aqui" ou "leia mais".
Check out our guide to web performance <a href="/guide">here</a>.
Check out <a href="/guide">our guide to web performance</a>.
Verificar se uma animação aciona o layout
Uma animação que move um elemento usando algo diferente de transform
provavelmente será lenta.
No exemplo abaixo, alcancei o mesmo resultado visual com a animação de top
e left
e o uso de transform
.
.box { position: absolute; top: 10px; left: 10px; animation: move 3s ease infinite; } @keyframes move { 50% { top: calc(90vh - 160px); left: calc(90vw - 200px); } }
.box { position: absolute; top: 10px; left: 10px; animation: move 3s ease infinite; } @keyframes move { 50% { transform: translate(calc(90vw - 200px), calc(90vh - 160px)); } }
É possível testar isso nos dois exemplos do Glitch a seguir e explorar a performance usando o DevTools.
Com a mesma marcação, podemos substituir: padding-top: 56.25%
por aspect-ratio: 16 / 9
, definindo
aspect-ratio
como uma proporção especificada de width
/ height
.
.container { width: 100%; padding-top: 56.25%; }
.container { width: 100%; aspect-ratio: 16 / 9; }
O uso de aspect-ratio
em vez de padding-top
é muito mais claro e não substitui a propriedade
de padding para fazer algo fora do escopo habitual.
Isso mesmo. Estou usando reduce
para encadear uma sequência de promessas. Sou muito
inteligente. Mas essa é uma codificação inteligente que facilita o trabalho sem ela.
No entanto, ao converter o item acima para uma função assíncrona, é tentador ser sequencial demais:
async function logInOrder(urls) { for (const url of urls) { const response = await fetch(url); console.log(await response.text()); } }Parece muito mais elegante, mas minha segunda busca não começa até que a primeira tenha sido totalmente lida e assim por diante. Isso é muito mais lento do que o exemplo de promessas que executa as buscas em paralelo. Felizmente há um meio-termo ideal.
function markHandled(...promises) { Promise.allSettled(promises); } async function logInOrder(urls) { // fetch all the URLs in parallel const textPromises = urls.map(async (url) => { const response = await fetch(url); return response.text(); }); markHandled(...textPromises); // log them in sequence for (const textPromise of textPromises) { console.log(await textPromise); } }Neste exemplo, os URLs são buscados e lidos em paralelo, mas o bit
reduce
"inteligente" é substituído por um loop for padrão, chato e legível.
Como gravar propriedades personalizadas do Houdini
Veja um exemplo de como configurar uma propriedade personalizada (como a variável CSS), mas agora com sintaxe (tipo), valor inicial (substituto) e booleano de herança (ele herda o valor do pai ou não?). A maneira atual de fazer isso é
com CSS.registerProperty()
em JavaScript, mas no Chromium 85 e versões posteriores, a sintaxe
@property
será compatível com seus arquivos CSS:
CSS.registerProperty({ name: '--colorPrimary', syntax: '', initialValue: 'magenta', inherits: false });
@property --colorPrimary { syntax: ''; initial-value: magenta; inherits: false; }
Agora é possível acessar --colorPrimary
como qualquer outra propriedade personalizada de CSS usando var(--colorPrimary)
. No entanto, a diferença é que --colorPrimary
não é
apenas lido como uma string. Ela tem dados!
A CSS backdrop-filter
aplica um ou mais efeitos a um elemento translúcido ou transparente. Para entender isso, considere as imagens abaixo.
![Um triângulo sobreposto em um círculo. Não é possível ver o círculo dentro do triângulo.](https://web.dev/static/examples/image/admin/LOqxvB3qqVkbZBmxMmKS.png?hl=pt-br)
.frosty-glass-pane { backdrop-filter: blur(2px); }
![Um triângulo sobreposto em um círculo. O triângulo é translúcido, o que permite que o círculo seja visto através dele.](https://web.dev/static/examples/image/admin/VbyjpS6Td39E4FudeiVg.png?hl=pt-br)
.frosty-glass-pane { opacity: .9; backdrop-filter: blur(2px); }
A imagem à esquerda mostra como elementos sobrepostos seriam renderizados se o backdrop-filter
não fosse usado nem compatível. A imagem à direita aplica um efeito de desfoque usando backdrop-filter
. Observe que ele usa opacity
, além de backdrop-filter
. Sem o opacity
, não há nada para aplicar o desfoque. É quase óbvio que, se opacity
for definida como 1
(totalmente opaco), não haverá efeito no segundo plano.
No entanto, ao contrário do evento unload
, há usos legítimos para
beforeunload
. Por exemplo, quando você quiser avisar ao usuário que ele fez
alterações não salvas, ele será perdido se sair da página. Nesse caso,
recomendamos adicionar listeners beforeunload
somente quando um usuário tiver mudanças
não salvas e, em seguida, removê-los imediatamente após salvar as mudanças.
window.addEventListener('beforeunload', (event) => { if (pageHasUnsavedChanges()) { event.preventDefault(); return event.returnValue = 'Are you sure you want to exit?'; } });O código acima adiciona um listener
beforeunload
incondicionalmente.
function beforeUnloadListener(event) { event.preventDefault(); return event.returnValue = 'Are you sure you want to exit?'; }; // A function that invokes a callback when the page has unsaved changes. onPageHasUnsavedChanges(() => { window.addEventListener('beforeunload', beforeUnloadListener); }); // A function that invokes a callback when the page's unsaved changes are resolved. onAllChangesSaved(() => { window.removeEventListener('beforeunload', beforeUnloadListener); });O código acima só adiciona o listener
beforeunload
quando necessário (e
o remove quando não é).
Minimizar o uso de Cache-Control: no-store
Cache-Control: no-store
é um cabeçalho HTTP que os servidores da Web podem definir em respostas que instrui o navegador a não armazenar a resposta em nenhum cache HTTP. Ela deve ser usada para recursos que contêm informações sensíveis do usuário, como páginas protegidas por login.
O elemento fieldset
, que contém cada grupo de entrada (.fieldset-item
), está usando gap: 1px
para
criar as bordas finas entre elementos. Nenhuma solução de borda complicada.
.grid { display: grid; gap: 1px; background: var(--bg-surface-1); & > .fieldset-item { background: var(--bg-surface-2); } }
.grid { display: grid; & > .fieldset-item { background: var(--bg-surface-2); &:not(:last-child) { border-bottom: 1px solid var(--bg-surface-1); } } }
Quebra natural de grade
O layout mais complexo acabou sendo o layout de macro, o sistema
lógico de layout entre <main>
e <form>
.
<input type="checkbox" id="text-notifications" name="text-notifications" >
<label for="text-notifications"> <h3>Text Messages</h3> <small>Get notified about all text messages sent to your device</small> </label>
O elemento fieldset
, que contém cada grupo de entrada (.fieldset-item
), está usando gap: 1px
para
criar as bordas finas entre elementos. Nenhuma solução de borda complicada.
.grid { display: grid; gap: 1px; background: var(--bg-surface-1); & > .fieldset-item { background: var(--bg-surface-2); } }
.grid { display: grid; & > .fieldset-item { background: var(--bg-surface-2); &:not(:last-child) { border-bottom: 1px solid var(--bg-surface-1); } } }
Layout das guias <header>
O próximo layout é quase o mesmo: uso flexível para criar ordenação vertical.
<snap-tabs> <header> <nav></nav> <span class="snap-indicator"></span> </header> <section></section> </snap-tabs>
header { display: flex; flex-direction: column; }
O .snap-indicator
precisa viajar horizontalmente com o grupo de links, e
esse layout de cabeçalho ajuda a definir esse estágio. Não há elementos de posição absoluta aqui.
O Gentle Flex é uma verdadeira estratégiaúnica. É suave e suave, porque,
ao contrário da place-content: center
, nenhum tamanho de caixa infantil é modificado durante a
centralização. Da forma mais suave possível, todos os itens são empilhados, centralizados e espaçados.
.gentle-flex {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 1ch;
}
- Processa apenas o alinhamento, a direção e a distribuição.
- Edições e manutenção em um só lugar
- A lacuna garante espaçamento igual entre n filhos
- A maioria das linhas de código
Ótimo para layouts macro e micro.
Uso
gap
aceita qualquer comprimento ou porcentagem de CSS como um valor.
.gap-example {
display: grid;
gap: 10px;
gap: 2ch;
gap: 5%;
gap: 1em;
gap: 3vmax;
}
A lacuna pode ser transmitida em um comprimento, que será usado para linha e coluna.
.grid { display: grid; gap: 10px; }Defina as linhas e colunas de uma só vez
.grid { display: grid; row-gap: 10px; column-gap: 10px; }
A lacuna pode ser transmitida para dois comprimentos, que serão usados para linha e coluna.
.grid { display: grid; gap: 10px 5%; }Defina as linhas e colunas separadamente de uma só vez
.grid { display: grid; row-gap: 10px; column-gap: 5%; }