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>