Bordures, ombres, coins arrondis et images de bordure — tous les outils pour structurer et embellir vos composants.
Les bordures sont bien plus qu'un simple trait autour d'un élément. Elles constituent un outil polyvalent pour créer des badges, avatars, cartes et boutons avec du style. Combinées aux ombres (box-shadow), elles donnent de la profondeur et du relief à vos composants.
| Propriété | Description | Valeurs principales |
|---|---|---|
border |
Shorthand pour width, style, color | 2px solid #333 |
border-width |
Épaisseur de la bordure | 1px, thin, medium, thick |
border-style |
Style de la bordure | solid, dashed, dotted, double, groove, ridge... |
border-color |
Couleur de la bordure | Tout format de couleur CSS |
border-radius |
Arrondi des coins | 50%, 10px, elliptical values |
outline |
Contour externe (hors box model) | Même syntaxe que border |
outline-offset |
Espace entre bordure et outline | Longueurs, valeurs négatives |
box-shadow |
Ombre portée de la boîte | offset-x offset-y blur spread color |
border-image |
Image comme bordure | url(), linear-gradient() |
border prend de la place dans le modèle de boîte (elle augmente la taille visible). L'outline est un contour externe qui ne affecte pas les dimensions — idéal pour les focus rings d'accessibilité.
/* Propriétés individuelles */
.boite {
border-width: 2px;
border-style: solid;
border-color: #333;
}
/* Shorthand */
.boite {
border: 2px solid #333;
}
/* Bordures individuelles par côté */
.boite {
border-top: 3px solid red;
border-right: 1px dashed blue;
border-bottom: 3px solid red;
border-left: 1px dashed blue;
}
/* Supprimer une bordure spécifique */
.boite {
border-top: none;
border-bottom: 2px solid #333;
}
/* Valeurs absolues */
.boite { border-width: 1px; }
.boite { border-width: 0.5rem; }
/* Mots-clés (rarement utilisés) */
.boite { border-width: thin; } /* ~1px */
.boite { border-width: medium; } /* ~3px (défaut) */
.boite { border-width: thick; } /* ~5px */
/* Côtés individuels */
.boite { border-width: 2px 1px 3px 0.5px; }
.boite { border-style: solid; } /* Ligne pleine */
.boite { border-style: dashed; } /* Tirets */
.boite { border-style: dotted; } /* Pointillés */
.boite { border-style: double; } /* Double ligne */
.boite { border-style: groove; } /* Gravure 3D */
.boite { border-style: ridge; } /* Crête 3D */
.boite { border-style: inset; } /* Enfoncé */
.boite { border-style: outset; } /* En relief */
.boite { border-style: none; } /* Pas de bordure */
.boite { border-style: hidden; } /* Masquée (comportement model différent) */
Démonstration : Les 9 styles de bordure
border-style, la bordure est invisible même si border-width et border-color sont définis.
/* FAUX — invisible ! */
.boite {
border-width: 3px;
border-color: red;
/* border-style n'est pas défini = none par défaut */
}
/* CORRECT */
.boite {
border-width: 3px;
border-style: solid;
border-color: red;
}
/* Tous les coins */
.boite { border-radius: 8px; }
/* Coins individuels (sens horaire : haut-gauche, haut-droit, bas-droit, bas-gauche) */
.boite { border-radius: 10px 20px 30px 40px; }
/* Deux valeurs : coins horizontaux / coins verticaux */
.boite { border-radius: 10px / 20px; }
/* Cercle parfait */
.cercle {
width: 100px;
height: 100px;
border-radius: 50%;
}
/* Ellipse */
.ellipse {
width: 200px;
height: 100px;
border-radius: 50%;
}
/* Coins arrondis par coin spécifique */
.boite {
border-radius: 10px 0 10px 0; /* Coins en losange */
border-radius: 0 10px 0 10px; /* Coins en losange inversé */
}
/* Rayons individuels de chaque coin */
.boite {
border-top-left-radius: 10px;
border-top-right-radius: 20px;
border-bottom-right-radius: 30px;
border-bottom-left-radius: 40px;
}
Démonstration : border-radius
border-radius: 9999px ou border-radius: 50vw. La valeur est si grande que le navigateur arrondit au maximum possible.
/* Syntaxe similaire à border */
.boite:focus {
outline: 3px solid #2563eb;
outline-offset: 4px; /* Espace entre la bordure et le contour */
}
/* Supprimer le focus ring (À ÉVITER pour l'accessibilité !) */
.boite:focus { outline: none; }
/* Focus ring moderne et accessible */
.boite:focus-visible {
outline: 2px solid #2563eb;
outline-offset: 2px;
}
/* outline-offset peut être négatif — contour à l'intérieur */
.boite {
outline: 2px dashed red;
outline-offset: -4px; /* À l'intérieur de la bordure */
}
Comparaison : outline vs border
| Critère | border | outline |
|---|---|---|
| Place dans le modèle | Oui (augmente la taille) | Non |
| Shape | Suit le border-radius | Toujours rectangulaire |
| Côtés individuels | Oui | Non |
| Offset | Non | Oui (outline-offset) |
| Usage principal | Décoration visuelle | Focus ring (accessibilité) |
/* Syntaxe complète */
box-shadow: offset-x offset-y blur-radius spread-radius color;
/* Exemples */
.boite {
/* Ombre basique */
box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.2);
/* Ombre sans décalage (glow) */
box-shadow: 0 0 20px rgba(59, 130, 246, 0.5);
/* Ombre interne */
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
/* Plusieurs ombres (séparées par une virgule) */
box-shadow:
0 1px 3px rgba(0, 0, 0, 0.12),
0 4px 8px rgba(0, 0, 0, 0.08),
0 8px 16px rgba(0, 0, 0, 0.04);
}
/* Supprimer l'ombre */
.boite { box-shadow: none; }
box-shadow: 8px 8px 16px 0px rgba(0,0,0,0.2);
│ │ │ │ │
│ │ │ │ └── color
│ │ │ └── spread-radius (agrandit/réduit l'ombre)
│ │ └── blur-radius (flou de l'ombre)
│ └── offset-y (décalage vertical)
└── offset-x (décalage horizontal)
┌─────────────┐
│ │
│ BOÎTE │╲
│ │ ╲ ← blur (flou)
└─────────────┘──╲
↕ offset-y ← spread (taille)
════════════════ ← offset-x →
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ← ombre
Anatomie d'une box-shadow
Démonstration : box-shadow
filter: drop-shadow() crée une ombre qui suit la forme réelle de l'élément (y compris le border-radius et la transparence), contrairement à box-shadow qui suit toujours un rectangle.
/* box-shadow — suit toujours le rectangle */
.boite-rectangle {
box-shadow: 4px 4px 10px rgba(0,0,0,0.3);
}
/* drop-shadow — suit la forme réelle */
.boite-forme {
filter: drop-shadow(4px 4px 10px rgba(0,0,0,0.3));
}
/* Parfait pour les images PNG avec transparence */
.icon {
filter: drop-shadow(2px 2px 4px rgba(0,0,0,0.3));
}
/* Utile quand le border-radius est important */
.cercle {
border-radius: 50%;
filter: drop-shadow(0 4px 8px rgba(0,0,0,0.2));
/* L'ombre suit le cercle, pas un rectangle */
}
Comparaison : box-shadow vs drop-shadow
/* Avec image */
.boite {
border: 12px solid transparent;
border-image-source: url('border.png');
border-image-slice: 30; /* Taille du slice */
border-image-width: 12px; /* Largeur de la bordure */
border-image-outset: 0; /* Débordement */
border-image-repeat: stretch; /* repeat, round, space, stretch */
}
/* Shorthand */
.boite {
border: 12px solid transparent;
border-image: url('border.png') 30 stretch;
}
/* Avec gradient — effet moderne */
.boite {
border: 3px solid transparent;
border-image: linear-gradient(135deg, #667eea, #764ba2) 1;
}
/* Bordure en escalier */
.boite {
border: 16px solid transparent;
border-image: repeating-linear-gradient(
45deg,
#3b82f6 0px,
#3b82f6 8px,
#93c5fd 8px,
#93c5fd 16px
) 16;
}
Démonstration : border-image
┌─ outline-offset ──────────────────────────────────┐ │ ┌─ OUTLINE ───────────────────────────────────┐ │ │ │ (hors du modèle de boîte) │ │ │ │ ┌─ BORDER ───────────────────────────────┐ │ │ │ │ │ border-width + border-style │ │ │ │ │ │ ┌─ PADDING ────────────────────────┐ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ┌─ CONTENT ──────────────────┐ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ Le contenu │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └────────────────────────────┘ │ │ │ │ │ │ │ └─────────────────────────────────┘ │ │ │ │ │ └───────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────┘ box-shadow (inset ou externe) est rendu AUTOUR de la bordure ┌─ box-shadow spread ────────────────────────────┐ │ ┌─ box-shadow blur ─────────────────────────┐ │ │ │ ┌─ outline ───────────────────────────┐ │ │ │ │ │ ┌─ border ───────────────────────┐ │ │ │ │ │ │ │ ┌─ padding ────────────────┐ │ │ │ │ │ │ │ │ │ ┌─ content ──────────┐ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └────────────────────┘ │ │ │ │ │ │ │ │ │ └──────────────────────────┘ │ │ │ │ │ │ │ └────────────────────────────────┘ │ │ │ │ │ └──────────────────────────────────────┘ │ │ │ └────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────┘
Interaction entre border, outline, et box-shadow
border-radius: 20px 10px 30px 15px;
│ │ │ │
│ │ │ └── bas-gauche (15px)
│ │ └─── bas-droit (30px)
│ └──── haut-droit (10px)
└───── haut-gauche (20px)
╭──── 20px ────╮
╭────┤ ├────╮
│ │ │ │
│ │ CONTENU │ 10px
│ │ │ │
╰────┤ ├────╯
15px ╰──── 30px ────╯
border-radius: 20px / 10px;
→ Rayon horizontal: 20px
→ Rayon vertical: 10px
(Crée des coins elliptiques)
Position des valeurs de border-radius
Ombre externe : Ombre interne (inset) :
┌─────────────┐ ┌─────────────┐
│ │ │ ░░░░░░░░░░░ │ ← inset shadow
│ BOÎTE │╲ │ ░┌───────┐░ │
│ │ ╲ ← blur │ ░│ │░ │
└─────────────┘──╲ │ ░│ ░░░░ │░ │
▓▓▓▓▓ │ ░└───────┘░ │
▓▓▓▓▓ │ ░░░░░░░░░░░ │
▓▓▓▓▓ └─────────────┘
Glow (blur sans offset) : Ombre multi-couche :
╭──────╮ Couche 1: spread faible, flou léger
╭─│ │─╮ Couche 2: spread moyen, flou moyen
╭│ │ BOÎTE│ │╮ Couche 3: spread fort, flou fort
│╰─│ │─╯│ → Crée un effet de profondeur
╰──╰──────╯──╯ → Le plus réaliste
░░░░░░░░░░░░░
░░░░░░░░░░░
Types d'ombres portées
Composant Badge (notification + statut)
/* Badge de notification */
.badge-notification {
position: relative;
display: inline-block;
}
.badge-notification::after {
content: '3';
position: absolute;
top: -6px;
right: -6px;
min-width: 18px;
height: 18px;
padding: 0 5px;
background: #ef4444;
color: white;
font-size: 0.7rem;
font-weight: 700;
border-radius: 9999px;
display: grid;
place-items: center;
border: 2px solid white;
}
/* Badge de statut */
.badge-status {
display: inline-flex;
align-items: center;
gap: 0.375rem;
padding: 0.25rem 0.75rem;
border-radius: 9999px;
font-size: 0.8rem;
font-weight: 600;
}
.badge-success {
background: #dcfce7;
color: #166534;
border: 1px solid #86efac;
}
.badge-warning {
background: #fef3c7;
color: #92400e;
border: 1px solid #fcd34d;
}
.badge-error {
background: #fee2e2;
color: #991b1b;
border: 1px solid #fca5a5;
}
.badge-info {
background: #dbeafe;
color: #1e40af;
border: 1px solid #93c5fd;
}
.badge-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: currentColor;
}
Composant Avatar (avec bordure, ring et indicateur)
/* Avatar de base */
.avatar {
width: 48px;
height: 48px;
border-radius: 50%;
object-fit: cover;
}
/* Avatar avec bordure */
.avatar-bordure {
border: 3px solid #e2e8f0;
}
/* Avatar avec ring (anneau coloré) */
.avatar-ring {
box-shadow: 0 0 0 3px white, 0 0 0 5px #3b82f6;
}
/* Avatar avec indicateur de statut */
.avatar-wrapper {
position: relative;
display: inline-block;
}
.avatar-indicator {
position: absolute;
bottom: 0;
right: 0;
width: 14px;
height: 14px;
border-radius: 50%;
border: 2px solid white;
background: #22c55e;
}
.avatar-indicator.offline { background: #9ca3af; }
.avatar-indicator.busy { background: #ef4444; }
.avatar-indicator.away { background: #f59e0b; }
/* Groupe d'avatars */
.avatar-group {
display: flex;
}
.avatar-group .avatar {
margin-left: -12px;
border: 3px solid white;
}
.avatar-group .avatar:first-child {
margin-left: 0;
}
Composant Carte (avec hover effects)
.carte {
background: white;
border: 1px solid #e2e8f0;
border-radius: 12px;
padding: 1.5rem;
transition: box-shadow 0.3s, transform 0.3s, border-color 0.3s;
}
.carte:hover {
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1);
transform: translateY(-4px);
border-color: #93c5fd;
}
/* Carte avec bordure colorée à gauche */
.carte-border-left {
border-left: 4px solid #3b82f6;
}
/* Carte avec bordure colorée en haut */
.carte-border-top {
border-top: 4px solid #8b5cf6;
}
/* Carte avec ombre interne */
.carte-inset {
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.06);
border: none;
}
/* Image dans la carte */
.carte-img {
width: 100%;
height: 160px;
object-fit: cover;
border-radius: 8px 8px 0 0;
margin: -1.5rem -1.5rem 1rem;
}
Bordure simple avec ombre au survol. Transform translateY pour l'effet de levitation.
Bordure colorée à gauche pour attirer l'attention. Idéal pour les notifications.
Pas de bordure visible, juste une ombre interne subtile pour la profondeur.
Composant Bouton (tous les états)
/* Bouton de base */
.btn {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.625rem 1.25rem;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
border: 2px solid transparent;
}
/* État normal */
.btn-primary {
background: #3b82f6;
color: white;
border-color: #3b82f6;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
/* État hover */
.btn-primary:hover {
background: #2563eb;
border-color: #2563eb;
box-shadow: 0 4px 12px rgba(37, 99, 235, 0.4);
transform: translateY(-1px);
}
/* État active (click) */
.btn-primary:active {
background: #1d4ed8;
border-color: #1d4ed8;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
transform: translateY(0);
}
/* État focus-visible */
.btn-primary:focus-visible {
outline: 2px solid #3b82f6;
outline-offset: 2px;
}
/* Bouton outline */
.btn-outline {
background: transparent;
color: #3b82f6;
border-color: #3b82f6;
}
.btn-outline:hover {
background: #3b82f6;
color: white;
box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);
}
/* Bouton ghost */
.btn-ghost {
background: transparent;
color: #64748b;
border-color: transparent;
}
.btn-ghost:hover {
background: #f1f5f9;
color: #334155;
}
/* Tailles */
.btn-sm { padding: 0.375rem 0.75rem; font-size: 0.8rem; }
.btn-lg { padding: 0.875rem 1.75rem; font-size: 1.1rem; }
/* FAUX — la bordure est invisible */
.boite {
border-width: 3px;
border-color: red;
/* border-style est none par défaut ! */
}
/* CORRECT */
.boite {
border: 3px solid red;
}
/* FAUX — casse l'accessibilité */
.btn:focus {
outline: none;
}
/* CORRECT — garder un focus visible */
.btn:focus-visible {
outline: 2px solid #3b82f6;
outline-offset: 2px;
}
/* FAUX — l'ombre suit le rectangle, pas la forme */
.img-transparente {
background: transparent;
box-shadow: 4px 4px 10px rgba(0,0,0,0.3);
/* L'ombre est rectangulaire malgré le border-radius: 50% */
}
/* CORRECT — utiliser drop-shadow pour les formes */
.img-transparente {
filter: drop-shadow(4px 4px 10px rgba(0,0,0,0.3));
}
/* FAUX — un span est inline, le border-radius ne s'applique pas correctement */
span {
border-radius: 50%;
}
/* CORRECT — convertir en inline-block ou block */
span {
display: inline-block;
width: 50px;
height: 50px;
border-radius: 50%;
}
/* FAUX — ombre trop diffuse, pas de relief */
.boite {
box-shadow: 0 0 30px rgba(0,0,0,0.2);
}
/* CORRECT — combiner offset + blur pour un effet naturel */
.boite {
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
/* FAUX — border-image ignore complètement border-radius */
.boite {
border-radius: 12px;
border-image: url('border.png') 30 stretch;
/* Les coins arrondis sont ignorés ! */
}
/* CORRECT — utiliser un gradient avec background-clip */
.boite {
border-radius: 12px;
background:
linear-gradient(#fff, #fff) padding-box,
linear-gradient(135deg, #667eea, #764ba2) border-box;
border: 3px solid transparent;
}
outline sans fournir une alternative visible.| Situation | Propriété recommandée |
|---|---|
| Bordure visible autour d'un élément | border: Xpx solid color |
| Focus ring d'accessibilité | outline: 2px solid; outline-offset: 2px |
| Ombre de carte | box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1) |
| Ombre d'icône/forme | filter: drop-shadow() |
| Cercle parfait | border-radius: 50% (avec width = height) |
| Bouton pill | border-radius: 9999px |
| Bordure colorée sur un côté | border-left: 4px solid color |
| Ombre interne | box-shadow: inset 0 2px 4px rgba(0,0,0,0.1) |
Exercice 1 : Badge de notification
Crée un icône avec un badge de notification rouge en haut à droite :
Solution :
.icone {
position: relative;
width: 48px;
height: 48px;
background: #f1f5f9;
border-radius: 12px;
display: grid;
place-items: center;
}
.badge {
position: absolute;
top: -6px;
right: -6px;
min-width: 20px;
height: 20px;
background: #ef4444;
color: white;
font-size: 0.75rem;
font-weight: 700;
border-radius: 9999px;
border: 2px solid white;
display: grid;
place-items: center;
padding: 0 4px;
}
Exercice 2 : Avatar avec ring
Crée un avatar circulaire avec un anneau (ring) bleu autour :
Solution :
.avatar-ring {
width: 64px;
height: 64px;
border-radius: 50%;
background: #e2e8f0;
box-shadow:
0 0 0 2px white,
0 0 0 5px #3b82f6;
}
Exercice 3 : Carte avec ombre au survol
Crée une carte qui s'élève au survol avec une ombre progressive :
Solution :
.carte {
background: white;
border: 1px solid #e2e8f0;
border-radius: 12px;
padding: 1.5rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
transition: box-shadow 0.3s, transform 0.3s;
}
.carte:hover {
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
transform: translateY(-4px);
}
Exercice 4 : Bouton outline
Crée un bouton outline qui se remplit au survol :
Solution :
.btn-outline {
padding: 0.5rem 1.25rem;
background: transparent;
color: #3b82f6;
border: 2px solid #3b82f6;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
}
.btn-outline:hover {
background: #3b82f6;
color: white;
box-shadow: 0 4px 12px rgba(37, 99, 235, 0.4);
}
.btn-outline:active {
background: #1d4ed8;
box-shadow: none;
}
Exercice 5 : Texte avec bordure gradient
Crée un bloc avec une bordure qui est un dégradé (en utilisant background-clip) :
Solution :
.gradient-border {
background:
linear-gradient(#fff, #fff) padding-box,
linear-gradient(135deg, #8b5cf6, #3b82f6) border-box;
border: 3px solid transparent;
border-radius: 12px;
padding: 1.5rem;
}
Exercice 6 : Badge statut animé
Crée un badge de statut "en ligne" avec un point vert qui pulse :
Solution :
.statut {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.25rem 0.75rem;
background: #f1f5f9;
color: #475569;
border-radius: 9999px;
font-size: 0.85rem;
font-weight: 500;
}
.statut-point {
width: 8px;
height: 8px;
background: #22c55e;
border-radius: 50%;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
Projet : Composants UI avec bordures et ombres
Crée un fichier index.html et bordures.css qui implémentent une collection de composants UI :
HTML requis :
<header> avec class="en-tete" — titre et sous-titre<main> contenant :<section class="badges"> — 4 badges de statut (success, warning, error, info)<section class="avatars"> — 3 avatars avec ring + indicateur de statut<section class="cartes"> — 3 cartes avec bordures différentes<section class="boutons"> — 3 types de boutons (primary, outline, ghost)<footer>CSS requis :
Objectif : Démontrer la maîtrise des bordures, ombres, border-radius et outline dans la création de composants UI réalistes.
Quiz rapide
border et outline ?box-shadow avec ses 4 valeurs principales ?filter: drop-shadow() plutôt que box-shadow ?outline: none sans alternative ?border-image avec border-radius ?border-style — sans elle, la bordure est invisible même avec width et color définis.border prend de la place dans le modèle de boîte et suit le border-radius. L'outline est hors du modèle, toujours rectangulaire, avec outline-offset.border-radius: 50% (avec width = height pour un carré).box-shadow: offset-x offset-y blur-radius spread-radius colorborder-radius: 9999px (valeur si grande que le navigateur arrondit au max).background avec deux couches : linear-gradient(#fff, #fff) padding-box et linear-gradient(gradient) border-box avec border: 3px solid transparent.outline-offsetborder-radius est ignoré — border-image dessine toujours un rectangle.