Comparar y CompareCaption

El atributo lang solo puede tener un idioma asociado. Esto significa que el atributo <html> solo puede tener un idioma, incluso si hay varios en la página. Configura lang como el idioma principal de la página.

Qué no debes hacer
<html lang="ar,en,fr,pt">...</html>
No se admiten varios idiomas.
<html lang="ar">...</html>
Establece solo el idioma principal de la página. En este caso, el idioma es el árabe.

Al igual que los botones, su nombre de accesibilidad se obtiene principalmente a partir del contenido de texto. Un buen truco para crear un vínculo es colocar el texto más significativo dentro del vínculo, en lugar de palabras de relleno como "Aquí" o "Leer más".

No es lo suficientemente descriptivo
Check out our guide to web performance <a href="/guide">here</a>.
Contenido útil
Check out <a href="/guide">our guide to web performance</a>.

Cómo comprobar si una animación activa un diseño

Es probable que una animación que mueve un elemento con otro elemento que no sea transform sea lenta. En el siguiente ejemplo, obtuve el mismo resultado visual con la animación de top y left, y con el uso de transform.

Qué no debes hacer
.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));
  }
}

Puedes probar esto en los siguientes dos ejemplos de Glitch y explorar el rendimiento con Herramientas para desarrolladores.

Con el mismo lenguaje de marcado, podemos reemplazar padding-top: 56.25% por aspect-ratio: 16 / 9 y establecer aspect-ratio en una proporción especificada de width / height.

Cómo usar padding-top
.container {
  width: 100%;
  padding-top: 56.25%;
}
Uso de la relación de aspecto
.container {
  width: 100%;
  aspect-ratio: 16 / 9;
}

El uso de aspect-ratio en lugar de padding-top es mucho más claro y no reajusta la propiedad de padding para hacer algo fuera de su alcance habitual.

Sí, así es, estoy usando reduce para encadenar una secuencia de promesas. Soy tan inteligente. Pero esta es una codificación un poco tan inteligente sin la cual te convendrá.

Sin embargo, cuando conviertes lo anterior en una función asíncrona, es tentador ser demasiado secuencial:

No se recomienda: demasiado secuencial
async function logInOrder(urls) {
  for (const url of urls) {
    const response = await fetch(url);
    console.log(await response.text());
  }
}
Se ve mucho más prolijo, pero mi segunda recuperación no comienza hasta que la primera se haya leído por completo, y así sucesivamente. Esto es mucho más lento que el ejemplo de promesas que realiza las recuperaciones en paralelo. Afortunadamente, hay un punto intermedio.
Recomendada: agradable y paralela
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);
  }
}
En este ejemplo, las URLs se recuperan y leen en paralelo, pero el bit "inteligente" reduce se reemplaza por un bucle for estándar y aburrido.

Escribe propiedades personalizadas de Houdini

Este es un ejemplo de cómo configurar una propiedad personalizada (p. ej., una variable de CSS), pero ahora con una sintaxis (tipo), un valor inicial (resguardo) y una herencia booleana (¿hereda el valor de su elemento superior o no?). La forma actual de hacerlo es a través de CSS.registerProperty() en JavaScript, pero en Chromium 85 y versiones posteriores, la sintaxis @property será compatible con los archivos CSS:

Archivo JavaScript independiente (Chromium 78)
CSS.registerProperty({
  name: '--colorPrimary',
  syntax: '',
  initialValue: 'magenta',
  inherits: false
});
Se incluye en el archivo CSS (Chromium 85)
@property --colorPrimary {
  syntax: '';
  initial-value: magenta;
  inherits: false;
}

Ahora puedes acceder a --colorPrimary como a cualquier otra propiedad personalizada de CSS mediante var(--colorPrimary). Sin embargo, la diferencia aquí es que --colorPrimary no se lee solo como una cadena. ¡Tiene datos!

CSS backdrop-filter aplica uno o más efectos a un elemento que es translúcido o transparente. Para entenderlo, ten en cuenta las siguientes imágenes.

Sin transparencia en primer plano
Triángulo superpuesto sobre un círculo. No se puede ver el círculo a través del triángulo.
.frosty-glass-pane {
  backdrop-filter: blur(2px);
}
Transparencia en primer plano
Triángulo superpuesto sobre un círculo. El triángulo es translúcido, lo que permite que se vea el círculo a través de él.
.frosty-glass-pane {
  opacity: .9;
  backdrop-filter: blur(2px);
}

En la imagen de la izquierda, se muestra cómo se renderizarían los elementos superpuestos si no se usara o se admitiera backdrop-filter. En la imagen de la derecha, se aplica un efecto de desenfoque con backdrop-filter. Ten en cuenta que usa opacity además de backdrop-filter. Sin el elemento opacity, no habría nada a lo que aplicarle el desenfoque. No hace falta decir que si opacity se configura como 1 (completamente opaco), no habrá efecto en el fondo.

Sin embargo, a diferencia del evento unload, existen usos legítimos para beforeunload. Por ejemplo, si deseas advertir al usuario que tiene cambios sin guardar, los perderá si abandona la página. En este caso, se recomienda que solo agregues objetos de escucha beforeunload cuando un usuario tenga cambios sin guardar y, luego, los quites inmediatamente después de que se guarden esos cambios.

Qué no debes hacer
window.addEventListener('beforeunload', (event) => {
  if (pageHasUnsavedChanges()) {
    event.preventDefault();
    return event.returnValue = 'Are you sure you want to exit?';
  }
});
El código anterior agrega un objeto de escucha beforeunload de forma incondicional.
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);
});
El código anterior solo agrega el objeto de escucha beforeunload cuando es necesario (y lo quita cuando no lo es).

Minimizar el uso de Cache-Control: no-store

Cache-Control: no-store es un encabezado HTTP que los servidores web pueden configurar en las respuestas para indicarle al navegador que no almacene la respuesta en ninguna caché HTTP. Se debe usar para recursos que contengan información sensible del usuario, por ejemplo, páginas con acceso protegido.

El elemento fieldset, que contiene cada grupo de entrada (.fieldset-item), usa gap: 1px para crear los bordes finos entre los elementos. ¡No es una solución de borde complicada!

Espacio lleno
.grid {
  display: grid;
  gap: 1px;
  background: var(--bg-surface-1);

  & > .fieldset-item {
    background: var(--bg-surface-2);
  }
}
Truco de borde
.grid {
  display: grid;

  & > .fieldset-item {
    background: var(--bg-surface-2);

    &:not(:last-child) {
      border-bottom: 1px solid var(--bg-surface-1);
    }
  }
}

Envoltura de cuadrícula natural

El diseño más complejo fue el diseño macro, el sistema de diseño lógico entre <main> y <form>.

salida
<input
  type="checkbox"
  id="text-notifications"
  name="text-notifications"
>
etiqueta
<label for="text-notifications">
  <h3>Text Messages</h3>
  <small>Get notified about all text messages sent to your device</small>
</label>

El elemento fieldset, que contiene cada grupo de entrada (.fieldset-item), usa gap: 1px para crear los bordes finos entre los elementos. ¡No es una solución de borde complicada!

Espacio lleno
.grid {
  display: grid;
  gap: 1px;
  background: var(--bg-surface-1);

  & > .fieldset-item {
    background: var(--bg-surface-2);
  }
}
Truco de borde
.grid {
  display: grid;

  & > .fieldset-item {
    background: var(--bg-surface-2);

    &:not(:last-child) {
      border-bottom: 1px solid var(--bg-surface-1);
    }
  }
}

Diseño de las pestañas <header>

El siguiente diseño es casi igual: uso flex para crear el orden vertical.

HTML
<snap-tabs>
  <header>
    <nav></nav>
    <span class="snap-indicator"></span>
  </header>
  <section></section>
</snap-tabs>
CSS
header {
  display: flex;
  flex-direction: column;
}

El .snap-indicator debe viajar horizontalmente con el grupo de vínculos, y este diseño de encabezado ayuda a establecer esa etapa. Aquí no hay elementos de posicionamiento absoluto.

Gentle Flex es una estrategia más centrada únicamente. Es suave y suave porque, a diferencia de place-content: center, no se cambian los tamaños de caja de los elementos secundarios durante el enfoque. Con la mayor suavidad posible, todos los elementos se apilan, se centran y se separan.

.gentle-flex {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1ch;
}
Ventajas
  • Solo controla la alineación, la dirección y la distribución
  • Las ediciones y el mantenimiento se encuentran en un solo lugar
  • La brecha garantiza que el espaciado sea igual entre n elementos secundarios.
Desventajas
  • La mayoría de las líneas de código

Ideal para diseños macro y micro.

Uso

gap acepta cualquier longitud o porcentaje de CSS como valor.

.gap-example {
  display: grid;
  gap: 10px;
  gap: 2ch;
  gap: 5%;
  gap: 1em;
  gap: 3vmax;
}


Se puede pasar 1 longitud para la brecha, que se usará tanto para la fila como para la columna.

Abreviatura
.grid {
  display: grid;
  gap: 10px;
}
Configurar filas y columnas juntas a la vez
Expandido
.grid {
  display: grid;
  row-gap: 10px;
  column-gap: 10px;
}


Se pueden pasar 2 longitudes para la brecha, que se usarán para la fila y la columna.

Abreviatura
.grid {
  display: grid;
  gap: 10px 5%;
}
Establece filas y columnas por separado al mismo tiempo
Expandido
.grid {
  display: grid;
  row-gap: 10px;
  column-gap: 5%;
}