Descripción general fundamental de cómo compilar componentes de <button>
que se adapten al color, sean responsivos y accesibles.
En esta publicación, quiero compartir mis ideas sobre cómo crear un elemento <button>
que se adapte al color, responsivo y accesible.
Prueba la demostración y consulta la fuente.
Si prefieres ver un video, aquí tienes una versión de YouTube de esta publicación:
Descripción general
El elemento <button>
está diseñado para la interacción del usuario. Su evento click
se activa desde el teclado, el mouse, el tacto, la voz y otras funciones, con reglas inteligentes sobre su tiempo. También incluye algunos estilos predeterminados en cada navegador, de modo que puedes usarlos directamente sin personalización. Usa color-scheme
para habilitar también los botones claros y oscuros proporcionados por el navegador.
También hay diferentes tipos de botones, cada uno de los cuales se muestra en la incorporación anterior de Codepen. Un <button>
sin un tipo se
adaptará a estar dentro de un <form>
y cambiará al tipo de envío.
<!-- buttons -->
<button></button>
<button type="submit"></button>
<button type="button"></button>
<button type="reset"></button>
<!-- button state -->
<button disabled></button>
<!-- input buttons -->
<input type="button" />
<input type="file">
En el desafío de la GUI de este mes, cada botón tendrá estilos para ayudar a diferenciar visualmente su intención. Los botones para restablecer tendrán colores de advertencia, ya que son destructivos, y los botones para enviar tendrán un texto de acento azul para que parezca un poco más promovido que los botones normales.
![Vista previa del conjunto final de todos los tipos de botones, que se muestra en un formulario y no en un formulario, con buenas adiciones para botones de íconos y botones personalizados.](https://web.dev/static/articles/building/a-button-component/image/preview-the-final-set-a-f0edd66ff9463.png?authuser=6&hl=es)
Los botones también tienen seudoclases para que las CSS las usen a fin de definir los diseños. Estas clases proporcionan hooks de CSS para personalizar la sensación del botón: :hover
para cuando un mouse está sobre el botón, :active
para cuando un mouse o teclado presiona y :focus
o :focus-visible
para ayudar con el estilo de tecnología de accesibilidad.
button:hover {}
button:active {}
button:focus {}
button:focus-visible {}
![Vista previa del conjunto final de todos los tipos de botones en el tema oscuro.](https://web.dev/static/articles/building/a-button-component/image/preview-the-final-set-a-65448775506f6.png?authuser=6&hl=es)
Marca
Además de los tipos de botones que proporciona la especificación HTML, agregué un botón con un ícono y otro con una clase personalizada btn-custom
.
<button>Default</button>
<input type="button" value="<input>"/>
<button>
<svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
<path d="..." />
</svg>
Icon
</button>
<button type="submit">Submit</button>
<button type="button">Type Button</button>
<button type="reset">Reset</button>
<button disabled>Disabled</button>
<button class="btn-custom">Custom</button>
<input type="file">
Luego, para realizar pruebas, cada botón se coloca dentro de un formulario. De esta manera, puedo asegurarme de que los diseños se actualicen de forma adecuada para el botón predeterminado, que se comporta como un botón de envío. También cambio la estrategia de íconos, de SVG intercalado a SVG enmascarado, para asegurarme de que ambos funcionen por igual.
<form>
<button>Default</button>
<input type="button" value="<input>"/>
<button>Icon <span data-icon="cloud"></span></button>
<button type="submit">Submit</button>
<button type="button">Type Button</button>
<button type="reset">Reset</button>
<button disabled>Disabled</button>
<button class="btn-custom btn-large" type="button">Large Custom</button>
<input type="file">
</form>
La matriz de combinaciones es bastante abrumadora en este punto. Entre los tipos de botones, las seudoclases y el hecho de estar dentro o fuera de una forma, hay más de 20 combinaciones de botones. Lo bueno es que CSS pueda ayudarnos a articular cada uno de ellos con claridad.
Accesibilidad
Los elementos de botones son accesibles de manera natural, pero hay algunas mejoras comunes.
Coloca el cursor sobre un elemento y enfoca
Me gusta agrupar :hover
y :focus
con el seudoselector funcional :is()
. Esto ayuda a garantizar que mis interfaces siempre tengan en cuenta los estilos de teclado y tecnología de asistencia.
button:is(:hover, :focus) {
…
}
Anillo de enfoque interactivo
Me gusta animar el anillo de enfoque para los usuarios de teclado y tecnología de accesibilidad. Para ello, puedo animar el contorno del botón 5 px alejando el contorno del botón, pero solo cuando el botón no esté activo. Esto crea un efecto que hace que el anillo de enfoque se reduzca al tamaño del botón cuando se presiona.
:where(button, input):where(:not(:active)):focus-visible {
outline-offset: 5px;
}
Cómo asegurar el contraste de colores de paso
Existen al menos cuatro combinaciones de colores diferentes para claro y oscuro que deben tener en cuenta el contraste de color: botón, botón de envío, botón de restablecimiento y botón inhabilitado. VisBug se usa aquí para inspeccionar y mostrar todas sus puntuaciones a la vez:
Ocultar iconos a personas que no pueden ver
Cuando se crea un botón de ícono, este debe proporcionar soporte visual para el texto del botón. Esto también significa que el ícono no es valioso para una persona con pérdida de vista. Por suerte, el navegador proporciona una forma de ocultar elementos de la tecnología del lector de pantalla para que las personas con pérdida de visión no se molesten con las imágenes de botones decorativos:
<button>
<svg … aria-hidden="true">...</svg>
Icon Button
</button>
![Las Herramientas para desarrolladores de Chrome muestran el árbol de accesibilidad del botón. El árbol ignora la imagen del botón porque tiene aria-hidden configurado como verdadero.](https://web.dev/static/articles/building/a-button-component/image/chrome-devtools-showing-4f9517c567e4c.png?authuser=6&hl=es)
Estilos
En la siguiente sección, primero estableceré un sistema de propiedades personalizadas para administrar los estilos adaptables del botón. Con esas propiedades personalizadas, puedo comenzar a seleccionar elementos y personalizar su aspecto.
Una estrategia de propiedades personalizadas adaptables
La estrategia de propiedades personalizadas que se usa en este desafío de la GUI es muy similar a la que se usa para crear un esquema de colores. En el caso de un sistema de colores claro y oscuro adaptable, se define una propiedad personalizada para cada tema y se le asigna un nombre correspondiente. Luego, se usa una sola propiedad personalizada para conservar el valor actual del tema y se asigna a una propiedad de CSS. Luego, la propiedad personalizada única se puede actualizar a un valor diferente y, luego, se actualiza el diseño del botón.
button {
--_bg-light: white;
--_bg-dark: black;
--_bg: var(--_bg-light);
background-color: var(--_bg);
}
@media (prefers-color-scheme: dark) {
button {
--_bg: var(--_bg-dark);
}
}
Lo que me gusta es que los temas claro y oscuro son declarativos y claros. La indirecta y la abstracción se descargan en la propiedad personalizada --_bg
, que ahora es la única propiedad "reactiva"; --_bg-light
y --_bg-dark
son estáticas. También está claro que el tema claro es el predeterminado y que el oscuro solo se aplica de forma condicional.
Cómo prepararse para la coherencia del diseño
El selector compartido
El siguiente selector se usa para apuntar a todos los tipos de botones y es un poco abrumador al principio. Se usa :where()
, por lo que la personalización del botón no requiere especificidad. Los botones a menudo se adaptan para situaciones alternativas y el selector :where()
garantiza que la tarea sea fácil. Dentro de :where()
, se selecciona cada tipo de botón, incluido el ::file-selector-button
, que no se puede usar dentro de :is()
ni :where()
.
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"],
input[type="file"]
),
:where(input[type="file"])::file-selector-button {
…
}
Todas las propiedades personalizadas se determinarán dentro de este selector. Es hora de revisar todas las propiedades personalizadas. Hay varias propiedades personalizadas que se usan en este botón. Describiré cada grupo a medida que avanzamos y, luego, compartiré los contextos oscuros y reducidos de movimientos al final de la sección.
Color de los elementos destacados del botón
Los botones y los íconos de envío son ideales para un toque de color:
--_accent-light: hsl(210 100% 40%);
--_accent-dark: hsl(210 50% 70%);
--_accent: var(--_accent-light);
Color del texto del botón
Los colores del texto de los botones no son blanco ni negro. Son versiones oscurecidas o aclaradas de --_accent
que usan hsl()
y se ajustan al tono 210
:
--_text-light: hsl(210 10% 30%);
--_text-dark: hsl(210 5% 95%);
--_text: var(--_text-light);
Color del botón de la parte inferior
Los fondos de los botones siguen el mismo patrón de hsl()
, excepto los botones para el Tema claro: se configuran en blanco para que su superficie los haga aparecer cerca del usuario o frente a otras superficies:
--_bg-light: hsl(0 0% 100%);
--_bg-dark: hsl(210 9% 31%);
--_bg: var(--_bg-light);
Botón en segundo plano
Este color de fondo sirve para hacer que una superficie aparezca detrás de otras superficies, lo que es útil para el fondo de la entrada del archivo:
--_input-well-light: hsl(210 16% 87%);
--_input-well-dark: hsl(204 10% 10%);
--_input-well: var(--_input-well-light);
Relleno del botón
El espaciado alrededor del texto del botón se realiza con la unidad ch
, una longitud relativa al tamaño de fuente. Esto resulta fundamental cuando los botones grandes pueden aumentar el font-size
y el botón se escala proporcionalmente:
--_padding-inline: 1.75ch;
--_padding-block: .75ch;
Borde del botón
El radio del borde del botón se almacena de forma temporal en una propiedad personalizada para que la entrada del archivo pueda coincidir con los otros botones. Los colores de los bordes siguen el sistema de colores adaptables establecido:
--_border-radius: .5ch;
--_border-light: hsl(210 14% 89%);
--_border-dark: var(--_bg-dark);
--_border: var(--_border-light);
Efecto de resaltado del botón al colocar el cursor sobre un botón
Estas propiedades establecen una propiedad de tamaño para la transición en la interacción y el color de resaltado sigue el sistema de colores adaptables. Más adelante en esta publicación, veremos cómo interactúan estos elementos, pero, en última instancia, se usan para un efecto box-shadow
:
--_highlight-size: 0;
--_highlight-light: hsl(210 10% 71% / 25%);
--_highlight-dark: hsl(210 10% 5% / 25%);
--_highlight: var(--_highlight-light);
Sombra del texto del botón
Cada botón tiene un estilo de sombra de texto sutil. Esto ayuda a que el texto se ubique sobre el botón, lo que mejora la legibilidad y agrega una buena capa de pulido de la presentación.
--_ink-shadow-light: 0 1px 0 var(--_border-light);
--_ink-shadow-dark: 0 1px 0 hsl(210 11% 15%);
--_ink-shadow: var(--_ink-shadow-light);
Ícono de botón
Los íconos tienen el tamaño de dos caracteres gracias a la unidad ch
de longitud relativa nuevamente, lo que ayudará a que el ícono se escale proporcionalmente al texto del botón. El color del ícono se basa en el --_accent-color
para obtener un color adaptable y dentro del tema.
--_icon-size: 2ch;
--_icon-color: var(--_accent);
Sombra del botón
Para que las sombras se adapten correctamente a la luz y la oscuridad, deben cambiar su color y opacidad. Las sombras del tema claro son mejores cuando son sutiles y se ajustan al color de superficie con el que se superponen. Las sombras del tema oscuro deben ser más oscuras y saturadas para que puedan superponerse a los colores de superficie más oscuros.
--_shadow-color-light: 220 3% 15%;
--_shadow-color-dark: 220 40% 2%;
--_shadow-color: var(--_shadow-color-light);
--_shadow-strength-light: 1%;
--_shadow-strength-dark: 25%;
--_shadow-strength: var(--_shadow-strength-light);
Con las intensidades y los colores adaptables, puedo armar dos profundidades de sombras:
--_shadow-1: 0 1px 2px -1px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 9%));
--_shadow-2:
0 3px 5px -2px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 3%)),
0 7px 14px -5px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 5%));
Además, para darles a los botones una apariencia ligeramente 3D, una sombra de cuadro 1px
crea la ilusión:
--_shadow-depth-light: 0 1px var(--_border-light);
--_shadow-depth-dark: 0 1px var(--_bg-dark);
--_shadow-depth: var(--_shadow-depth-light);
Transiciones de botones
Siguiendo el patrón de los colores adaptables, creo dos propiedades estáticas para contener las opciones del sistema de diseño:
--_transition-motion-reduce: ;
--_transition-motion-ok:
box-shadow 145ms ease,
outline-offset 145ms ease
;
--_transition: var(--_transition-motion-reduce);
Todas las propiedades juntas en el selector
:where( button, input[type="button"], input[type="submit"], input[type="reset"], input[type="file"] ), :where(input[type="file"])::file-selector-button { --_accent-light: hsl(210 100% 40%); --_accent-dark: hsl(210 50% 70%); --_accent: var(--_accent-light);--_text-light: hsl(210 10% 30%); --_text-dark: hsl(210 5% 95%); --_text: var(--_text-light);
--_bg-light: hsl(0 0% 100%); --_bg-dark: hsl(210 9% 31%); --_bg: var(--_bg-light);
--_input-well-light: hsl(210 16% 87%); --_input-well-dark: hsl(204 10% 10%); --_input-well: var(--_input-well-light);
--_padding-inline: 1.75ch; --_padding-block: .75ch;
--_border-radius: .5ch; --_border-light: hsl(210 14% 89%); --_border-dark: var(--_bg-dark); --_border: var(--_border-light);
--_highlight-size: 0; --_highlight-light: hsl(210 10% 71% / 25%); --_highlight-dark: hsl(210 10% 5% / 25%); --_highlight: var(--_highlight-light);
--_ink-shadow-light: 0 1px 0 hsl(210 14% 89%); --_ink-shadow-dark: 0 1px 0 hsl(210 11% 15%); --_ink-shadow: var(--_ink-shadow-light);
--_icon-size: 2ch; --_icon-color-light: var(--_accent-light); --_icon-color-dark: var(--_accent-dark); --_icon-color: var(--accent, var(--_icon-color-light));
--_shadow-color-light: 220 3% 15%; --_shadow-color-dark: 220 40% 2%; --_shadow-color: var(--_shadow-color-light); --_shadow-strength-light: 1%; --_shadow-strength-dark: 25%; --_shadow-strength: var(--_shadow-strength-light); --_shadow-1: 0 1px 2px -1px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 9%)); --_shadow-2: 0 3px 5px -2px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 3%)), 0 7px 14px -5px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 5%)) ;
--_shadow-depth-light: hsl(210 14% 89%); --_shadow-depth-dark: var(--_bg-dark); --_shadow-depth: var(--_shadow-depth-light);
--_transition-motion-reduce: ; --_transition-motion-ok: box-shadow 145ms ease, outline-offset 145ms ease ; --_transition: var(--_transition-motion-reduce); }
Adaptaciones con temas oscuros
El valor de los patrones de los objetos estáticos -light
y -dark
queda claro cuando se configuran los props del tema oscuro:
@media (prefers-color-scheme: dark) {
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"],
input[type="file"]
),
:where(input[type="file"])::file-selector-button {
--_bg: var(--_bg-dark);
--_text: var(--_text-dark);
--_border: var(--_border-dark);
--_accent: var(--_accent-dark);
--_highlight: var(--_highlight-dark);
--_input-well: var(--_input-well-dark);
--_ink-shadow: var(--_ink-shadow-dark);
--_shadow-depth: var(--_shadow-depth-dark);
--_shadow-color: var(--_shadow-color-dark);
--_shadow-strength: var(--_shadow-strength-dark);
}
}
Esto no solo es legible, sino que los consumidores de estos botones personalizados pueden usar los objetos básicos con la confianza de que se adaptarán de forma adecuada a las preferencias del usuario.
Adaptaciones de movimiento reducidas
Si el movimiento está bien con el usuario visitante, asigna --_transition
a var(--_transition-motion-ok)
:
@media (prefers-reduced-motion: no-preference) {
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"],
input[type="file"]
),
:where(input[type="file"])::file-selector-button {
--_transition: var(--_transition-motion-ok);
}
}
Algunos estilos compartidos
Las fuentes de los botones y las entradas deben estar configuradas en inherit
para que coincidan con el resto de las fuentes de la página. De lo contrario, el navegador les dará estilo. Esto también se aplica a letter-spacing
. Si configuras line-height
en 1.5
, se establece el tamaño del cuadro de letras para que el texto tenga espacio arriba y abajo:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"],
input[type="file"]
),
:where(input[type="file"])::file-selector-button {
/* …CSS variables */
font: inherit;
letter-spacing: inherit;
line-height: 1.5;
border-radius: var(--_border-radius);
}
Cómo aplicar estilo a los botones
Ajuste del selector
El selector input[type="file"]
no es la parte del botón de la entrada, sino el seudoelemento ::file-selector-button
, por lo que quité input[type="file"]
de la lista:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"],
input[type="file"]
),
:where(input[type="file"])::file-selector-button {
}
Ajustes táctiles y del cursor
Primero, diseño el cursor según el estilo pointer
, lo que ayuda al botón a indicar a los usuarios del mouse que es interactivo. Luego, agrego touch-action: manipulation
para que los clics no necesiten esperar y observar un posible clic doble, lo que hace que los botones parezcan más rápidos:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
cursor: pointer;
touch-action: manipulation;
}
Colores y bordes
A continuación, personalizo el tamaño de la fuente, el fondo, el texto y los colores del borde con algunas de las propiedades personalizadas adaptables establecidas antes:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
…
font-size: var(--_size, 1rem);
font-weight: 700;
background: var(--_bg);
color: var(--_text);
border: 2px solid var(--_border);
}
Sombras
Los botones tienen algunas técnicas geniales. El objeto text-shadow
se adapta a la luz y a la oscuridad, lo que crea una apariencia agradable y sutil del texto del botón que se ubica muy bien sobre el fondo. Para el box-shadow
, se asignan tres sombras. La primera, --_shadow-2
, es una sombra de cuadro normal.
La segunda sombra es un truco para el ojo que hace que el botón parezca estar un poco biselado. La última sombra es para el elemento destacado que se coloca cuando se coloca el cursor, inicialmente en un tamaño de 0, pero se le dará un tamaño más tarde y se hará una transición para que parezca crecer desde el botón.
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
…
box-shadow:
var(--_shadow-2),
var(--_shadow-depth),
0 0 0 var(--_highlight-size) var(--_highlight)
;
text-shadow: var(--_ink-shadow);
}
Diseño
Le di al botón un diseño flexbox, en particular, un diseño inline-flex
que se ajusta a su contenido. Luego, centré el texto y alineo los elementos secundarios de forma vertical y horizontal en el centro. Esto ayudará a que los íconos y otros
elementos de los botones se alineen correctamente.
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
…
display: inline-flex;
justify-content: center;
align-items: center;
text-align: center;
}
Espaciado
En cuanto al espaciado de los botones, usé gap
para evitar que los elementos del mismo nivel toquen y propiedades lógicas para el padding, de modo que el espaciado de botones funcione en todos los diseños de texto.
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
…
gap: 1ch;
padding-block: var(--_padding-block);
padding-inline: var(--_padding-inline);
}
UX del panel táctil y del mouse
La siguiente sección está destinada principalmente a usuarios táctiles en dispositivos móviles. La primera propiedad, user-select
, es para todos los usuarios y evita que se destaque el texto del botón. Esto se puede notar mayormente en dispositivos táctiles cuando se presiona y se mantiene presionado un botón, y el sistema operativo destaca el texto del botón.
En general, descubrí que esta no es la experiencia del usuario con los botones de las apps integradas, así que la inhabilito estableciendo user-select
en ninguno. Los colores de resaltado de elementos presionados (-webkit-tap-highlight-color
) y los menús contextuales del sistema operativo (-webkit-touch-callout
) son otras funciones de botones centradas en la Web que no están alineadas con las expectativas generales del usuario sobre los botones, por lo que también los quito.
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
…
user-select: none;
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
}
Transiciones
La variable adaptable --_transition
se asigna a la propiedad de transición:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
…
transition: var(--_transition);
}
Cuando el usuario coloque el cursor sobre un elemento, mientras el usuario no esté presionando de forma activa, ajusta el tamaño de la sombra que se destaca para darle una buena apariencia de enfoque que parezca crecer desde el botón:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
):where(:not(:active):hover) {
--_highlight-size: .5rem;
}
Al enfocar, aumenta el desplazamiento del contorno del enfoque desde el botón, lo que también da una apariencia de enfoque agradable que parezca crecer desde el botón:
:where(button, input):where(:not(:active)):focus-visible {
outline-offset: 5px;
}
Íconos
Para controlar íconos, el selector tiene agregado un selector :where()
para elementos SVG directos o elementos con el atributo personalizado data-icon
. El tamaño del ícono se establece con la propiedad personalizada mediante propiedades lógicas intercaladas y de bloque. Se establecen el color del trazo y un elemento drop-shadow
para que coincida con el elemento text-shadow
. flex-shrink
se configura como 0
, por lo que el ícono nunca se aprieta. Por último, selecciono los íconos con líneas y asigno esos estilos aquí con los vértices de línea y las uniones de líneas fill: none
y round
:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
) > :where(svg, [data-icon]) {
block-size: var(--_icon-size);
inline-size: var(--_icon-size);
stroke: var(--_icon-color);
filter: drop-shadow(var(--_ink-shadow));
flex-shrink: 0;
fill: none;
stroke-linecap: round;
stroke-linejoin: round;
}
Personalización de los botones de envío
Quería enviar botones para que tuvieran un aspecto ligeramente promovido, y logré que el color del texto de los botones fuera el color de los elementos destacados:
:where(
[type="submit"],
form button:not([type],[disabled])
) {
--_text: var(--_accent);
}
Personalizar los botones de restablecimiento
Quería que los botones de restablecimiento tuvieran algunas señales de advertencia integradas para alertar a los usuarios sobre su comportamiento potencialmente destructivo. También elegí diseñar el botón de Tema claro con más detalles en rojo que el Tema oscuro. Para realizar la personalización, cambia el color subyacente claro u oscuro, y el botón actualizará el diseño:
:where([type="reset"]) {
--_border-light: hsl(0 100% 83%);
--_highlight-light: hsl(0 100% 89% / 20%);
--_text-light: hsl(0 80% 50%);
--_text-dark: hsl(0 100% 89%);
}
También pensé que sería bueno que el color del contorno del foco coincidiera con el acento de rojo. El color del texto adapta un rojo oscuro a un rojo claro. Hago que el color del contorno coincida con esto con la palabra clave currentColor
:
:where([type="reset"]):focus-visible {
outline-color: currentColor;
}
Personalizar botones inhabilitados
Es muy común que los botones inhabilitados tengan un contraste de color deficiente durante el intento de atenuar el botón inhabilitado para que parezca menos activo. Probé cada conjunto de colores y me aseguré de que fueran correctos, lo que sugirió el valor de luminosidad de HSL hasta que la puntuación se pasara en Herramientas para desarrolladores o VisBug.
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
)[disabled] {
--_bg: none;
--_text-light: hsl(210 7% 40%);
--_text-dark: hsl(210 11% 71%);
cursor: not-allowed;
box-shadow: var(--_shadow-1);
}
Cómo personalizar los botones de entrada de archivos
El botón de entrada de archivos es un contenedor de un intervalo y un botón. CSS puede diseñar un poco el contenedor de entrada y el botón anidado, pero no el intervalo. El contenedor recibe max-inline-size
para que no se expanda de lo necesario, mientras que inline-size: 100%
permite reducirse y ajustarse a contenedores más pequeños de lo que es. El color de fondo se establece en un color adaptable más oscuro que otras superficies, por lo que se ve detrás del botón del selector de archivos.
:where(input[type="file"]) {
inline-size: 100%;
max-inline-size: max-content;
background-color: var(--_input-well);
}
El botón del selector de archivos y los botones de tipo de entrada se proporcionan específicamente appearance: none
para quitar los estilos proporcionados por el navegador que no se reemplazaron por los otros estilos de botones.
:where(input[type="button"]),
:where(input[type="file"])::file-selector-button {
appearance: none;
}
Por último, se agrega margen al inline-end
del botón para alejar el texto del intervalo del botón, lo que crea un poco de espacio.
:where(input[type="file"])::file-selector-button {
margin-inline-end: var(--_padding-inline);
}
Excepciones especiales al tema oscuro
Le di a los botones de acción principales un fondo más oscuro para que el texto contraste más, lo que les da un aspecto un poco más promovido.
@media (prefers-color-scheme: dark) {
:where(
[type="submit"],
[type="reset"],
[disabled],
form button:not([type="button"])
) {
--_bg: var(--_input-well);
}
}
Crea variantes
Por diversión, y debido a que es práctico, elegí mostrar cómo crear algunas variantes. Una variante es muy vibrante, similar a la apariencia de los botones principales. Otra variante es grande. La última variante tiene un ícono lleno de gradientes.
Botón vibrante
Para lograr este estilo de botón, sobrescribí los objetos básicos directamente con colores azules. Si bien fue rápido y fácil, quita los accesorios adaptables y se ve igual en los temas claro y oscuro.
.btn-custom {
--_bg: linear-gradient(hsl(228 94% 67%), hsl(228 81% 59%));
--_border: hsl(228 89% 63%);
--_text: hsl(228 89% 100%);
--_ink-shadow: 0 1px 0 hsl(228 57% 50%);
--_highlight: hsl(228 94% 67% / 20%);
}
Botón grande
Este estilo de botón se logra modificando la propiedad personalizada --_size
.
El padding y otros elementos del espacio están relacionados con este tamaño y se ajustan de manera proporcional al tamaño nuevo.
.btn-large {
--_size: 1.5rem;
}
Botón de ícono
Este efecto de ícono no tiene nada que ver con nuestros diseños de botón, pero muestra cómo lograrlo con solo algunas propiedades de CSS y qué tan bien el botón controla los íconos que no son SVG intercalados.
[data-icon="cloud"] {
--icon-cloud: url("https://api.iconify.design/mdi:apple-icloud.svg") center / contain no-repeat;
-webkit-mask: var(--icon-cloud);
mask: var(--icon-cloud);
background: linear-gradient(to bottom, var(--_accent-dark), var(--_accent-light));
}
Conclusión
Ahora que sabes cómo lo hice, ¿cómo lo harías 🙂
Diversifiquemos nuestros enfoques y aprendamos todas las formas de desarrollar en la Web.
Crea una demostración, twittea vínculos y la agregaré a la sección de remixes de la comunidad a continuación.
Remixes de la comunidad
Aún no hay nada que ver aquí.
Recursos
- Código fuente en GitHub