使文本根据其下面的颜色动态改变颜色

问题描述 投票:0回答:1

我试图根据菜单下面的颜色在黑色和白色之间更改菜单。我尝试过混合混合模式,但它会创建某些场景,使文本变得难以辨认。

我已经设法让它分析背景并输出颜色,但它在做出决定时似乎只是读取自身。我试图绕过它(在远离文本的 :before 上运行分析,但我认为它也不起作用......

问题是: 它可以识别背景,但不会更改文本颜色以与背景形成对比。深色背景=白色文本。,浅色背景=黑色文本我尝试了几种不同的方法,但它们要么使颜色闪烁,要么根本不改变颜色..

function getContrastRatio(color1, color2) {
  // Convert hex colors to RGB if necessary
  color1 = (color1.charAt(0) === '#') ? color1.substr(1) : color1;
  color2 = (color2.charAt(0) === '#') ? color2.substr(1) : color2;

  // Extract RGB values
  var r1 = parseInt(color1.substr(0, 2), 16);
  var g1 = parseInt(color1.substr(2, 2), 16);
  var b1 = parseInt(color1.substr(4, 2), 16);
  var r2 = parseInt(color2.substr(0, 2), 16);
  var g2 = parseInt(color2.substr(2, 2), 16);
  var b2 = parseInt(color2.substr(4, 2), 16);

  // Calculate relative luminance
  var lum1 = (Math.max(r1, g1, b1) + Math.min(r1, g1, b1)) / 2;
  var lum2 = (Math.max(r2, g2, b2) + Math.min(r2, g2, b2)) / 2;

  // Calculate contrast ratio
  var contrastRatio = (lum1 + 0.05) / (lum2 + 0.05);

  return contrastRatio;
}

function readBackgroundColor() {
  var menu = document.querySelector('.sticky-menu');
  var contentTop = menu.offsetTop + menu.offsetHeight;
  
  // Use the body as the default content element
  var content = document.body;

  // Iterate over all elements with class "colour" to find the one under the menu
  var colours = document.querySelectorAll('.colour');
  for (var i = 0; i < colours.length; i++) {
    var rect = colours[i].getBoundingClientRect();
    if (rect.top >= contentTop && colours[i] !== menu) { // Exclude the menu from consideration
      break;
    }
    content = colours[i];
  }

  // Check if the content element is a child of the menu
  if (!menu.contains(content)) {
    var computedStyle = window.getComputedStyle(content);
    var backgroundColor = computedStyle.backgroundColor;

    // Calculate contrast ratio for black and white text
    var blackContrast = getContrastRatio(backgroundColor, 'black');
    var whiteContrast = getContrastRatio(backgroundColor, 'white');

    // Choose the color with better contrast
    var textColor = blackContrast > whiteContrast ? 'black' : 'white';

    menu.style.color = textColor;

    console.log("Background:", backgroundColor, "Text:", textColor);
  }
}

// Event listener for scroll
window.addEventListener('scroll', readBackgroundColor);

// Initial call to read background color
readBackgroundColor();
body, html {padding:0;margin:0;}
.colour {height:250px;width:100vw;}

.black {background:black;}
.blue  {background:blue;}
.red   {background:red;}
  
.sticky-menu {
  position: fixed;
  top: 0;
  padding: 10px;
  line-height:0;
  font-size:50px;
}
<div class="sticky-menu">home</div>

<div class="colour black"></div>
<div class="colour white"></div>
<div class="colour blue"></div>
<div class="colour red"></div>
<div class="colour white"></div>

javascript colors navigation contrast computed-style
1个回答
0
投票

第一个问题是对比度函数的参数。看起来

getComputedStyle
rgb(25, 25, 25)
格式返回背景。另一个问题是
.white
类未定义为
background: white
,因此它没有返回所需的
rgb(255, 255, 255)
计算背景。最后,我从
这个答案
中获取了contrast

函数

最后一期,这个示例按原样提供,您当然可以缩短它。

const rgba2hex = (rgba) => `${rgba.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+\.{0,1}\d*))?\)$/).slice(1).map((n, i) => (i === 3 ? Math.round(parseFloat(n) * 255) : parseFloat(n)).toString(16).padStart(2, '0').replace('NaN', '')).join('')}`

const RED = 0.2126;
const GREEN = 0.7152;
const BLUE = 0.0722;

const GAMMA = 2.4;

function luminance(r, g, b) {
  var a = [r, g, b].map((v) => {
    v /= 255;
    return v <= 0.03928 ?
      v / 12.92 :
      Math.pow((v + 0.055) / 1.055, GAMMA);
  });
  return a[0] * RED + a[1] * GREEN + a[2] * BLUE;
}

function contrast(rgb1, rgb2) {
  var lum1 = luminance(...rgb1);
  var lum2 = luminance(...rgb2);
  var brightest = Math.max(lum1, lum2);
  var darkest = Math.min(lum1, lum2);
  return (brightest + 0.05) / (darkest + 0.05);
}

function getContrastRatio(color1, color2) {
  // Convert hex colors to RGB if necessary
  color1 = rgba2hex(color1)
  color2 = rgba2hex(color2)

  // Extract RGB values
  var r1 = parseInt(color1.substr(0, 2), 16);
  var g1 = parseInt(color1.substr(2, 2), 16);
  var b1 = parseInt(color1.substr(4, 2), 16);
  var r2 = parseInt(color2.substr(0, 2), 16);
  var g2 = parseInt(color2.substr(2, 2), 16);
  var b2 = parseInt(color2.substr(4, 2), 16);

  return contrast([r1, g1, b1], [r2, g2, b2])
}

function readBackgroundColor() {
  var menu = document.querySelector('.sticky-menu');
  var contentTop = menu.offsetTop + menu.offsetHeight;

  // Use the body as the default content element
  var content = document.body;

  // Iterate over all elements with class "colour" to find the one under the menu
  var colours = document.querySelectorAll('.colour');
  for (var i = 0; i < colours.length; i++) {
    var rect = colours[i].getBoundingClientRect();
    if (rect.top >= contentTop && colours[i] !== menu) { // Exclude the menu from consideration
      break;
    }
    content = colours[i];
  }

  // Check if the content element is a child of the menu
  if (!menu.contains(content)) {
    var computedStyle = window.getComputedStyle(content);
    var backgroundColor = computedStyle.backgroundColor;

    // Calculate contrast ratio for black and white text
    var blackContrast = getContrastRatio(backgroundColor, 'rgb(0,0,0)');
    var whiteContrast = getContrastRatio(backgroundColor, 'rgb(255,255,255)');

    // Choose the color with better contrast
    var textColor = blackContrast > whiteContrast ? 'black' : 'white';

    menu.style.color = textColor;

    // console.log("Background:", backgroundColor, "blackContrast", blackContrast, "whiteContrast", whiteContrast);
  }
}

// Event listener for scroll
window.addEventListener('scroll', readBackgroundColor);

// Initial call to read background color
readBackgroundColor();
body,
html {
  padding: 0;
  margin: 0;
}

.colour {
  height: 250px;
  width: 100vw;
}

.white {
  background: white;
}

.black {
  background: black;
}

.blue {
  background: blue;
}

.red {
  background: red;
}

.sticky-menu {
  position: fixed;
  top: 0;
  padding: 10px;
  line-height: 0;
  font-size: 50px;
}
<div class="sticky-menu">home</div>

<div class="colour black"></div>
<div class="colour white"></div>
<div class="colour blue"></div>
<div class="colour red"></div>
<div class="colour white"></div>

© www.soinside.com 2019 - 2024. All rights reserved.