Live Components : JavaScript, moi non plus
Avec les Live Components, Symfony transforme PHP en super-héros du front : réactif, typé, et sans une ligne de JavaScript.
Les liens externes, c’est comme les inconnus dans une soirée : on a toujours un peu peur de cliquer dessus, c'est pour ça que j'ai ajouté le favicon du site devant les liens.
J'aime soigner les petits détails qui rendent la lecture plus fluide et agréable. Récemment, je me suis attaqué à un micro-détail qui change tout : afficher automatiquement le favicon des sites externes devant chaque lien. L’idée ? Permettre aux lecteurs d’identifier visuellement la source d’un lien avant même de cliquer. C’est simple, élégant… et ça améliore vraiment l’expérience utilisateur.
L’objectif était clair :
Tout se passe dans mon MarkdownProcessor
, le service qui convertit le contenu Markdown en HTML. J’y ai ajouté une méthode dédiée : addFaviconsToExternalLinks()
.
private function addFaviconsToExternalLinks(string $html): string
{
$pattern = '/<a\s+href="(https?:\/\/([^\/\s"]+)[^"]*)"([^>]*)>([^<]*)<\/a>/i';
return preg_replace_callback($pattern, function (array $matches): string {
$fullUrl = $matches[1];
$domain = $matches[2];
$attributes = $matches[3];
$linkText = $matches[4];
*// Sécurisation automatique*
if (!str_contains($attributes, 'target=')) {
$attributes .= ' target="_blank"';
}
if (!str_contains($attributes, 'rel=')) {
$attributes .= ' rel="noreferrer nofollow"';
}
$attributes .= ' class="link"';
*// Génération du favicon via DuckDuckGo*
$faviconUrl = "https://icons.duckduckgo.com/ip3/{$domain}.ico";
$faviconImg = "<img src=\"{$faviconUrl}\" alt=\"\" class=\"favicon-img\" loading=\"lazy\">";
return "<a href=\"{$fullUrl}\"{$attributes}>{$faviconImg}<span class=\"link-text\">{$linkText}</span></a>";
}, $html) ?? $html;
}
Pourquoi cette approche ?
target="_blank"
et rel="noreferrer nofollow"
.<span>
pour un contrôle CSS précis.L’enjeu côté front : aligner parfaitement l’icône et le texte, sans casser le flux du paragraphe. Voici le CSS final :
.content .favicon-img {
@apply inline-block w-4 h-4;
vertical-align: middle;
flex-shrink: 0;
margin-right: 0.125rem;
transform: translateY(-1px);
}
.content a.link {
text-decoration: none;
display: inline;
vertical-align: baseline;
}
.content a.link .link-text {
text-decoration: underline;
text-underline-offset: 2px;
text-decoration-thickness: 1.5px;
text-decoration-skip-ink: auto;
}
.content a.link:hover .link-text {
text-decoration-thickness: 2.5px;
}
Chaque image est chargée avec :
<img src="..." loading="lazy" />
Les favicons ne se chargent que lorsqu’ils apparaissent à l’écran.
DuckDuckGo renvoie les favicons avec un bon cache HTTP. Pas besoin de recharger les mêmes icônes à chaque page.
target="_blank"
+ rel="noreferrer nofollow"
: protection contre le tab nabbing.alt=""
: accessibilité respectée pour les lecteurs d’écran.Il ne reste qu'à améliorer tout ça :
Ce genre de micro-fonctionnalité ne change pas le monde, mais il change la sensation du site. Un simple favicon peut rendre un lien plus lisible, plus crédible, plus agréable.
Et surtout, c’est l’exemple parfait d’un petit détail pensé avec soin — exactement le genre de choses que j’aime peaufiner : Symfony, High Performance PHP Framework for Web Development