Cómo compilar un componente de botón

Una descripción general fundamental de cómo compilar componentes de <button> adaptables, responsivos y accesibles

En esta publicación, quiero compartir mis pensamientos sobre cómo crear un diseño adaptable, elemento <button> responsivo, accesible y responsivo. Prueba la demostración y mira la fuente

. Se puede interactuar con los botones a través del teclado y el mouse en los temas claro y oscuro.

Si prefieres ver un video, aquí tienes una versión de YouTube de esta publicación:

Descripción general

Navegadores compatibles

  • Chrome: 1.
  • Límite: 12.
  • Firefox: 1.
  • Safari: 1.

Origen

El <button> está diseñado para la interacción del usuario. Su evento click se activa desde el teclado. mouse, táctil, voz y más, con reglas inteligentes sobre su tiempos. También incluye con algunos estilos predeterminados en cada navegador, para que puedas usarlos directamente sin cualquier personalización. Usa color-scheme para habilitar esta opción. en botones claros y oscuros proporcionados por el navegador.

También hay diferentes tipos de botones, en la incorporación anterior de Codepen. Una <button> sin un tipo hará lo siguiente: se adapta a un <form> y cambia 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 GUI de este mes, cada botón tendrá estilos que ayudarán a diferenciar visualmente su intención. Restablecer botones tendrá colores de advertencia, ya que son destructivos, y envía botones recibirán un texto de acento azul, de modo que parezca un poco más promocionado que el normal. botones.

Vista previa del conjunto final de todos los tipos de botones, que se muestra en un formato y no en forma, con buenas incorporaciones para botones de íconos y botones personalizados.
Vista previa del conjunto final de todos los tipos de botones, que se muestra en un formulario y no en un formulario, con buenas incorporaciones para botones de íconos y botones personalizados
.

Los botones también tienen pseudoclases. para que CSS lo use para definir el estilo. Estas clases proporcionan hooks CSS para personalizar la apariencia del botón: :hover para cuando un mouse está sobre el botón, :active para cuando se activa un mouse o el teclado está presionando y :focus o :focus-visible para ayudar con el diseño de la 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.
Vista previa del conjunto final de todos los tipos de botones en el tema oscuro

Marca

Además de los tipos de botones que proporciona la especificación HTML, agregué un botón con un ícono y un botón 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 las pruebas, cada botón se coloca dentro de un formulario. De esta manera, puedo asegurarme los estilos se actualizan adecuadamente para el botón predeterminado, que se comporta como en el botón Enviar. También cambio la estrategia de íconos, de SVG intercalado a un SVG enmascarado, para garantizar que ambas funcionen igual de bien.

<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>

En este punto, la matriz de combinaciones es bastante abrumadora. Botón Entre tipos, seudoclases y estar dentro o fuera de un formulario, hay más de 20 combinaciones de botones. Es bueno que CSS nos ayude a articular cada uno de con claridad.

Accesibilidad

Los elementos de los botones son accesibles de forma natural, pero hay algunos mejoras.

Coloca el cursor sobre un elemento y enfócalo a la vez

Me gusta agrupar :hover y :focus junto con la función :is() seudoselector. Esto ayuda a garantizar que mis interfaces siempre consideren el teclado y estilos de tecnología de accesibilidad.

button:is(:hover, :focus) {
  
}
Prueba una demostración.

Anillo de enfoque interactivo

Me gusta animar el anillo de enfoque para los usuarios de teclado y tecnología de accesibilidad. me lograr esto alejando el contorno del botón 5 px, pero solo cuando el botón no está activo. De esta manera, se crea un efecto que hace que el anillo de enfoque se reducirá al tamaño del botón cuando lo presiones.

:where(button, input):where(:not(:active)):focus-visible {
  outline-offset: 5px;
}

Cómo garantizar el contraste de color de paso

Hay al menos cuatro combinaciones de colores diferentes entre claro y oscuro que se debe tener en cuenta el contraste de color: botón, botón de envío, botón de restablecimiento y inhabilitado. VisBug se usa aquí para inspeccionarán y muestren todas sus puntuaciones a la vez:

Ocultar iconos de las personas que no pueden ver

Al crear un botón de icono, este debe proporcionar soporte visual al texto del botón. Esto también significa que el ícono no es valioso para alguien que ve pérdida de reputación y de talento. Afortunadamente, el navegador proporciona una forma de ocultar elementos del lector de pantalla tecnología para que las personas con pérdida de visión no se molesten con botones decorativos imágenes:

<button>
  <svg … aria-hidden="true">...</svg>
  Icon Button
</button>
Se muestra el árbol de accesibilidad del botón para las Herramientas para desarrolladores de Chrome. El árbol ignora la imagen del botón porque aria-hidden está configurado como verdadero.
Se muestra el árbol de accesibilidad del botón para las Herramientas para desarrolladores de Chrome. El árbol ignora la imagen del botón porque aria-hidden está configurado como verdadero

Estilos

En esta sección, primero estableceré un sistema de propiedades personalizadas para administrar los estilos adaptables del botón. Con esas propiedades personalizadas, seleccionar elementos y personalizar su apariencia.

Una estrategia de propiedades personalizadas adaptables

La estrategia de propiedad personalizada que se utiliza en este desafío de la GUI es muy similar a la siguiente: que se usa para crear un esquema de colores. Para en un sistema de colores claro y oscuro adaptable, se crea una propiedad personalizada para cada tema definidos y nombrados según corresponda. Luego, se usa una sola propiedad personalizada valor actual del tema y se asigna a una propiedad de CSS. Luego, el sencillo propiedad personalizada se puede actualizar a un valor diferente y, luego, se actualiza el botón estilo.

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. El la indirección y la abstracción se descargan en la propiedad personalizada --_bg que ahora es la única solución "reactiva" propiedad; --_bg-light y --_bg-dark son estática. También es claro que el tema claro es el predeterminado y el modo oscuro solo se aplica de manera condicional.

Prepárate para lograr la coherencia en el diseño

El selector compartido

El siguiente selector se utiliza para apuntar a todos los diferentes tipos de botones y se un poco abrumador al principio. :where() es por lo que la personalización del botón no requiere especificidad. Los botones suelen ser adaptado para situaciones alternativas y el selector :where() garantiza que esa tarea es sencillo. Dentro de :where(), se selecciona cada tipo de botón, incluido el ::file-selector-button, que no pueden usado dentro de :is() o :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 tendrán alcance dentro de este selector. Tiempo de revisión todas las propiedades personalizadas. Aquí se usan varias propiedades personalizadas . Describiré cada grupo sobre la marcha, luego compartiré la oscuridad y de movimiento al final de la sección.

Color de los elementos destacados del botón

Los botones y los íconos de envío son el lugar ideal para dar 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 blancos ni negros; son versiones oscuras o claras. de --_accent que usan hsl() y con el 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 botones siguen el mismo patrón de hsl(), excepto por el tema claro. botones, que están establecidos en blanco, de modo que su superficie los haga parecer cerca de la usuario o frente a otras plataformas:

--_bg-light: hsl(0 0% 100%);
--_bg-dark: hsl(210 9% 31%);
--_bg: var(--_bg-light);

Bien el fondo del botón

Este color de fondo hace que una superficie aparezca detrás de otras superficies, ú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 en el botón se realiza con ch unidad, una longitud relativa al tamaño de la fuente. Esto es crítico cuando son grandes los botones pueden simplemente aumentar el font-size y las escalas de los botones proporcionalmente:

--_padding-inline: 1.75ch;
--_padding-block: .75ch;

Borde del botón

El radio del borde del botón se guarda en una propiedad personalizada para que se pueda coincide con los demás botones. Los colores de los bordes siguen el color adaptable establecido sistema:

--_border-radius: .5ch;

--_border-light: hsl(210 14% 89%);
--_border-dark: var(--_bg-dark);
--_border: var(--_border-light);

Efecto de resaltar el botón cuando se coloca el cursor

Estas propiedades establecen una propiedad de tamaño para la transición durante la interacción. el color de resaltado sigue el sistema de colores adaptables. Veremos cómo estas interactuar más adelante en esta publicación, pero finalmente se usan para un box-shadow efecto:

--_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 encima el botón, lo que mejora la legibilidad y agrega una buena capa de pulido a 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 otra vez, lo que ayudará a que el icono se ajuste proporcionalmente al texto del botón. El El color del ícono se basa en el --_accent-color para un diseño adaptable y dentro del tema. color.

--_icon-size: 2ch;
--_icon-color: var(--_accent);

Sombra del botón

Para que las sombras se adapten correctamente a la luz y a la oscuridad, deben cambiar su el color y la opacidad. Las sombras de los temas de luz son mejores cuando son sutiles y tonos hacia el color de superficie que se superponen. Las sombras del tema oscuro deben ser más oscuras y más saturados para que puedan superponerse a 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 intensidades y 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 dar a los botones una apariencia ligeramente en 3D, se aplica 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 contiene 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

Todas las propiedades personalizadas de un 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); }

Los botones predeterminados se muestran en los temas claro y oscuro uno al lado del otro.

Adaptaciones del tema oscuro

El valor del patrón de objetos estáticos -light y -dark queda claro cuando se configuraron los accesorios 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);
  }
}

No solo se lee bien, sino que los usuarios de estos botones personalizados pueden usar desnudos y con la confianza de que se adaptarán adecuadamente a las preferencias del usuario.

Adaptaciones de movimiento reducidos

Si el movimiento es adecuado para 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

Los botones y las entradas deben tener las fuentes configuradas en inherit para que coincidan con el el resto de las fuentes de la página; de lo contrario, serán personalizadas según el navegador. Esto también se aplica a letter-spacing. Si estableces line-height en 1.5, se activará el cuadro de texto. para darle al texto un poco de espacio por encima y por debajo:

: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);
}

Captura de pantalla en la que se muestran los botones después de aplicar los estilos anteriores.

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, el el seudoelemento ::file-selector-button es, así 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, cambio el estilo del cursor al estilo pointer, que ayuda al botón a indicar a los usuarios de mouse que es interactivo. Luego agrego touch-action: manipulation a en lugar de hacer clics, no es necesario esperar y observar un posible doble clic, lo que hace que botones para que parezca más rápido:

: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

Luego, personalizo el tamaño de fuente, el fondo, el texto y los colores de los bordes, de las propiedades personalizadas adaptables establecidas anteriormente:

: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);
}

Captura de pantalla en la que se muestran los botones después de aplicar los estilos anteriores.

Sombras

Se aplican algunas técnicas excelentes a los botones. El text-shadow es adaptable a la luz y la oscuridad, lo que crea una apariencia sutil y agradable del botón sobre el fondo. Para el box-shadow: se asignan tres sombras. El primero, --_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 biselada. La última sombra es para destacar al colocar el cursor sobre un elemento, inicialmente en un tamaño de 0, pero se le dará otro más adelante y se lo cambiará para que aparezca para crecer con 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);
}

Captura de pantalla en la que se muestran los botones después de aplicar los estilos anteriores.

Diseño

Le di al botón un diseño de flexbox, En particular, un diseño inline-flex que se ajustará a su contenido. Luego centré el texto, y alinear los elementos secundarios de forma vertical y horizontal center. Esto ayudará a los íconos y otros para que los elementos del botón 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;
}

Captura de pantalla en la que se muestran los botones después de aplicar los estilos anteriores.

Espaciado

Para el espaciado entre botones, usé gap para mantener a los hermanos desde el tacto y Properties para el padding. el espaciado funciona para 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);
}

Captura de pantalla en la que se muestran los botones después de aplicar los estilos anteriores.

UX del tacto y el mouse

La siguiente sección está destinada principalmente a los usuarios táctiles en dispositivos móviles. La primera propiedad, user-select: es para todos los usuarios. evita que el texto destaque el texto del botón. Esto es principalmente son visibles en los dispositivos táctiles cuando se presiona y se mantiene presionado un botón y el sistema sistema destaca el texto del botón.

En general, noté que esta no es la experiencia del usuario con botones integrados apps, así que la inhabilito configurando user-select en "none". Presiona los colores de resaltado. (-webkit-tap-highlight-color) y los menús contextuales del sistema operativo (-webkit-touch-callout) hay otras funciones de botones muy centradas en la Web que no están alineadas con las las expectativas de los usuarios, por lo que también las 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 al Propiedad Transition:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  

  transition: var(--_transition);
}

Cuando se coloca el cursor sobre un elemento, mientras el usuario no presiona activamente, ajusta el resaltado de la sombra. para darle una linda apariencia enfocada que parece crecer :

: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 le da un linda apariencia enfocada que parece crecer desde el botón:

:where(button, input):where(:not(:active)):focus-visible {
  outline-offset: 5px;
}

Íconos

Para administrar íconos, el selector tiene un selector :where() agregado para SVG directo. elementos secundarios o con el atributo personalizado data-icon Se establece el tamaño del ícono con la propiedad personalizada mediante propiedades lógicas intercaladas y de bloqueo. Color del trazo se configura, así como un drop-shadow para que coincida con el text-shadow. flex-shrink se establece en 0, por lo que el ícono nunca se vuelve. aplastados. Por último, selecciono iconos alineados y asigno esos estilos aquí con Límites de línea fill: none y round, y uniones de líneas:

: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;
}

Captura de pantalla en la que se muestran los botones después de aplicar los estilos anteriores.

Personaliza los botones de envío

Quería enviar botones para que tuvieran una apariencia levemente promocionada y logré haciendo que el color del texto de los botones sea el color de énfasis:

:where(
  [type="submit"], 
  form button:not([type],[disabled])
) {
  --_text: var(--_accent);
}

Captura de pantalla en la que se muestran los botones después de aplicar los estilos anteriores.

Personaliza los botones de restablecimiento

Quería que los botones tuvieran algunas señales de advertencia integradas para alertar a los usuarios sobre su comportamiento potencialmente destructivo. También elegí darle estilo al tema claro con más detalles en rojo que el tema oscuro. La personalización se realiza cambia el color subyacente claro u oscuro adecuado, y el botón actualiza 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 el color del contorno debe coincidir con la palabra clave currentColor:

:where([type="reset"]):focus-visible {
  outline-color: currentColor;
}

Captura de pantalla en la que se muestran los botones después de aplicar los estilos anteriores.

Personalizar botones inhabilitados

Es muy común que los botones inhabilitados tengan un contraste de color deficiente durante la intenta suprimir el botón inhabilitado para que parezca menos activo. Probé cada uno color establecido y se aseguró de que pasaron, lo que indica el valor de luminosidad de HSL hasta que que se pasa 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);
}

Captura de pantalla en la que se muestran los botones después de aplicar los estilos anteriores.

Cómo personalizar los botones de entrada de archivos

El botón de entrada de archivos es el contenedor de un intervalo y un botón. CSS puede definir un poco el estilo del contenedor de entrada, así como del botón anidado, pero no el intervalo. Se le da max-inline-size al contenedor para que no crezca más de debe hacerlo, mientras que inline-size: 100% permitirá reducirse y ajustarse contenedores más pequeños de lo que es. El color de fondo se establece en un color adaptable. más oscuro que otras, 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 hayan reemplazados por los otros estilos de botones.

:where(input[type="button"]),
:where(input[type="file"])::file-selector-button {
  appearance: none;
}

Por último, se agrega el margen al inline-end del botón para enviar el texto del intervalo. lejos del botón, creando algo de espacio.

:where(input[type="file"])::file-selector-button {
  margin-inline-end: var(--_padding-inline);
}

Captura de pantalla en la que se muestran los botones después de aplicar los estilos anteriores.

Excepciones especiales del tema oscuro

Otorgué un fondo más oscuro a los botones de acción principales para lograr un mayor contraste. texto, lo que le da una apariencia ligeramente más promocionada.

@media (prefers-color-scheme: dark) {
  :where(
    [type="submit"],
    [type="reset"],
    [disabled],
    form button:not([type="button"])
  ) {
    --_bg: var(--_input-well);
  }
}

Captura de pantalla en la que se muestran los botones después de aplicar los estilos anteriores.

Cómo crear variantes

Por diversión, y porque es práctico, elegí mostrar cómo crear varios variantes. Una variante es muy llamativa, de manera similar a lo que suelen hacer los botones principales estilo. Otra variante es grande. La última variante tiene un ícono lleno de gradientes.

Botón vibrante

Para lograr este estilo de botón, sobrescribí la utilería de la base directamente con azul colores. Aunque esto fue rápido y fácil, quita los objetos y el aspecto adaptables 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%);
}

El botón personalizado se muestra en color claro y oscuro. Es de color azul muy intenso, como suelen tener los botones de acción principal.

Botón grande

Este estilo de botón se logra modificando la propiedad personalizada --_size. El relleno y otros elementos del espacio son relativos a este tamaño y escalan junto proporcionalmente con el tamaño nuevo.

.btn-large {
  --_size: 1.5rem;
}

El botón grande se muestra junto al botón personalizado, unas 150 veces más grande.

Botón de ícono

Este efecto de ícono no tiene nada que ver con nuestros estilos de botones, pero sí aprenderás a lograrlo con solo algunas propiedades de CSS y qué tan bien maneja í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));
}

Se muestra un botón con un ícono en Temas claro y oscuro.

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.

Crear una demostración, twittearme vínculos y la agregaré. a la sección de remixes de la comunidad.

Remixes de la comunidad

Aún no hay nada para ver aquí.

Recursos