Superficies
Este skill decide de qué está hecho cada elemento: su relleno, borde, sombra, radio, estados e iconos. Elige de una lista corta de recetas, así dos pantallas nunca llevan dos tarjetas diferentes.
Antes de cualquier decisión, aplica product-ui §1 (el diario de gusto y precedencia) y §5 (qué skill es dueño de qué).
Decide en este orden
- ¿Se necesita una superficie? Elimina antes de añadir. Un título con espacio alrededor no necesita tarjeta. Nunca anides una tarjeta dentro de otra tarjeta. Por qué: cada contenedor añade un borde que el ojo debe leer.
- ¿Qué nivel? Página, elevado, flotante o superpuesto. Un nivel por elemento, elegido por lo que hace, no por cuánto quieres que destaque. elevation.md.
- ¿Qué dibuja el borde? La elevación obtiene un anillo de sombra. La estructura obtiene un borde. Nunca ambos en un mismo borde. elevation.md.
- ¿Qué radio? Toma el token para el rol del elemento, luego haz que los radios anidados sean concéntricos. elevation.md.
- ¿Qué estados? Diseña hover, presionado, seleccionado, deshabilitado y focus-visible como cambios en la superficie, antes de pulir el estado por defecto. states-and-icons.md.
- ¿Qué tratamiento de iconos? Un conjunto,
currentColor, trazo igualado al texto. states-and-icons.md. - ¿Está permitido un material? Solo cromo flotante sobre contenido que se desplaza. materials-and-edges.md.
- Bordes del scroll. Divisores, desvanecimientos, overscroll. materials-and-edges.md.
Los cuatro niveles
| Nivel | Para | Claro | Oscuro |
|---|---|---|---|
| Página | El fondo | Relleno de fondo, sin sombra | Relleno más oscuro, sin sombra |
| Elevado | Tarjetas, controles, la opción seleccionada | Blanco, anillo + 1px de caída + 3px de caída ajustada | Un tono más claro, anillo blanco, caída negra ajustada |
| Flotante | Menús, popovers, tooltips, toasts | Blanco, anillo + 1px de caída + 4px de caída ajustada | Dos tonos más claro, anillo blanco, caída negra ajustada |
| Superpuesto | Diálogos, hojas, paleta de comandos (con un scrim) | Blanco, anillo + 1px de caída + 6px de caída ajustada | Tres tonos más claro, anillo blanco, caída negra ajustada |
Los tokens exactos están en elevation.md. Las reglas detrás de ellos:
- Un anillo más una caída ajustada. Desenfoque ≤ 8px, desplazamiento ≤ 6px, caídas con una dispersión negativa. Por qué: los desenfoques grandes y suaves se leen como brillo, ensucian la página y parecen generados.
- El modo oscuro se eleva volviéndose más claro. Las sombras apenas se ven en oscuro, así que la claridad transmite altura y un anillo blanco con baja opacidad transmite el borde.
- Las sombras son translúcidas y de un solo color. Los grises opacos dejan un halo. Las caídas oscuras permanecen negras.
- Los hermanos comparten un nivel. Las tarjetas en una fila tienen una sombra, un radio, un relleno.
- Hover cambia el relleno, no la sombra.
Reglas que no necesitan referencia
- Los bordes muestran estructura, las sombras muestran elevación. Divisores, inputs, celdas de tabla y estados seleccionados mantienen bordes. Una tarjeta cuyo borde existe solo para elevarla obtiene un anillo.
- Mantén
border: 1px solid transparentdebajo de un anillo de sombra. Por qué: el modo de colores forzados elimina las sombras, y el borde aún dibuja un borde. - Las imágenes obtienen un contorno interior de 1px:
outline: 1px solidnegro al 10% (blanco al 10% en oscuro),outline-offset: -1px. Nunca un color teñido, que aparece como un fleco. Omite logotipos y obras de arte transparentes. - Radio concéntrico. Exterior = interior + relleno (+ borde), hasta 24px de relleno. Más allá, son superficies separadas.
- El foco es un anillo, nunca nada.
:focus-visiblemuestra un contorno de acento de 2px con un desplazamiento de 2px; los campos lo toman al ras, como un borde de acento de 2px sin espacio.outline: nonesin un reemplazo es un error. El anillo no ocupa espacio de diseño. - Los controles deshabilitados no tienen hover, presión ni escala.
- Iconos: un conjunto por superficie,
currentColor, contorno por defecto y relleno cuando está activo. El trazo sigue el peso del texto vecino, 1.5px a 400 hasta 2px a 600. - Desenfoque detrás solo en cromo flotante. Nunca en contenido, tarjetas o tablas.
- Superposiciones desplazables (diálogos, cajones, menús) obtienen
overscroll-behavior: contain.
Pares
| Roto | Arreglado | Por qué |
|---|---|---|
border: 1px solid #e5e5e5 en una tarjeta | box-shadow: var(--elev-raised); border: 1px solid transparent | Un borde de solo profundidad se convierte en anillo; los colores forzados aún dibujan un borde |
box-shadow: 0 10px 40px rgba(0,0,0,.2) | 0 0 0 1px a.08, 0 1px 2px a.12, 0 4px 8px -4px a.16 | Ajustado y nítido vence a grande y suave |
Tarjeta oscura con 0 8px 24px #000 | Relleno más claro más 0 0 0 1px oklch(1 0 0 / .08) | Las sombras desaparecen en oscuro; la claridad muestra altura |
| Radio de tarjeta 8, radio de imagen interior 8, relleno 8 | Interior 8, exterior 16 | Las esquinas concéntricas mantienen un espacio uniforme |
<img> fundiéndose en una tarjeta blanca | outline: 1px solid oklch(0 0 0 / .1); outline-offset: -1px | El borde se lee sin un borde |
button:focus { outline: none } | button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px } | Los usuarios de teclado mantienen su lugar |
| Trazo de icono de 1.5px junto a una etiqueta de peso 600 | Trazo de 2px | El peso del trazo coincide con el peso del tallo |
| Iconos rellenos en cada ranura de la barra de herramientas | Contorno por defecto, relleno para el activo | El relleno es la señal de estado |
backdrop-filter: blur(20px) en una tarjeta | Una superficie opaca | El desenfoque pertenece al cromo que flota sobre contenido desplazable |
Antes de terminar
| Patrón | Arreglo |
|---|---|
box-shadow con desenfoque > 8px o alfa > .2 en UI claro | Usa un token de nivel |
border más box-shadow haciendo el mismo trabajo | Anillo más borde transparente solamente |
Anillo de sombra sin border: 1px solid transparent | Agrégarlo |
Mismo border-radius en un padre y su hijo con relleno | inner + padding para el padre |
outline: none o outline: 0 sin reemplazo :focus-visible | Agrega el anillo |
:focus (no :focus-visible) estilizando un anillo | Cambia a :focus-visible |
border-width cambiando en un estado | Color, relleno o un borde transparente del mismo ancho |
fill="#…" o stroke="#…" codificado en un icono | currentColor |
| Dos bibliotecas de iconos importadas en una pantalla | Una |
backdrop-filter fuera de una barra fija, barra lateral o menú flotante | Quítalo |
Lista de superposición sin overscroll-behavior: contain | Agrégarlo |
Corte duro en el borde de un desplazador, o una sombra recortada por overflow: hidden | Desvanece el borde; añade relleno al desplazador |
Verifica renderizando claro y oscuro a 2× y recortando un borde de cada nivel. Pasa el ratón, presiona, presiona Tab para enfocar, selecciona y deshabilita cada control y compara el tamaño de la caja antes y después. Alterna colores forzados (DevTools de Chrome, emulación de renderizado) y confirma que cada tarjeta aún tiene un borde.