Présentation de base de la création d'un composant de paramètres composé de curseurs et de cases à cocher.
Dans ce message, je vais vous expliquer comment créer un composant "Paramètres" pour Web réactif, compatible avec plusieurs entrées d'appareils et fonctionnant sur des navigateurs. Essayez la démonstration.
<ph type="x-smartling-placeholder">Si vous préférez la vidéo, ou si vous voulez un aperçu de l'UI ou de l'expérience utilisateur, voici un tutoriel plus court sur YouTube:
Présentation
Les différents aspects de ce composant sont répartis dans les sections suivantes:
- Mises en page
- Couleur
- Saisie d'une plage personnalisée
- Saisie par case à cocher personnalisée
- Considérations relatives à l'accessibilité
- JavaScript
Mises en page
Il s'agit de la première démo du défi IUG à utiliser toutes les grilles CSS. Voici chaque grille avec les Outils pour les développeurs Chrome pour la grille encadrés:
Juste pour l'écart
La mise en page la plus courante:
foo {
display: grid;
gap: var(--something);
}
J'appelle cette mise en page "juste pour l'écart" car elle n'utilise la grille que pour ajouter des intervalles entre les blocs.
Cinq mises en page utilisent cette stratégie. Voici toutes les mises en page affichées:
L'élément fieldset
, qui contient chaque groupe d'entrées (.fieldset-item
), utilise gap: 1px
pour
créer des bordures de cheveux entre les éléments. Pas de solution compliquée en matière de bordure !
.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); } } }
Enveloppement naturel de la grille
La mise en page la plus complexe a fini par être
la mise en page macro, la disposition logique
entre <main>
et <form>
.
Centrer le contenu d'encapsulation
Flexbox et la grille offrent toutes deux des capacités à align-items
ou
align-content
et, lorsqu'il s'agit d'encapsuler des éléments, la mise en page content
les alignements répartiront l'espace
entre les enfants en tant que groupe.
main {
display: grid;
gap: var(--space-xl);
place-content: center;
}
L'élément principal utilise l'alignement place-content: center
.
raccourci afin de
les enfants sont centrés verticalement et horizontalement,
dans les mises en page à une ou deux colonnes.
Dans la vidéo ci-dessus, découvrez comment le "contenu" reste centrée, même si l'encapsulation a eu lieu.
Répéter l'ajustement automatique minimal
<form>
utilise une mise en page en grille adaptative pour chaque section.
Cette mise en page passe d'une à deux colonnes en fonction de l'espace disponible.
form {
display: grid;
gap: var(--space-xl) var(--space-xxl);
grid-template-columns: repeat(auto-fit, minmax(min(10ch, 100%), 35ch));
align-items: flex-start;
max-width: 89vw;
}
La valeur de cette grille est différente pour row-gap
(--space-xl) et column-gap
(--space-xxl)
pour ajouter une touche
personnalisée à la mise en page responsive. Lorsque les colonnes s'empilent,
veulent un écart important, mais pas
aussi grand que sur un grand écran.
La propriété grid-template-columns
utilise trois fonctions CSS: repeat()
, minmax()
et
min()
Una Kravets possède un excellent blog de mise en page
dans un post à ce sujet, en l'appelant
RAM.
Notre mise en page comporte trois ajouts spéciaux, si vous la comparez à celle d'Una:
- Nous transmettons une fonction
min()
supplémentaire. - Nous spécifions
align-items: flex-start
. - Il existe un style
max-width: 89vw
.
La fonction supplémentaire min()
est bien décrite par Evan Minto sur son blog dans l'article
publier une grille CSS intrinsèquement réactive avec minmax() et
min().
Je vous conseille de le lire. La correction de l'alignement de flex-start
consiste à
supprimez l'effet d'étirement par défaut afin que les enfants de cette mise en page
doivent avoir des hauteurs égales,
elles peuvent avoir des hauteurs naturelles et intrinsèques. La
La vidéo YouTube présente brièvement l'ajout de l'alignement.
max-width: 89vw
mérite d'être détaillé dans ce post.
Voici la mise en page avec et sans le style appliqué:
Que se passe-t-il ? Lorsque max-width
est spécifié, cela fournit du contexte,
un dimensionnement explicite ou défini
taille pour l'attribut auto-fit
l'algorithme de mise en page pour savoir comment
de répétitions qu'il peut tenir dans l'espace. Même s'il semble évident que la
l'espace est en "pleine largeur", conformément aux spécifications de la grille CSS, une taille définie ou une taille maximale doit
fournies. J'ai fourni une valeur max-size.
Pourquoi 89vw
? Parce que « ça a marché » pour ma mise en page.
Avec plusieurs autres utilisateurs de Chrome,
je cherche pourquoi une valeur plus raisonnable,
comme 100vw
n'est pas suffisant, et s'il s'agit bien d'un bug.
Espacement
Une grande partie de l'harmonie de cette mise en page provient d'une palette d'espacement limitée, 7 pour être exact.
:root {
--space-xxs: .25rem;
--space-xs: .5rem;
--space-sm: 1rem;
--space-md: 1.5rem;
--space-lg: 2rem;
--space-xl: 3rem;
--space-xxl: 6rem;
}
Ces flux sont très bien utilisés avec la grille, CSS @nest et la syntaxe de niveau 5.
de @media. Voici un exemple de l'ensemble de styles de mise en page <main>
complet.
main {
display: grid;
gap: var(--space-xl);
place-content: center;
padding: var(--space-sm);
@media (width >= 540px) {
& {
padding: var(--space-lg);
}
}
@media (width >= 800px) {
& {
padding: var(--space-xl);
}
}
}
Grille au contenu centré, légèrement remplie par défaut (comme sur mobile) Toutefois, à mesure que l'espace disponible dans la fenêtre d'affichage augmente, il s'étend en augmentant la marge intérieure. Le CSS 2021 s'est plutôt bien passé !
Vous vous souvenez de la mise en page précédente, « juste pour l'écart » ? Voici une version plus complète de ce à quoi ils ressemblent dans ce composant:
header {
display: grid;
gap: var(--space-xxs);
}
section {
display: grid;
gap: var(--space-md);
}
Couleur
Une utilisation contrôlée de la couleur a permis à ce design de se démarquer de la concurrence minimale. Je fais comme ceci:
:root {
--surface1: lch(10 0 0);
--surface2: lch(15 0 0);
--surface3: lch(20 0 0);
--surface4: lch(25 0 0);
--text1: lch(95 0 0);
--text2: lch(75 0 0);
}
Je nomme les couleurs de ma surface et de mon texte avec des chiffres plutôt que des noms comme
surface-dark
et surface-darker
, car dans une requête média, je vais retourner
et le clair et le noir n'auront pas de sens.
Je les inverse dans une requête média de préférence comme celle-ci:
:root {
...
@media (prefers-color-scheme: light) {
& {
--surface1: lch(90 0 0);
--surface2: lch(100 0 0);
--surface3: lch(98 0 0);
--surface4: lch(85 0 0);
--text1: lch(20 0 0);
--text2: lch(40 0 0);
}
}
}
Il est important d'avoir un aperçu rapide de la stratégie et de la stratégie d'ensemble nous plongerons dans les détails de la syntaxe des couleurs. Mais, comme je me suis un peu dépassé, permettez-moi de revenir un peu en arrière.
LCH?
Sans entrer trop en profondeur dans la théorie des couleurs, LCH est une syntaxe orientée humain, qui s'adapte à la façon dont nous percevons la couleur, et non à la façon dont nous la mesurons avec des mathématiques (comme 255). Cela lui donne un avantage particulier, car les humains peuvent l'écrire plus facilement les humains seront en phase avec ces ajustements.
<ph type="x-smartling-placeholder">Aujourd'hui, dans cette démonstration, concentrons-nous sur la syntaxe et les valeurs pour faire de la lumière et de l'obscurité. Examinons une couleur de surface et une couleur de texte:
:root {
--surface1: lch(10 0 0);
--text1: lch(95 0 0);
@media (prefers-color-scheme: light) {
& {
--surface1: lch(90 0 0);
--text1: lch(40 0 0);
}
}
}
--surface1: lch(10 0 0)
signifie 10%
de luminosité, 0 chrominance et 0 teinte: a
un gris très foncé. Ensuite, dans la requête média pour le mode clair,
est retourné en 90%
avec --surface1: lch(90 0 0);
. Et c'est l'essentiel
stratégie. Commencez par modifier la luminosité entre les deux thèmes, en conservant
rapports de contraste requis par la conception ou ce qui peut maintenir l’accessibilité.
L'avantage avec lch()
, c'est que la légèreté est orientée vers l'humain et que l'on peut
les modifications apportées à %
sont bénéfiques, car elles seront perceptuelles et cohérentes
que %
. hsl()
, par exemple, n'est pas aussi
fiables.
Il y a plus à
en savoir plus
des espaces colorimétriques et lch()
si cela vous intéresse. Ça arrive !
Pour le moment, le CSS ne peut pas du tout accéder à ces couleurs. Je le répète: nous n'avons pas accès à un tiers des couleurs de la plupart des de surveillance. Et il n'y a pas que des couleurs, mais les couleurs les plus vives l'écran peut afficher. Nos sites Web sont égarés en raison de l'évolution du matériel d'écran que les spécifications CSS et les implémentations de navigateurs.
Lea Verou
Commandes de formulaire adaptatives avec jeu de couleurs
De nombreux navigateurs proposent des commandes pour le thème sombre, comme Safari et Chromium pour le moment, spécifier en CSS ou HTML que votre conception les utilise.
Ce qui précède illustre l'effet de la propriété dans le panneau "Styles" de DevTools. La démonstration utilise la balise HTML, qui, à mon avis, est généralement un meilleur emplacement:
<meta name="color-scheme" content="dark light">
Pour en savoir plus, consultez color-scheme
article de Thomas
Steiner. Il y a beaucoup
plus à gagner
que les cases à cocher sombres !
CSS accent-color
Il y a eu récents
activité autour de
accent-color
sur les éléments du formulaire. Il s'agit d'un style CSS unique capable de modifier
teinte utilisée dans l'élément de saisie des navigateurs. Pour en savoir plus, cliquez ici
GitHub Je l'ai inclus dans mon
pour ce composant. Comme les navigateurs le prennent, mes cases à cocher seront
plus sur le thème avec les couleurs
rose et violette.
input[type="checkbox"] {
accent-color: var(--brand);
}
Color pop avec dégradés fixes et mettant l'accent sur l'intérieur
Les couleurs ressortent le plus lorsqu'elles sont utilisées avec parcimonie, et c'est l'une des façons dont j'aime grâce à des interactions colorées dans l'interface utilisateur.
La vidéo ci-dessus comporte de nombreuses couches de commentaires et d'interaction de l'interface utilisateur, qui permettent de personnaliser l'interaction en:
- Mettre en avant le contexte
- Fournir des commentaires sur l'interface utilisateur concernant le niveau de remplissage la valeur est comprise dans la plage.
- Indique à l'interface utilisateur qu'un champ accepte des entrées.
Pour envoyer des commentaires lorsqu'un élément fait l'objet d'une interaction, le CSS utilise la méthode
:focus-within
pour modifier l'apparence des différents éléments, analysons
.fieldset-item
, c'est très intéressant:
.fieldset-item {
...
&:focus-within {
background: var(--surface2);
& svg {
fill: white;
}
& picture {
clip-path: circle(50%);
background: var(--brand-bg-gradient) fixed;
}
}
}
Lorsque l'un des enfants de cet élément est sélectionné:
- Une couleur de surface plus contrastée est attribuée à l'arrière-plan
.fieldset-item
. - Le
svg
imbriqué est rempli en blanc pour un contraste plus élevé. - L'élément
clip-path
<picture>
imbriqué se développe pour former un cercle complet et la l'arrière-plan est rempli du dégradé fixe.
Période personnalisée
À partir de l'élément d'entrée HTML suivant, je vais vous montrer comment apparence:
<input type="range">
Cet élément doit être personnalisé en trois parties:
Styles d'élément de plage
input[type="range"] {
/* style setting variables */
--track-height: .5ex;
--track-fill: 0%;
--thumb-size: 3ex;
--thumb-offset: -1.25ex;
--thumb-highlight-size: 0px;
appearance: none; /* clear styles, make way for mine */
display: block;
inline-size: 100%; /* fill container */
margin: 1ex 0; /* ensure thumb isn't colliding with sibling content */
background: transparent; /* bg is in the track */
outline-offset: 5px; /* focus styles have space */
}
Les premières lignes de CSS correspondent aux parties personnalisées des styles, et j'espère que les étiqueter clairement aide. Le reste des styles est principalement des styles réinitialisés, pour fournir une base cohérente pour construire les parties délicates du composant.
Styles de suivi
input[type="range"]::-webkit-slider-runnable-track {
appearance: none; /* clear styles, make way for mine */
block-size: var(--track-height);
border-radius: 5ex;
background:
/* hard stop gradient:
- half transparent (where colorful fill we be)
- half dark track fill
- 1st background image is on top
*/
linear-gradient(
to right,
transparent var(--track-fill),
var(--surface1) 0%
),
/* colorful fill effect, behind track surface fill */
var(--brand-bg-gradient) fixed;
}
L'astuce est de « révéler » la couleur de remplissage éclatante. Pour ce faire, un dégradé d'arrêt fixe sur le dessus. Le dégradé est transparent jusqu'au pourcentage de remplissage, et après qui utilise la couleur de la surface de la piste non remplie. Derrière cette surface inachevée, couleur pleine largeur, en attendant que la transparence la révèle.
Suivre le style de remplissage
Ma conception nécessite JavaScript pour conserver le style de remplissage. Il y Il s'agit de stratégies seulement CSS, mais l'élément "Thumb" doit être de la même hauteur. que le titre, et je n'ai pas réussi à trouver une harmonie dans ces limites.
/* grab sliders on page */
const sliders = document.querySelectorAll('input[type="range"]')
/* take a slider element, return a percentage string for use in CSS */
const rangeToPercent = slider => {
const max = slider.getAttribute('max') || 10;
const percent = slider.value / max * 100;
return `${parseInt(percent)}%`;
};
/* on page load, set the fill amount */
sliders.forEach(slider => {
slider.style.setProperty('--track-fill', rangeToPercent(slider));
/* when a slider changes, update the fill prop */
slider.addEventListener('input', e => {
e.target.style.setProperty('--track-fill', rangeToPercent(e.target));
})
})
Je pense que cela constitue une jolie mise à niveau visuelle. Le curseur fonctionne très bien sans
JavaScript, la propriété --track-fill
n'est pas obligatoire, elle n'aura tout simplement pas
style de remplissage s'il n'est pas présent. Si du code JavaScript est disponible, renseignez la colonne
tout en observant les modifications apportées par les utilisateurs, en synchronisant la propriété personnalisée avec
la valeur.
Voici une excellente
publier sur
CSS-Tricks par Ana
Tudor, qui présente une solution dédiée uniquement aux CSS
le remplissage de la piste. J'ai aussi trouvé ceci
élément range
très inspirant.
Styles de pouce
input[type="range"]::-webkit-slider-thumb {
appearance: none; /* clear styles, make way for mine */
cursor: ew-resize; /* cursor style to support drag direction */
border: 3px solid var(--surface3);
block-size: var(--thumb-size);
inline-size: var(--thumb-size);
margin-top: var(--thumb-offset);
border-radius: 50%;
background: var(--brand-bg-gradient) fixed;
}
La plupart de ces styles servent à créer un joli cercle.
Ici aussi, vous voyez le dégradé d'arrière-plan fixe qui unifie
couleurs dynamiques des vignettes, des pistes et des éléments SVG associés.
J'ai séparé les styles de l'interaction afin d'isoler box-shadow
.
utilisée pour la mise en surbrillance au passage de la souris:
@custom-media --motionOK (prefers-reduced-motion: no-preference);
::-webkit-slider-thumb {
…
/* shadow spread is initally 0 */
box-shadow: 0 0 0 var(--thumb-highlight-size) var(--thumb-highlight-color);
/* if motion is OK, transition the box-shadow change */
@media (--motionOK) {
& {
transition: box-shadow .1s ease;
}
}
/* on hover/active state of parent, increase size prop */
@nest input[type="range"]:is(:hover,:active) & {
--thumb-highlight-size: 10px;
}
}
L'objectif était une mise en évidence visuelle animée et facile à gérer pour les commentaires des utilisateurs. En utilisant une ombre de boîte, je peux éviter de déclencher mise en page. Je fais ça en créant une ombre qui n'est pas floutée et qui correspond à la forme circulaire . Ensuite, je change la taille de la répartition au passage de la souris.
Si seulement l'effet de mise en surbrillance était si facile sur les cases à cocher...
Sélecteurs multinavigateurs
J'ai constaté que j'avais besoin de ces sélecteurs -webkit-
et -moz-
pour obtenir des résultats multi-navigateurs.
cohérence:
input[type="range"] {
&::-webkit-slider-runnable-track {}
&::-moz-range-track {}
&::-webkit-slider-thumb {}
&::-moz-range-thumb {}
}
Case à cocher personnalisée
À partir de l'élément d'entrée HTML suivant, je vais vous montrer comment apparence:
<input type="checkbox">
Cet élément doit être personnalisé en trois parties:
Élément de case à cocher
input[type="checkbox"] {
inline-size: var(--space-sm); /* increase width */
block-size: var(--space-sm); /* increase height */
outline-offset: 5px; /* focus style enhancement */
accent-color: var(--brand); /* tint the input */
position: relative; /* prepare for an absolute pseudo element */
transform-style: preserve-3d; /* create a 3d z-space stacking context */
margin: 0;
cursor: pointer;
}
Les styles transform-style
et position
se préparent au pseudo-élément que nous présenterons plus tard.
pour appliquer un style à la mise en surbrillance. Sinon, il s'agit principalement
des trucs de style avisés mineures de ma part. J'aime que le curseur soit un pointeur, j'aime
décalages de contour, les cases à cocher par défaut sont trop petites et si accent-color
est
compatible, apportez-les
cases à cocher dans
le jeu de couleurs de la marque.
Étiquettes des cases à cocher
Il est important de fournir des libellés pour les cases à cocher pour deux raisons. La première consiste à représenter l'utilisation de la valeur de la case à cocher, pour répondre à la question "Activé ou désactivé pour quoi ?" Deuxièmement, pour l'UX, les utilisateurs Web se sont habitués à interagir avec des cases à cocher par les libellés qui leur sont associés.
<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>
Sur votre libellé, placez un attribut for
qui pointe vers une case à cocher par ID: <label for="text-notifications">
. Dans la case à cocher, doublez le nom et l'ID pour
Vérifiez qu'elle est accessible à l'aide de divers outils et technologies, comme une souris ou un lecteur d'écran:
<input type="checkbox" id="text-notifications" name="text-notifications">
:hover
, :active
et d'autres sont fournis sans frais avec la connexion, ce qui augmente la
et différentes façons d'interagir avec votre formulaire.
Mise en surbrillance de la case à cocher
Je veux que mes interfaces restent cohérentes, et le curseur a une belle
sélection de la miniature à utiliser
avec la case à cocher. La miniature était
capable d'utiliser box-shadow
et sa propriété spread
pour mettre à l'échelle une ombre et
vers le bas. Toutefois, cet effet ne fonctionne pas ici, car les cases à cocher sont, et doivent
être, carré.
J'ai obtenu le même effet visuel avec un pseudo-élément nombre de pages CSS délicates:
@custom-media --motionOK (prefers-reduced-motion: no-preference);
input[type="checkbox"]::before {
--thumb-scale: .01; /* initial scale of highlight */
--thumb-highlight-size: var(--space-xl);
content: "";
inline-size: var(--thumb-highlight-size);
block-size: var(--thumb-highlight-size);
clip-path: circle(50%); /* circle shape */
position: absolute; /* this is why position relative on parent */
top: 50%; /* pop and plop technique (https://web.dev/centering-in-css#5-pop-and-plop) */
left: 50%;
background: var(--thumb-highlight-color);
transform-origin: center center; /* goal is a centered scaling circle */
transform: /* order here matters!! */
translateX(-50%) /* counter balances left: 50% */
translateY(-50%) /* counter balances top: 50% */
translateZ(-1px) /* PUTS IT BEHIND THE CHECKBOX */
scale(var(--thumb-scale)) /* value we toggle for animation */
;
will-change: transform;
@media (--motionOK) { /* transition only if motion is OK */
& {
transition: transform .2s ease;
}
}
}
/* on hover, set scale custom property to "in" state */
input[type="checkbox"]:hover::before {
--thumb-scale: 1;
}
La création d'un pseudo-élément en forme de cercle est simple, mais placez-le derrière l'élément auquel il est attaché était plus difficile. Voici la vidéo précédente et après l'avoir corrigé:
C'est certainement une micro-interaction, mais il est important pour moi de garder l'aspect visuel
la cohérence. La technique de mise à l'échelle de l'animation est la même que celle que nous avons utilisée
à d'autres endroits. Nous définissons une propriété personnalisée sur une nouvelle valeur et laissons le CSS la transférer
en fonction des préférences de mouvement. La principale caractéristique ici est translateZ(-1px)
. La
a créé un espace 3D. Ce pseudo-élément enfant a utilisé dessus
se replaçant légèrement dans l'espace Z.
Accessibilité
La vidéo YouTube présente parfaitement les fonctionnalités de la souris, du clavier interactions du lecteur d'écran pour ce composant de paramètres. Je vais mentionner certains des plus de détails ici.
Éléments HTML disponibles
<form>
<header>
<fieldset>
<picture>
<label>
<input>
Chacun de ces éléments fournit des conseils et des astuces pour l'outil de navigation de l'utilisateur. Certains éléments des indices d'interaction, de l'interactivité de connexion et d'autres aident à façonner arborescence d'accessibilité consultée par un lecteur d'écran.
Attributs HTML
Nous pouvons masquer des éléments dont les lecteurs d'écran n'ont pas besoin, dans ce cas, l'icône à côté du curseur:
<picture aria-hidden="true">
La vidéo ci-dessus illustre le fonctionnement du lecteur d'écran sous Mac OS. Notez que la méthode d'entrée le curseur passe d'un curseur à l'autre. C'est parce que nous avons masqué l'icône qui a peut-être été un arrêt sur le chemin vers le curseur suivant. Sans cela, , l'utilisateur doit s'arrêter, écouter et passer au-delà de l'image qui ils ne peuvent peut-être pas voir.
Le format SVG est un processus mathématique. Ajoutons un élément <title>
pour permettre un survol sans frais avec la souris.
un titre et un commentaire lisible par l'humain sur ce que crée le calcul:
<svg viewBox="0 0 24 24">
<title>A note icon</title>
<path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/>
</svg>
En dehors de cela, nous avons utilisé suffisamment de code HTML clairement indiqué pour que le formulaire teste très bien avec la souris, le clavier, les manettes de jeu vidéo et les lecteurs d'écran.
JavaScript
J'ai déjà expliqué comment la couleur de remplissage de la piste était gérée à partir de JavaScript.
Examinons maintenant le JavaScript associé à <form>
:
const form = document.querySelector('form');
form.addEventListener('input', event => {
const formData = Object.fromEntries(new FormData(form));
console.table(formData);
})
À chaque interaction avec le formulaire et à chaque modification de celui-ci, la console consigne le formulaire en tant que un objet dans une table pour en faciliter la révision avant de l'envoyer à un serveur.
Conclusion
Maintenant que tu sais comment j'ai fait, comment faire ?! Cela permet de s'amuser une architecture de composants. Qui va créer la 1re version avec des emplacements dans sa votre framework préféré ? 🙂
Diversifiez nos approches et découvrons toutes les manières de créer des applications sur le Web. Créer une démonstration, me envoyer des tweets et je l'ajouterai à la section Remix de la communauté ci-dessous.