O atributo lang só pode ter um idioma associado a ele. Isso significa
que o atributo <html>
só pode ter um idioma, mesmo que haja vários
idiomas na página. Defina lang
como o idioma principal da página.
<html lang="ar,en,fr,pt">...</html>
<html lang="ar">...</html>
Links
Assim como os botões, os links recebem o nome acessível principalmente do conteúdo de texto. Um bom truque ao criar um link é colocar o texto mais significativo no próprio link, em vez de palavras de enchimento 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, consegui o mesmo resultado visual animando top
e left
e usando 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)); } }
Você pode testar isso nos dois exemplos de Glitch a seguir e conferir 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; }
Usar aspect-ratio
em vez de padding-top
é muito mais claro e não altera a propriedade
de padding para fazer algo fora do escopo normal.
Sim, isso mesmo, estou usando reduce
para ligar de uma sequência de promessas. Eu sou tão
inteligente. Mas isso é uma codificação muito inteligente que é melhor não usar.
No entanto, ao converter o item acima para uma função assíncrona, é tentador ser muito sequencial:
async function logInOrder(urls) { for (const url of urls) { const response = await fetch(url); console.log(await response.text()); } }
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); } }
reduce
"inteligente" é substituído por um loop for padrão, enfadonho e legível.
Como gravar propriedades personalizadas do Houdini
Confira um exemplo de como definir uma propriedade personalizada (pense em uma variável CSS), mas agora
com uma sintaxe (tipo), um valor inicial (padrão) e um booleano de herança (ele
herda o valor do pai ou não?). Atualmente, isso é feito
usando CSS.registerProperty()
no JavaScript, mas no Chromium 85 e versões mais recentes, a
sintaxe @property
será compatível com os 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 do CSS, por meio de
var(--colorPrimary)
. No entanto, a diferença aqui é que --colorPrimary
não
é lido apenas como uma string. Ele tem dados!
O CSS backdrop-filter
aplica um ou mais efeitos a um elemento translúcido ou transparente. Para entender isso, considere as imagens abaixo.

.frosty-glass-pane { backdrop-filter: blur(2px); }

.frosty-glass-pane { opacity: .9; backdrop-filter: blur(2px); }
A imagem à esquerda mostra como os elementos sobrepostos seriam renderizados se backdrop-filter
não fosse usado ou não tivesse suporte. A imagem à direita aplica um efeito de desfoque usando backdrop-filter
. Ele usa opacity
, além de backdrop-filter
. Sem opacity
, não haveria nada para aplicar o desfoque. Se opacity
for definido como 1
(totalmente opaco), não haverá efeito no plano de fundo.
No entanto, ao contrário do evento unload
, há usos legítimos para
beforeunload
. Por exemplo, quando você quer avisar o usuário de que ele tem
mudanças não salvas que serão perdidas se ele sair da página. Nesse caso, é
recomendado adicionar listeners beforeunload
apenas quando um usuário tiver alterações não salvas
e removê-los imediatamente após as alterações não salvas serem salvas.
window.addEventListener('beforeunload', (event) => { if (pageHasUnsavedChanges()) { event.preventDefault(); return event.returnValue = 'Are you sure you want to exit?'; } });
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); });
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 instruem o navegador a não armazenar a resposta em nenhum cache HTTP. Isso deve ser usado para recursos que contêm informações sensíveis do usuário, por exemplo, páginas protegidas por login.
O elemento fieldset
, que contém cada grupo de entrada (.fieldset-item
), usa gap: 1px
para
criar as bordas finas entre os elementos. Não há solução de fronteira 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 macro layout, o sistema de layout lógico
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
), usa gap: 1px
para
criar as bordas finas entre os elementos. Não há solução de fronteira 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 de <header>
das guias
O próximo layout é quase o mesmo: uso o flex para criar a 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 se mover horizontalmente com o grupo de links, e
esse layout de cabeçalho ajuda a definir esse estágio. Não há elementos posicionados de forma absoluta aqui.
O Gentle Flex é uma estratégia de centralização mais verdadeira. Ele é suave e suave, porque
diferente de place-content: center
, nenhum tamanho de caixa de crianças é alterado durante a
centralização. Com cuidado, 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
- As edições e a manutenção ficam em um só lugar
- O intervalo garante o mesmo espaçamento entre n crianças
- A maioria das linhas de código
Ótimo para layouts macro e micro.
Uso
gap
aceita qualquer length
ou percentage CSS como valor.
.gap-example {
display: grid;
gap: 10px;
gap: 2ch;
gap: 5%;
gap: 1em;
gap: 3vmax;
}
O intervalo pode ser transmitido com 1 comprimento, que será usado para linha e coluna.
.grid { display: grid; gap: 10px; }
.grid { display: grid; row-gap: 10px; column-gap: 10px; }
O intervalo pode receber duas medidas, que serão usadas para linha e coluna.
.grid { display: grid; gap: 10px 5%; }
.grid { display: grid; row-gap: 10px; column-gap: 5%; }