Classic - toutes les polices, un large support
La solution la plus portable et la plus agréable à l'œil serait d'utiliser text-shadow
(h/t to <a href="https://stackoverflow.com/a/14978871/519360">Réponse de Thorgeir </a>con <a href="https://stackoverflow.com/q/5687035/519360#comment69586072_14978871">Commentaire de atorscho </a>) combinée avec -webkit-text-stroke-width
(lorsque disponible. h/t to <a href="https://stackoverflow.com/a/50511696/519360">Réponse d'Oliver </a>) .
li:hover { text-shadow: -0.06ex 0 0 currentColor, 0.06ex 0 0 currentColor; }
@supports (-webkit-text-stroke-width: 0.04ex) { /* 2017+, mobile 2022+ */
li:hover { text-shadow: -0.03ex 0 0 currentColor, 0.03ex 0 0 currentColor;
-webkit-text-stroke-width: 0.04ex; }
}
Cela permet de placer de minuscules "ombres" dans la couleur actuelle de votre police de part et d'autre de chaque caractère en utilisant des unités qui s'échelonneront correctement avec le rendu de la police. S'il y a support du navigateur En revanche, l'ombre est réduite de moitié et nous augmentons la largeur des traits utilisés pour dessiner le texte. L'effet est un peu plus net, car les ombres sont floues sans rayon de flou et les traits sont flous à des niveaux plus élevés (voir la démo ci-dessous).
Avertissement : alors que px
prennent en charge les valeurs décimales, elles ne seront pas très esthétiques lorsque la taille de la police change (par exemple, si l'utilisateur modifie l'affichage à l'aide de la fonction Ctrl + + ). Utilisez plutôt des valeurs relatives.
Cette réponse utilise des fractions de ex
puisqu'elles s'adaptent à la taille de la police.
Dans la plupart des navigateurs par défaut * attendez 1ex
≈ 8px
et donc 0.025ex
≈ 0.1px
.
Moderne - polices variables
Il y a maintenant quelques nouveaux polices variables capable de changer qualité de la police via font-variation-settings
. Vous avez besoin des deux support du navigateur (bon depuis 2018) et dans la police spécifique que vous utilisez (ce qui est encore rare).
@import url("https://fonts.googleapis.com/css2?family=Roboto+Flex:opsz,wght,GRAD@8..144,400,45;8..144,400,50;8..144,1000,0&family=Roboto+Serif:opsz,GRAD@8..144,71&display=swap");
li { font-family:Roboto Flex, sans-serif; }
/* Grade: Increase the typeface's relative weight/density */
@supports (font-variation-settings: 'GRAD' 150) {
li:hover { font-variation-settings: 'GRAD' 150; }
}
/* Text Shadow: Failover for pre-2018 browsers */
@supports not (font-variation-settings: 'GRAD' 150) {
li:hover { text-shadow: -0.06ex 0 0 currentColor, 0.06ex 0 0 currentColor; }
}
Elle charge une police variable puis, dans les navigateurs qui prennent en charge les paramètres de ces polices, demande au navigateur d'afficher cette police avec une note en gras lorsqu'elle est survolée. La solution classique (sans traits puisque ceux-ci sont aussi récents que la prise en charge des polices variables) est fournie comme solution de secours pour les navigateurs plus anciens, mais comme il y a une prise en charge plutôt universelle de la gradation des polices depuis 2018, cela ne devrait plus être nécessaire.
Pour être complet (puisque cela affecte la largeur rendue), les polices variables prennent également en charge les graisses analogiques (gras), ce qui contraste avec les graisses prédéfinies de font-weight
. Quelle que soit la méthode utilisée, vous êtes tributaire de la granularité de votre police. Alors que les polices variables qui prennent en charge la méthode wght
La plupart des polices de caractères n'ont pas de variation en gras ou n'en ont qu'une seule. Les systèmes qui ont besoin de rendre une police en gras le feront eux-mêmes si nécessaire, mais seulement avec une seule graisse ( détails et exemples ici ). Certaines polices non variables offrent plusieurs poids, comme Roboto utilisé dans la démo ci-dessous. Jouez avec le curseur dans la démo pour voir la différence de granularité.
Démonstration de six méthodes
(Ne vous laissez pas décourager par le gros bloc de code, qui sert principalement à mettre en œuvre le curseur interactif et à comparer toutes les méthodes proposées dans les réponses à cette question).
@import url("https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900");
@import url("https://fonts.googleapis.com/css2?family=Roboto+Flex:opsz,wght,GRAD@8..144,400,45;8..144,400,50;8..144,1000,0&family=Roboto+Serif:opsz,GRAD@8..144,71&display=swap");
body { font-family: 'Roboto'; }
.v { font-family: 'Roboto Flex'; } /* variable! */
/* For parity w/ shadow, weight is 400+ (not 100+) & grade is 0+ (not -200+) */
li:hover { text-shadow: initial !important; font-weight: normal !important;
-webkit-text-stroke-width: 0 !important; }
.weight { font-weight: calc(var(--bold) * 500 + 400); }
.shadow, .grade { text-shadow: calc(var(--bold) * -0.06ex) 0 0 currentColor,
calc(var(--bold) * 0.06ex) 0 0 currentColor; }
ul[style*="--bold: 0;"] li { text-shadow:none; } /* none < zero */
.stroke { -webkit-text-stroke-width: calc(var(--bold) * 0.08ex); }
.strokshd { -webkit-text-stroke-width: calc(var(--bold) * 0.04ex);
text-shadow: calc(var(--bold) * -0.03ex) 0 0 currentColor,
calc(var(--bold) * 0.03ex) 0 0 currentColor; }
.after span { display:inline-block; font-weight: bold; } /* @SlavaEremenko */
.after:hover span { font-weight:normal; }
.after span::after { content: attr(title); font-weight: bold;
display: block; height: 0; overflow: hidden; }
.ltrsp { letter-spacing:0px; font-weight:bold; } /* @Reactgular */
.ltrsp:hover { letter-spacing:1px; }
@supports (font-variation-settings: 'GRAD' 150) { /* variable font support */
:hover { font-variation-settings: 'GRAD' 0 !important; }
.weight.v { font-weight: none !important;
font-variation-settings: 'wght' calc(var(--bold) * 500 + 400); }
.grade { text-shadow: none !important;
font-variation-settings: 'GRAD' calc(var(--bold) * 150); }
}
Boldness: <input type="range" value="0.5" min="0" max="1.5" step="0.01"
style="height: 1ex;"
onmousemove="document.getElementById('dynamic').style
.setProperty('--bold', this.value)">
<ul style="--bold: 0.5; margin:0;" id="dynamic">
<li class="" >MmmIii123 This tests regular weight/grade/shadow</li>
<li class="weight" >MmmIii123 This tests the slider (weight)</li>
<li class="weight v">MmmIii123 This tests the slider (weight, variable)</li>
<li class="grade v" >MmmIii123 This tests the slider (grade, variable)</li>
<li class="shadow" >MmmIii123 This tests the slider (shadow)</li>
<li class="stroke" >MmmIii123 This tests the slider (stroke)</li>
<li class="strokshd">MmmIii123 This tests the slider (50/50 stroke/shadow)</li>
<li class="after"><span title="MmmIii123 This tests [title]"
>MmmIii123 This tests [title]</span> (@SlavaEremenko)</li>
<li class="ltrsp" >MmmIii123 This tests ltrsp (@Reactgular)</li>
</ul>
Survolez les lignes rendues pour voir en quoi elles diffèrent du texte standard. (Cela inverse l'intention de la question de mettre en gras le texte survolé afin de pouvoir comparer plus facilement les différentes méthodes). Déplacez le curseur d'audace (pour les entrées contrôlées par le curseur) ou modifiez le niveau de zoom de votre navigateur ( Ctrl + + et Ctrl + - ) pour voir comment ils varient.
Notez que le poids (non variable) s'ajuste en quatre étapes discrètes alors que le poids variable est continu.
J'ai ajouté deux autres solutions à titre de comparaison : L'astuce de @Reactgular pour l'espacement des lettres qui ne fonctionne pas très bien puisqu'elle implique de deviner les plages de largeur de la police, et Le site de @SlavaEremenko ::after
astuce de dessin ce qui laisse un espace supplémentaire gênant pour que le texte en gras puisse s'étendre sans gêner les éléments de texte voisins (j'ai placé l'attribution après le texte en gras pour que vous puissiez voir qu'il ne bouge pas).