Superposer du texte sur une image de fond est très courant : hero de page d’accueil, bannière d’article, carte produit, section d’appel à l’action, couverture WordPress… Le piège, toutefois, consiste à poser du texte blanc sur une belle photo et à croiser les doigts.
Mauvaise nouvelle : les yeux de vos visiteurs ne fonctionnent pas en mode “inspecteur CSS”. Si l’image est claire, chargée ou très contrastée, le texte devient vite illisible.
Bonne nouvelle : une simple couche sombre, appliquée en CSS, règle le problème proprement.
Le principe : ajouter un overlay entre l’image et le texte
Pour rendre un texte lisible sur une image, on ajoute généralement un voile sombre au-dessus de l’image. Ensuite, on place le texte au-dessus de ce voile.
La méthode la plus simple consiste à utiliser plusieurs arrière-plans CSS avec background-image : d’abord un dégradé semi-transparent, puis l’image.
Exemple HTML minimal
<section class="hero-image">
<div class="hero-image__content">
<h1>Voici une planche à voile</h1>
<p>Une image de planche à voile se trouve derrière ce texte.</p>
</div>
</section>Langage du code : HTML, XML (xml)
Le HTML reste volontairement simple. On garde une section, un conteneur de contenu, puis le titre et le texte.
CSS : image de fond avec overlay sombre
.hero-image {
display: grid;
min-height: min(70vh, 42rem);
place-items: center;
padding: clamp(3rem, 8vw, 7rem) 1.5rem;
color: #ffffff;
text-align: center;
background-color: #111827;
background-image:
linear-gradient(
rgb(0 0 0 / 62%),
rgb(0 0 0 / 62%)
),
url("https://images.unsplash.com/photo-1518810370118-0fde40f8b0f3?auto=format&fit=crop&w=1800&q=80");
background-position: center;
background-size: cover;
}
.hero-image__content {
max-width: 48rem;
}
.hero-image h1 {
margin: 0 0 1rem;
font-size: clamp(2.25rem, 6vw, 5rem);
line-height: 1;
}
.hero-image p {
margin: 0;
font-size: clamp(1.125rem, 2vw, 1.375rem);
line-height: 1.6;
}Langage du code : CSS (css)
La première couche de background-image est le dégradé sombre. La deuxième couche est l’image. CSS empile les arrière-plans dans cet ordre : le premier déclaré apparaît au-dessus des suivants.
Autrement dit, le navigateur affiche ici le voile noir semi-transparent au-dessus de la photo, mais sous le texte. C’est propre, performant et sans JavaScript.
Pourquoi utiliser un dégradé au lieu d’une vraie image noire ?
Parce que le dégradé CSS ne déclenche aucune requête HTTP supplémentaire. Le navigateur le génère directement. Vous évitez donc une image décorative inutile.
Un projet WordPress en tête ?
Vous avez une idée claire de ce que vous voulez, mais pas les ressources en interne pour le faire bien. Je développe des sites et extensions WordPress sur-mesure — sans délais à rallonge ni mauvaises surprises.
Décrivez-moi votre projet →De plus, vous pouvez ajuster l’opacité très facilement. Par exemple, rgb(0 0 0 / 45%) assombrit peu l’image, tandis que rgb(0 0 0 / 75%) donne un rendu beaucoup plus contrasté.
Le secret réside dans l’image en filigrane noir qui se trouve au dessus de l’image, sous notre texte. Lorsque l’on utilise plusieurs propriétés background-image, elles se superposent, avec la première propriété au dessus des autres.
Nous ajoutons également un linear-gradient à notre background-image. Nous utilison la fonction rgba() pour notre déclaration de couleur, avec 0, 0, 0 pour obtenir du noir.
Ensuite nous utilisons 0.6 comment coefficient alpha – c’est-à-dire le coefficient de transparence, plus il est proche de 0 et plus il est transparent, plus il est proche de 1 et plus il est sombre.
Et voilà, vous obtenez un texte lisible superposé sur une image légérement assombrie pour améliorer le contraste.
Variante : assombrir seulement une partie de l’image
Parfois, vous ne voulez pas assombrir toute l’image. Si le texte se trouve à gauche, vous pouvez créer un dégradé latéral.
.hero-image {
background-image:
linear-gradient(
90deg,
rgb(0 0 0 / 78%) 0%,
rgb(0 0 0 / 54%) 42%,
rgb(0 0 0 / 12%) 100%
),
url("image.jpg");
background-position: center;
background-size: cover;
}Langage du code : CSS (css)
Cette variante fonctionne très bien pour les héros éditoriaux, les pages de vente et les bannières où le texte reste aligné à gauche.
Variante moderne : utiliser une couleur de marque
Vous pouvez aussi remplacer le noir par une couleur de marque. Par exemple, un bleu profond donne souvent un rendu plus élégant qu’un simple overlay noir.
.hero-image {
--hero-overlay: rgb(0 68 130 / 64%);
background-image:
linear-gradient(
var(--hero-overlay),
var(--hero-overlay)
),
url("image.jpg");
background-position: center;
background-size: cover;
}Langage du code : CSS (css)
Cette approche reste simple, mais elle facilite les déclinaisons graphiques. Vous pouvez changer la variable CSS sans toucher au reste du bloc.
Variante avec pseudo-élément ::before
Lorsque l’image est un vrai élément <img> et non une image de fond CSS, utilisez plutôt un pseudo-élément.
<section class="media-hero">
<img src="image.jpg" alt="" class="media-hero__image">
<div class="media-hero__content">
<h1>Un titre lisible</h1>
<p>Le texte reste lisible, même sur une photo contrastée.</p>
</div>
</section>Langage du code : JavaScript (javascript)
.media-hero {
position: relative;
display: grid;
min-height: min(70vh, 42rem);
overflow: hidden;
place-items: center;
padding: clamp(3rem, 8vw, 7rem) 1.5rem;
color: #ffffff;
text-align: center;
}
.media-hero::before {
position: absolute;
inset: 0;
z-index: 1;
background: rgb(0 0 0 / 62%);
content: "";
pointer-events: none;
}
.media-hero__image {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.media-hero__content {
position: relative;
z-index: 2;
max-width: 48rem;
}Langage du code : CSS (css)
Cette méthode est idéale quand vous voulez conserver une vraie image HTML, notamment pour mieux gérer le chargement, les attributs alt, le responsive ou le fetchpriority sur une image critique.
Et avec un bloc Cover WordPress ?
Dans WordPress, le bloc Cover gère déjà une partie de ce travail. Vous pouvez définir une image, ajouter du texte, puis régler l’opacité de l’overlay depuis l’éditeur.
Si vous avez besoin d’un style global plus précis, vous pouvez cibler les blocs Cover avec une classe personnalisée.
.wp-block-cover.is-style-readable-cover::before {
background-color: rgb(0 0 0 / 62%);
}
.wp-block-cover.is-style-readable-cover .wp-block-cover__inner-container {
max-width: 48rem;
}Langage du code : CSS (css)
Ensuite, ajoutez la classe is-style-readable-cover dans les réglages avancés du bloc Cover.
Pour un site WordPress, c’est souvent la solution la plus maintenable : vous laissez Gutenberg gérer la structure, puis vous ajoutez une couche CSS légère.
Contraste : le détail qui change tout
Un overlay joli ne suffit pas. Le texte doit rester lisible sur toute la zone où il apparaît.
Pour du texte courant, visez un contraste d’au moins 4,5:1. Pour du grand texte, le minimum recommandé descend à 3:1. Dans la pratique, soyez plus généreux, surtout sur mobile.
Une photo peut paraître sombre sur votre écran, puis devenir illisible sur un téléphone en plein soleil. Le CSS, lui, ne connaît pas la terrasse du café.
Checklist avant publication
- Le texte reste lisible sur desktop et mobile.
- L’overlay n’écrase pas complètement l’image.
- Le titre ne dépasse pas sur les petits écrans.
- L’image utilise
background-size: coverouobject-fit: cover. - La zone dispose d’un
background-colorde secours. - Le contraste reste suffisant sur les parties claires de l’image.
- L’image est optimisée en WebP ou AVIF si votre site le permet.
Exemple complet réutilisable
Voici une version complète, propre et réutilisable pour une section hero.
<section class="readable-hero">
<div class="readable-hero__inner">
<p class="readable-hero__eyebrow">CSS moderne</p>
<h1>Superposer du texte lisible sur une image</h1>
<p>Un overlay bien dosé améliore le contraste sans sacrifier l’image.</p>
</div>
</section>Langage du code : HTML, XML (xml)
.readable-hero {
--overlay-opacity: 68%;
display: grid;
min-height: min(72vh, 44rem);
place-items: center;
padding: clamp(3.5rem, 8vw, 8rem) 1.5rem;
color: #ffffff;
text-align: center;
background-color: #111827;
background-image:
linear-gradient(
rgb(0 0 0 / var(--overlay-opacity)),
rgb(0 0 0 / var(--overlay-opacity))
),
url("image.jpg");
background-position: center;
background-size: cover;
}
.readable-hero__inner {
max-width: 52rem;
}
.readable-hero__eyebrow {
margin: 0 0 0.75rem;
font-size: 0.875rem;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.readable-hero h1 {
margin: 0 0 1rem;
font-size: clamp(2.25rem, 7vw, 5.5rem);
line-height: 0.95;
text-wrap: balance;
}
.readable-hero p {
margin: 0;
font-size: clamp(1.125rem, 2vw, 1.375rem);
line-height: 1.65;
text-wrap: pretty;
}Langage du code : CSS (css)
Vous pouvez ensuite ajuster seulement --overlay-opacity. Pour une image claire, montez vers 72%. Pour une image déjà sombre, descendez vers 45%.
Conclusion
Pour superposer du texte lisible sur une image de fond, la meilleure solution reste souvent la plus simple : une image, un dégradé semi-transparent, puis du texte bien dimensionné.
La règle à retenir : ne faites jamais dépendre la lisibilité d’une photo. Ajoutez une couche de contraste, testez sur mobile, puis ajustez l’opacité. Votre design restera propre, et vos visiteurs n’auront pas besoin de plisser les yeux comme devant une facture EDF.
Sources et documentation
- MDN — background-image
- MDN — linear-gradient()
- MDN — background-size
- MDN — background-position
- W3C — WCAG 1.4.3 Contrast minimum
Il est souvent utile de pouvoir placer du texte sur une image de fond, de manière à ce que l’on puisse lire le texte facilement et distinguer l’image. C’est ce que j’utilise sur le blog pour les images d’illustration des articles.
Nous allons donc superposer du texte lisible sur une image de fond en utilisant uniquement du code HTML et CSS, ce qui nous donne ceci:
Vous souhaitez accomplir la même chose? Voici comment faire.
Marre des agences qui sous-traitent ?
Avec moi, vous parlez directement au développeur qui fait le travail. Pas d'intermédiaire, pas de promesses creuses. Juste du code propre et un interlocuteur joignable.
Travaillons directement ensemble →