Conjuguez les verbes entre parenthèses au passé composé.
Underline Focus
Un champ réduit à une ligne : au clic, un trait dégradé indigo-magenta part du milieu et file vers les deux bords pendant que le libellé monte au-dessus.
Mis à jour le
Cet effet est gratuit — la catégorie Formulaires en contient 20 au total, dont 2 gratuits. Effect.Labs regroupe 840 effets vanilla. Découvrir la catégorie →
Exemples d'usage
- Charte graphique14 éléments3 nov.
- Devis 202632 élémentsHier
- Photos atelier208 éléments28 oct.
- Factures57 éléments12 oct.
Maison Ferbaline · Bistrot
Une table pour ce soir ?
Cuisine du marché, 28 couverts. Service de 19 h à 22 h, du mardi au samedi.
Plus de 8 personnes ? Appelez-nous.
Comment ça marche
Le champ .udl-input n'a ni fond ni cadre, seulement un filet bas de 2 px en rgba(255, 255, 255, .2). Juste derrière lui dans le <label class="udl-field"> viennent le texte .udl-label puis un <span class="udl-line"> vide, placé en absolu sur ce filet : il démarre à left: 50% avec une largeur nulle.
Quand le champ prend le focus, .udl-input:focus ~ .udl-line fait passer le trait à left: 0 et width: 100%. Les deux valeurs changent ensemble en 0,4 s avec la courbe cubic-bezier(.4, 0, .2, 1) : le dégradé #6366f1 → #d946ef semble naître au centre et s'ouvrir des deux côtés. Au départ du focus, la même transition le referme vers le milieu.
Le libellé suit une autre règle. Il est posé à hauteur du texte (top: 30px) et monte à top: 2px, en 0.75rem indigo, dès que :focus ou :not(:placeholder-shown) s'applique ; le placeholder=" " invisible sert uniquement à savoir si le champ contient quelque chose. Un champ rempli garde donc son libellé en haut alors que le trait coloré est déjà reparti.
Le padding-top: 18px de .udl-field réserve la place du libellé remonté : empilés dans un formulaire, deux champs ne se chevauchent pas. La racine .fx-0282-root (fond sombre, 250 px de haut minimum) sert seulement à la démonstration.
Accessibilité
- Libellé réel : le
<label>enveloppe le champ, « Nom complet » est donc son nom accessible, sansidà dédoublonner quand la page en contient plusieurs. - Attributs de formulaire :
name="name"etautocomplete="name"sont fournis ; le navigateur propose le nom enregistré et la valeur part avec le formulaire. - Repérer le champ actif : le trait coloré n'existe que pendant le focus. Un champ rempli mais quitté retrouve le filet gris, ce qui le distingue du champ en cours.
- Mouvement réduit : sous
prefers-reduced-motion: reduce, ni le trait ni le libellé ne glissent ; ils apparaissent directement à leur place finale. - Contraste : au repos,
#8b8b93surrgb(26, 26, 36)atteint 5,1:1 ; le libellé remonté, en#818cf8à 12 px, atteint 5,8:1. Mesuré dans Chromium, Firefox et WebKit, au repos, au focus et rempli.
Compatibilité navigateur
Utilise :placeholder-shown (Chrome 47, Firefox 51, Safari 9), le sélecteur de frère ~, un dégradé linéaire et des variables CSS (Chrome 49, Firefox 31, Safari 9.1). Contrôlé dans Chromium, Firefox et WebKit : deux champs côte à côte qui s'animent chacun de leur côté, Tab, toucher, envoi dans un formulaire, 390 px de large, mouvement réduit.
Sans transitions, le trait et le libellé sautent d'un état à l'autre, le champ reste utilisable. Sans :placeholder-shown, le libellé redescend sur le texte saisi quand on quitte le champ.
Le code
Copiez les deux blocs (HTML et CSS) dans votre page. Aucun JavaScript, aucune dépendance.
<div class="fx-0282-root">
<label class="udl-field">
<input class="udl-input" type="text" name="name" autocomplete="name" placeholder=" ">
<span class="udl-label">Nom complet</span>
<span class="udl-line" aria-hidden="true"></span>
</label>
</div>
.fx-0282-root,
.fx-0282-root *,
.fx-0282-root *::before,
.fx-0282-root *::after {
box-sizing: border-box
}
.fx-0282-root {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
min-height: 250px;
padding: 24px 16px;
position: relative;
background: rgb(26, 26, 36);
color: rgb(255, 255, 255);
font-family: sans-serif;
}
.udl-field {
position: relative;
display: block;
width: var(--udl-width, 280px);
max-width: 100%;
padding-top: 18px;
}
.udl-input {
width: 100%;
padding: 12px 0;
font-size: 1rem;
font-family: inherit;
background: transparent;
border: none;
border-bottom: 2px solid rgba(255, 255, 255, 0.2);
color: white;
outline: none;
}
.udl-line {
position: absolute;
bottom: 0;
left: 50%;
width: 0;
height: 2px;
background: linear-gradient(90deg, #6366f1, #d946ef);
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.udl-input:focus ~ .udl-line {
left: 0;
width: 100%;
}
.udl-label {
position: absolute;
left: 0;
top: 30px;
color: var(--udl-muted, #8b8b93);
pointer-events: none;
transition: all 0.3s ease;
}
.udl-input:focus + .udl-label,
.udl-input:not(:placeholder-shown) + .udl-label {
top: 2px;
font-size: 0.75rem;
color: #818cf8;
}
@media (prefers-reduced-motion: reduce) {
.udl-line,
.udl-label {
transition: none;
}
}
CSS pur — aucun JavaScript requis.
Personnaliser
Options passées à l'API ou attributs data-* :
| Option / propriété | Défaut | Effet |
|---|---|---|
Largeur (CSS — --udl-width) |
280 px | 100% pour suivre la colonne, une valeur courte (100 à 140 px) pour un champ glissé dans une phrase. Le champ ne dépasse jamais son conteneur (max-width: 100%). |
Dégradé du trait (CSS — background de .udl-line) |
linear-gradient(90deg, #6366f1, #d946ef) |
Une couleur unie fonctionne aussi. Gardez une teinte nettement plus vive que le filet gris pour que le champ actif se voie. |
Épaisseur (CSS — height de .udl-line et border-bottom de .udl-input) |
2 px | Changez les deux valeurs ensemble : le trait recouvre exactement le filet du bas. |
Vitesse d'ouverture (CSS — transition de .udl-line) |
0,4 s | Le libellé, lui, se déplace en 0,3 s. Un trait un peu plus lent que le libellé donne l'impression que la ligne « suit » la montée du texte. |
Couleur du libellé au repos (CSS — --udl-muted) |
#8b8b93 |
Le libellé remonté garde #818cf8, écrit en dur dans la règle :focus + .udl-label. |
Place réservée au-dessus (CSS — padding-top de .udl-field) |
18 px | Si vous agrandissez le libellé remonté, augmentez cette marge et le top du libellé au repos (30 px) d'autant. |
FAQ
Pourquoi le trait part-il du centre et pas de la gauche ?
Parce que deux propriétés changent à la fois : left passe de 50 % à 0 pendant que width passe de 0 à 100 %. Pour un trait qui part de la gauche, laissez left: 0 au repos et ne faites varier que la largeur.
Le champ fonctionne-t-il sur fond clair ?
Le texte saisi est blanc et le filet est un blanc transparent : sur fond clair, passez color de .udl-input en sombre et le filet en rgba(0, 0, 0, .2). Le dégradé indigo-magenta reste lisible tel quel.
Peut-on mettre un champ au milieu d'une phrase ?
Oui : donnez à .udl-field un display: inline-block et une largeur courte via --udl-width. La ligne du texte s'agrandit pour loger l'espace réservé au libellé ; prévoyez un interligne d'environ 1,9.