Skip to content

Instantly share code, notes, and snippets.

@vielhuber
Last active February 18, 2025 13:55
Show Gist options
  • Save vielhuber/44cfe9d09d7e1b79a17bee4e29ee8755 to your computer and use it in GitHub Desktop.
Save vielhuber/44cfe9d09d7e1b79a17bee4e29ee8755 to your computer and use it in GitHub Desktop.
mix-blend-mode for elements inside a fixed header stacking context problem #css
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5, minimum-scale=1" />
<title>.</title>
<script>
/* debug switcher */
document.addEventListener('DOMContentLoaded', () => {
document.querySelector('.debug').addEventListener('change', e =>
{
document.body.setAttribute('class', e.currentTarget.value);
e.preventDefault();
});
});
</script>
<style>
/* basic css */
*
{
box-sizing: border-box;
margin: 0;
padding: 0;
}
.debug {
position:fixed;
top:25px;
left:25px;
font-size:20px;
z-index:2;
}
.sections__section {
height:40vh;
background-color:#fff;
}
.sections__section:nth-child(even) {
background-color:#000;
}
.header {
position:fixed;
top:0;
left:0;
width:100%;
height:auto;
padding:25px;
}
.header__logo {
float:right;
}
.header__logo-part {
display:inline;
font-size:25px;
font-family:"Courier New";
font-weight:bold;
letter-spacing:4px;
color:red;
}
/*
general rules:
- color must always be white (#fff), not black (#000)
- mix-blend-mode merges the applied element with the background of its parent (or any parents parent that has a background color)
- caveat: it never breaks out an existing stacking context (so it does not work if it is a child of e.g. a fixed element and should be applied to the parent of that fixed element)
/* first try */
/* does not work, because .header created a new stacking context and we cannot break out of it. mix-blend-mode get's applied to header, and not body. */
._1 .header__logo-part--blended {
mix-blend-mode:difference;
color:#fff;
}
/* second try */
/* does not work, because we never can exclude a child element from a parent styled with mix-blend-mode */
._2 .header {
mix-blend-mode:difference;
}
._2 .header__logo-part--blended {
color:#fff;
}
._2 .header *:not(.header__logo-part--blended) {
mix-blend-mode:difference;
}
/* third try */
/* reset stacking context of header */
._3 .header {
position:relative;
padding:0;
}
/* fix position of children (this is hacky) */
._3 .header__logo-part {
position:fixed;
top:25px;
z-index:1;
}
._3 .header__logo-part--1 {
right:147px;
}
._3 .header__logo-part--2 {
right:86px;
}
._3 .header__logo-part--3 {
right:25px;
}
/* apply mix blend mode (this now works, because it is not inside another stacking context) */
._3 .header__logo-part--blended {
mix-blend-mode:difference;
color:#fff;
}
</style>
</head>
<body class="_1">
<select class="debug">
<option value="_1">try #1</option>
<option value="_2">try #2</option>
<option value="_3">try #3</option>
</select>
<div class="header">
<div class="header__logo">
<div class="header__logo-part header__logo-part--1">foo</div>
<div class="header__logo-part header__logo-part--2 header__logo-part--blended">bar</div>
<div class="header__logo-part header__logo-part--3">baz</div>
</div>
</div>
<div class="sections">
<div class="sections__section"></div>
<div class="sections__section"></div>
<div class="sections__section"></div>
<div class="sections__section"></div>
<div class="sections__section"></div>
<div class="sections__section"></div>
<div class="sections__section"></div>
<div class="sections__section"></div>
<div class="sections__section"></div>
<div class="sections__section"></div>
<div class="sections__section"></div>
<div class="sections__section"></div>
<div class="sections__section"></div>
<div class="sections__section"></div>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment