


Nouer le contraste parfait entre le texte léger et une image d'arrière-plan
Avez-vous déjà rencontré du texte léger sur un site Web superposé à une image d'arrière-plan légère? Si vous l'avez rencontré, vous saurez à quel point il est difficile de lire. Une façon courante d'éviter cela est d'utiliser une superposition transparente. Mais cela soulève une question importante: quelle est la hauteur de la transparence de la superposition? Nous ne traitons pas toujours avec la même taille, épaisseur et couleur, et bien sûr, différentes images produiront également un contraste différent.
Essayez d'éliminer le problème du mauvais contraste de texte sur l'image de fond, tout comme jouer au jeu Goblin. Plutôt que de deviner, utilisez HTML<canvas></canvas>
Et quelques méthodes mathématiques pour résoudre ce problème.
Comme ça:
Nous pouvons dire "le problème est résolu!" puis terminer cet article. Mais quel est le plaisir de cela? Ce que je veux vous montrer, c'est comment cet outil fonctionne afin que vous puissiez maîtriser une nouvelle façon de faire face à ce problème commun.
plan
Tout d'abord, clarifions nos objectifs. Nous avons dit que nous voulons afficher du texte lisible sur l'image d'arrière-plan, mais que signifie exactement "lisible"? Pour nos besoins, nous utiliserons la définition de la lisibilité au niveau de l'AA-AA, qui indique qu'il est nécessaire de contraster suffisamment entre le texte et les couleurs d'arrière-plan afin qu'une couleur soit 4,5 fois plus brillant que l'autre.
Choisissons une couleur de texte, une image d'arrière-plan et une couleur de superposition comme point de départ. Compte tenu de ces entrées, nous voulons trouver un niveau d'opacité de superposition qui rend le texte lisible sans cacher tellement l'image que l'image est difficile à voir. Pour compliquer un peu les choses, nous utiliserons une image qui a à la fois des couleurs sombres et claires, et nous assurer que la superposition en prend en compte.
Notre résultat final sera une valeur que nous pouvons appliquer à la propriété CSS Opacity de la superposition, ce qui rend le texte 4,5 fois plus brillant que l'arrière-plan.
Pour trouver la meilleure opacité de superposition, nous effectuerons quatre étapes:
- Nous mettons l'image dans HTML
<canvas></canvas>
Cela nous permettra de lire la couleur de chaque pixel de l'image. - Nous trouverons les pixels dans l'image qui ont le moins de contraste avec le texte.
- Ensuite, nous préparerons une formule de mélange de couleurs que nous pouvons utiliser pour tester l'effet de différents niveaux d'opacité sur la couleur de ce pixel.
- Enfin, nous allons ajuster l'opacité de la superposition jusqu'à ce que le contraste du texte atteigne l'objectif de lisibilité. Ce ne sera pas deviner aléatoire - nous utiliserons des techniques de recherche binaires pour accélérer ce processus.
Commençons!
Étape 1: Lisez la couleur de l'image de la toile
La toile nous permet de "lire" les couleurs contenues dans l'image. Pour ce faire, nous devons "dessiner" l'image pour<canvas></canvas>
Sur l'élément, utilisez ensuite getImageData()
du contexte Canvas (CTX) pour générer une liste de couleurs d'image.
fonction getImagePixelColorsusingCanvas (image, canvas) { // Le contexte de la toile (généralement abrégé en CTX) est un objet contenant de nombreuses fonctions pour contrôler votre toile const ctx = canvas.getContext ('2d'); // La largeur peut être n'importe quelle valeur, donc j'ai choisi 500 car elle est suffisamment grande pour capturer les détails, mais suffisamment petit pour rendre le calcul plus rapide. canevas.width = 500; // Assurez-vous que Canvas correspond à l'échelle de notre image canvas.height = (image.height / image.width) * canvas.width; // Obtenez les mesures de l'image et du canevas afin que nous puissions les utiliser dans l'étape suivante SourceImageCoORDINATS = [0, 0, Image.Width, Image.Height]; const de destinationCanvasCoOrdines = [0, 0, canvas.width, canvas.height]; // Canvas 'DrawImage () fonctionne en cartographiant les mesures de notre image à la toile que nous voulons la dessiner sur ctx.DrawImage ( image, ... SourceMagecoordonate, ... DestinationCanvasCoOrdine )); // N'oubliez pas que GetImagedata ne fonctionne qu'avec des images avec la même source ou l'origine transversale activée. // https://developer.mozilla.org/en-us/docs/web/html/cors_enabled_image const imagePixelColors = ctx.getImagedata (... DestinationCanvasCoOrdine); return ImagePixElColors; }
getImageData()
nous fournit une liste de nombres représentant la couleur de chaque pixel. Chaque pixel est représenté par quatre nombres: rouge, vert, bleu et opacité (également connu sous le nom de "alpha". Sachant cela, nous pouvons parcourir la liste des pixels et trouver toutes les informations dont nous avons besoin. Ce sera très utile à l'étape suivante.
Étape 2: Trouvez le pixel avec le moins de contraste
Avant cela, nous devons savoir comment calculer le contraste. Nous rédigerons une fonction appelée getContrast()
qui prend deux couleurs et sortira un nombre indiquant le niveau de contraste entre les deux couleurs. Plus les chiffres sont élevés, mieux c'est le contraste et mieux la lisibilité.
Lorsque j'ai commencé à rechercher les couleurs de ce projet, je m'attendais à trouver une formule simple. Il s'est avéré qu'il y avait plusieurs étapes.
Pour calculer le contraste entre deux couleurs, nous devons connaître leur niveau de luminosité, qui est essentiellement la luminosité (Stacie Arellano a un aperçu approfondi de la luminosité, ce qui vaut le coup).
Grâce à W3C, nous connaissons la formule pour calculer le contraste à l'aide de la luminosité:
CONSTAST CONSTAGE = (LighterColorLuminance 0,05) / (Darkercolorluminance 0,05);
Obtenir la luminosité de la couleur signifie que nous devons convertir la couleur de la valeur RVB 8 bits ordinaire utilisée sur le réseau (où chaque couleur est 0-255) en ce qui est appelé RVB linéaire. Nous devons le faire car la luminosité n'augmente pas uniformément avec le changement de couleur. Nous devons convertir la couleur en un format où la luminosité change uniformément avec la couleur. Cela nous permet de calculer correctement la luminosité. De même, W3C fournit une aide ici:
const Luminance = (0,2126 * getLineArrgb (r) 0,7152 * getlineArrgb (g) 0,0722 * getlineArrgb (b));
Mais attendez, il y en a plus! Afin de convertir le RVB 8 bits (0 à 255) en RVB linéaire, nous devons passer par ce qui est appelé RVB standard (également connu sous le nom de SRGB), qui a un rapport de 0 à 1.
Par conséquent, le processus est le suivant:
<code>8位RGB → 标准RGB → 线性RGB → 亮度</code>
Une fois que nous avons la luminosité des deux couleurs que nous voulons comparer, nous pouvons remplacer les valeurs de luminosité dans la formule pour obtenir le contraste entre leurs couleurs respectives.
// getContrast est la seule fonction dont nous avons besoin pour interagir directement. // Les autres fonctions sont des étapes auxiliaires intermédiaires. fonction getContrast (Color1, Color2) { const Color1_Luminance = GetLuminance (Color1); const Color2_Luminance = GetLuminance (Color2); const LighterColorLuminance = Math.max (Color1_Luminance, Color2_Luminance); const darkercolorluminance = math.min (color1_luminance, color2_luminance); CONSTAST CONSTAGE = (LighterColorLuminance 0,05) / (Darkercolorluminance 0,05); Retour contraste; } fonction getluminance ({r, g, b}) { retour (0,2126 * getlineArrgb (r) 0,7152 * getlineArrgb (g) 0,0722 * getLineArrgb (b)); } function getlineArrgb (primorColor_8bit) { // Convertir d'abord de RVB 8 bits (0-255) en RVB standard (0-1) const primairecolor_srgb = convert_8bit_rgb_to_standard_rgb (primairecolor_8bit); // ensuite converti de SRGB en RVB linéaire afin que nous puissions l'utiliser pour calculer la luminosité const primairecolor_rgb_linear = convert_standard_rgb_to_linear_rgb (primorcolor_srgb); return primorColor_rgb_linear; } fonction convert_8bit_rgb_to_standard_rgb (primairecolor_8bit) { return primorColor_8bit / 255; } fonction convert_standard_rgb_to_linear_rgb (primairecolor_srgb) { const primatcolor_linear = primairecolor_srgb <p> Maintenant que nous pouvons calculer le contraste, nous devons regarder l'image à l'étape précédente et itérer à travers chaque pixel pour comparer le contraste entre la couleur de ce pixel et la couleur du texte de premier plan. Lorsque nous traversons les pixels de l'image, nous suivrons le pire contraste (le plus bas) jusqu'à présent, et lorsque nous atteindrons la fin de la boucle, nous connaîtrons la couleur avec le pire contraste de l'image.</p><pre class="brush:php;toolbar:false"> function getworkStContrastColoriNimage (textColor, imagePixelColors) { Laissez le pireContrastColorinimage; Laissez le pire-contraste = infinité; // Cela garantit que nous ne commençons pas par une valeur trop faible pour (que i = 0; i <imagepixelcolors.data.length i="4)" const r="imagePixelColors.data" g="imagePixelColors.data" b="imagePixelColors.data" imagepixelcolor="{r," contrast="getContrast" if pirecontrast="contraste;" pirecontrastcolorinimage="ImagePixelColor;" retourner><p></p> <h3 id="Étape-Préparez-la-formule-de-mélange-de-couleurs-pour-tester-le-niveau-d-opacité-de-superposition"> Étape 3: Préparez la formule de mélange de couleurs pour tester le niveau d'opacité de superposition</h3> <p></p> <p> Maintenant que nous connaissons la couleur avec le pire contraste de notre image, l'étape suivante consiste à déterminer la hauteur de la transparence de la superposition et de voir comment cela changera le contraste avec le texte.</p> <p></p> <p> Lorsque j'ai implémenté cela pour la première fois, j'ai utilisé une toile séparée pour mélanger les couleurs et lire les résultats. Cependant, grâce à l'article d'Ana Tudor sur la transparence, je sais maintenant qu'il existe une formule pratique pour calculer la couleur résultante après avoir mélangé la couleur de base avec la superposition transparente.</p> <p></p> <p> Pour chaque canal de couleur (rouge, vert et bleu), nous appliquerons cette formule pour obtenir les couleurs mélangées:</p> <p> Couleur mélangée = couleur de base (couleur de chevauchement - couleur de base) * Opacité qui se chevauche</p> <p></p> <p> Donc, dans le code, cela ressemblera à ceci:</p> <pre class="brush:php;toolbar:false"> Fonction MixColors (BaseColor, superlaycolor, superlayopacity) { const mixtescolor = { R: BaseColor.R (superlaycolor.r - BaseColor.R) * Overlayopacity, G: BaseColor.g (superlaycolor.g - basecolor.g) * superlayopacity, B: BaseColor.B (overlayColor.B - BaseColor.B) * Overlayopacity, } retour mixtecolor; }
Maintenant que nous pouvons mélanger les couleurs, nous pouvons tester le contraste lors de l'application de valeurs d'opacité de superposition.
function getTextContrastWithImagePlusOverlay ({textColor, overlayColor, imagePixelColor, superlayopacity}) { const ColoroFimagePixelPlusOverlay = mixColors (imagePixelColor, overlayColor, superlayopacity); const Contrast = GetContrast (textColor, ColoroFimagePixelPlusOverlay); Retour contraste; }
Avec cela, nous avons tous les outils dont nous avons besoin pour trouver la meilleure opacité de superposition!
Étape 4: Trouvez l'opacité de superposition qui atteint la cible de contraste
Nous pouvons tester l'opacité de la superposition et voir comment cela affectera le contraste entre le texte et l'image. Nous essaierons de nombreux niveaux d'opacité différents jusqu'à ce que nous trouvions une valeur qui atteint le contraste cible, où le texte est 4,5 fois plus brillant que l'arrière-plan. Cela peut sembler fou, mais ne vous inquiétez pas; Nous ne devinerons pas au hasard. Nous utiliserons la recherche binaire, un processus qui nous permet de réduire rapidement les ensembles de réponses possibles jusqu'à ce que nous obtenions des résultats précis.
Voici comment fonctionne la recherche binaire:
<code>- 在中间猜测。 - 如果猜测过高,我们将消除答案的上半部分。太低了吗?我们将改为消除下半部分。 - 在新的范围中间猜测。 - 重复此过程,直到我们得到一个值。我碰巧有一个工具可以展示它是如何工作的:在这种情况下,我们试图猜测一个介于0和1之间的不透明度值。因此,我们将从中间猜测,测试结果对比度是太高还是太低,消除一半的选项,然后再次猜测。如果我们将二分查找限制为八次猜测,我们将立即得到一个精确的答案。在我们开始搜索之前,我们需要一种方法来检查是否根本需要叠加层。我们根本不需要优化我们不需要的叠加层! ```javascript function isOverlayNecessary(textColor, worstContrastColorInImage, desiredContrast) { const contrastWithoutOverlay = getContrast(textColor, worstContrastColorInImage); return contrastWithoutOverlay </code>
Maintenant, nous pouvons utiliser la recherche binaire pour trouver la meilleure opacité de superposition:
fonction findOptimalOverLaYOPacity (textColor, overlayColor, pire // Si le contraste est assez bon, nous n'avons pas besoin de superposer, // Nous pouvons donc sauter le reste. const isOverlayneceSsary = isOverlaynecessary (textColor, pireContrastColoriniMage, désiréContrasse); if (! isOverlaynessary) { retour 0; } const OpacityGuessRange = { basse: 0, Point médian: 0,5, Upperbound: 1, }; Soit NumberOfGuesses = 0; const maxguess = 8; // S'il n'y a pas de solution, l'opacité sera proche de 1, // Nous pouvons donc l'utiliser comme limite supérieure pour vérifier la situation sans solutions. Const OpacityLimit = 0,99; // Cette boucle rétrécit à plusieurs reprises notre supposition jusqu'à ce que nous obtenions le résultat pendant (nombre de prudences <maxguess nombre de gar const currentguess="opacityGuessRange.MIDPoint;" contrast="getTextContrastWithImagePlusOverlay" overlaycolor imagepixelcolor: pirecontrastcolorinimage overlayopacity: currentgeess isguesstoolow="contraste" isguesstoohigh="contraste"> désiredContrast; if (isGuesstoolow) { OpacityGuessRange.LowerBound = CurrentGuess; } else if (isGuesstooHigh) { opacityGuessRange.upperbound = currentGuess; } const newMidpoint = ((opacityGuessRange.upperbound - opacityGuessRange.LowerBound) / 2) OpacityGuessRange.LowerBound; opacityGuessRange.midpoint = newMidPoint; } const OptimalOpacity = opacityGuessRange.midpoint; const Hasnosolution = OptimalOpacity> OpacityLimit; if (Hasnosolution) { console.log («pas de solution»); // gérer les situations insolubles au besoin RETOUR OPCACITYLIMIT; } Retour OptimalOpacity; }</maxguess>
Une fois l'expérience terminée, nous savons maintenant exactement à quel point la superposition doit être transparente pour rendre le texte lisible sans cacher trop d'images d'arrière-plan.
Nous l'avons fait!
Améliorations et limitations
La méthode que nous introduisons n'est efficace que si la couleur du texte et la couleur de superposition elles-mêmes ont un contraste suffisant. Par exemple, si vous choisissez la même couleur de texte que la superposition, il n'y aura pas de solution optimale à moins que l'image ne nécessite de superposition du tout.
De plus, même si le contraste est mathématiquement acceptable, cela ne garantit pas toujours qu'il a fière allure. Cela est particulièrement vrai pour le texte sombre avec des superpositions légères et des images d'arrière-plan occupées. Des parties de l'image peuvent distraire du texte et peuvent être difficiles à lire même si le contraste est numériquement bon. C'est pourquoi le conseil populaire est d'utiliser du texte clair sur des arrière-plans sombres.
Nous n'avons pas non plus considéré la position des pixels ou le nombre de pixels par couleur. Un inconvénient de cela est que les pixels dans les coins peuvent avoir un impact excessif sur les résultats. Mais l'avantage est que nous n'avons pas à nous soucier de la façon dont les couleurs de l'image sont distribuées ou où se trouve le texte, car tant que nous traitons des endroits avec le moins de contraste, nous pouvons être en sécurité ailleurs.
J'ai appris quelque chose en cours de route
Après cette expérience, j'ai gagné quelque chose et je veux le partager avec vous:
<code>- **明确目标非常有帮助!**我们从一个模糊的目标开始,即想要在图像上显示可读的文本,最终得到了一个我们可以努力达到的特定对比度级别。 - **明确术语非常重要。**例如,标准RGB并非我所期望的。我了解到,我认为的“常规”RGB(0到255)正式称为8位RGB。此外,我认为我研究的方程式中的“L”表示“亮度”,但它实际上表示“亮度”,这不能与“光度”混淆。澄清术语有助于我们编写代码以及讨论最终结果。 - **复杂并不意味着无法解决。**听起来很困难的问题可以分解成更小、更容易管理的部分。 - **当你走过这条路时,你会发现捷径。**对于白色文本在黑色透明叠加层上的常见情况,您永远不需要超过0.54的不透明度即可达到WCAG AA级可读性。 ### 总结…您现在有了一种方法可以在背景图像上使文本可读,而不会牺牲过多的图像。如果您已经读到这里,我希望我已经能够让您大致了解其工作原理。我最初开始这个项目是因为我看到(并制作了)太多网站横幅,其中文本在背景图像上难以阅读,或者背景图像被叠加层过度遮挡。我想做些什么,我想给其他人提供一种同样的方法。我写这篇文章是为了希望你们能够更好地理解网络上的可读性。我希望你们也学习了一些很酷的canvas技巧。如果您在可读性或canvas方面做了一些有趣的事情,我很乐意在评论中听到您的想法!</code>
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

Video Face Swap
Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds

Il est sorti! Félicitations à l'équipe Vue pour l'avoir fait, je sais que ce fut un effort massif et une longue période à venir. Tous les nouveaux documents aussi.

J'ai eu quelqu'un qui écrivait avec cette question très légitime. Lea vient de bloguer sur la façon dont vous pouvez obtenir les propriétés CSS valides elles-mêmes du navigateur. C'est comme ça.

Je dirais que "Site Web" correspond mieux que "Application mobile" mais j'aime ce cadrage de Max Lynch:

Si nous devons afficher la documentation à l'utilisateur directement dans l'éditeur WordPress, quelle est la meilleure façon de le faire?

L'autre jour, j'ai repéré ce morceau particulièrement charmant sur le site Web de Corey Ginnivan où une collection de cartes se cassent les uns sur les autres pendant que vous faites défiler.

Il existe un certain nombre de ces applications de bureau où l'objectif montre votre site à différentes dimensions en même temps. Vous pouvez donc, par exemple, écrire

CSS Grid est une collection de propriétés conçues pour faciliter la mise en page qu'elle ne l'a jamais été. Comme tout, il y a un peu une courbe d'apprentissage, mais Grid est

Je vois que Google Fonts a déployé un nouveau design (tweet). Comparé à la dernière grande refonte, cela semble beaucoup plus itératif. Je peux à peine faire la différence
