CSS: как динамически инвертировать цвет текста при наложении его на блок с тёмным фоном?

При наведении на цветной блок он плавно заползает под текст. Нужно, чтобы часть текста на фоне блока в этот момент меняла свой цвет на белый. Перепробовал все варианты mix-blend-mode - хотя бы немного меняют цвет текста hue, saturation и color, но это далеко не белый. Остальные либо не дают эффекта, либо скрывают текст под фоном.

Каким образом можно решить данную задачу? И можно ли вообще? Безо всяких костылей с дублированием текста, открытием/сокрытием и т.д.

main {
  position: relative;
  overflow: hidden;
  margin: 30px 0;
}
.main-text {
  position: relative;
  max-width: 70%;
  /*mix-blend-mode: ;*/
}
.color-block {
    height: 100%;
    width: 100%;
    background-color: #2845AA;
    position: absolute;
    top: 0;
    bottom: 0;
    margin: auto;
    right: -90%;
    transition: .5s;
}
.color-block:hover {
    right: -40%;
}
<main>
  <div class="color-block"></div>
  <div class="main-text">Lorem ipsum dolor sit amet consectetur, adipisicing elit. Doloribus tenetur saepe optio corrupti earum? Eligendi fugit nemo, quibusdam quas vero error qui obcaecati placeat suscipit provident? Consectetur, alias velit dignissimos. Lorem ipsum dolor sit amet consectetur, adipisicing elit. Doloribus tenetur saepe optio corrupti earum? Eligendi fugit nemo, quibusdam quas vero error qui obcaecati placeat suscipit provident? Consectetur, alias velit dignissimos.</div>
</main>


Ответы (6 шт):

Автор решения: Vivi

Действительно сложная задача. Если вам нужен именно синий фон, то вычитание здесь не поможет. Сделал вот такой вариант, конечно же нуждается в вашей доработке и будет работать только с чёрным цветом. Если пытаться делать с синим, то нужно вычесть из белого цвета желтый, но тогда и текст будет желтым.

main {
  position: relative;
  margin: 30px 0;
}
.main-text {
  position: relative;
  background:white;
  max-width: 70%;
  /*mix-blend-mode: ;*/
}

  .color-block {
    content: '';
    position: absolute;
    right: 0;
    bottom: 0;
    width: 100%;
    height:100%;
    margin: auto;
    right: -100%;
transition: .5s;
    background: black;
    mix-blend-mode: difference;
  }
.color-block:hover{
    right: -40%;
    z-index:1000;
    background:white;
}
<main>
  <div class="main-text">Lorem ipsum dolor sit amet consectetur, adipisicing elit. Doloribus tenetur saepe optio corrupti earum? Eligendi fugit nemo, quibusdam quas vero error qui obcaecati placeat suscipit provident? Consectetur, alias velit dignissimos. Lorem ipsum dolor sit amet consectetur, adipisicing elit. Doloribus tenetur saepe optio corrupti earum? Eligendi fugit nemo, quibusdam quas vero error qui obcaecati placeat suscipit provident? Consectetur, alias velit dignissimos.
  <div class="color-block"></div>
  </div>
</main>

→ Ссылка
Автор решения: puffleeck

как на счёт театра теней? :3

main {
  position: relative;
  overflow: hidden;
  margin: 30px 0;
}

.main-text {
  position: relative;
  padding: 0 .5em;
  max-width: 70%;
  line-height: 2;
  text-shadow: .5em 1em 0 white;
  mix-blend-mode: lighten;
}

.main-text::first-line {
  font: 30px bold;
}

#x:checked+.main-text {
  -webkit-text-stroke: 1px gray;
  filter: drop-shadow(0 0 2px skyblue);
}

.color-block {
  height: 100%;
  width: 100%;
  background-color: #2845AA;
  position: absolute;
  top: 50px;
  bottom: 0;
  margin: auto;
  right: -60%;
  transition: .5s;
}

.color-block:hover {
  right: 0;
}
<main>
  <div class="color-block"></div>
  <input type='checkbox' id='x' checked> <- убрать грязь
  <div class="main-text">Lorem ipsum dolor sit amet consectetur, adipisicing elit. Doloribus tenetur saepe optio corrupti earum? Eligendi fugit nemo, quibusdam quas vero error qui obcaecati placeat suscipit provident? Consectetur, alias velit dignissimos. Lorem ipsum dolor
    sit amet consectetur, adipisicing elit. Doloribus tenetur saepe optio corrupti earum? Eligendi fugit nemo, quibusdam quas vero error qui obcaecati placeat suscipit provident? Consectetur, alias velit dignissimos.</div>
</main>

→ Ссылка
Автор решения: Vivi

Сделал ещё вот такой кастыль с градиентом и анимацией. Выглядит конечно по-замудреннее, чем вариант с вычитанием, но со своей задачей справляется.

main {
  position: relative;
  overflow: hidden;
  margin: 30px 0;
}

.main-text {
  position: relative;
  max-width: 70%;
  background: linear-gradient(to right, black 100%, white 0%);
  -webkit-background-clip: text;
  color: transparent;
  transition: background 0.5s ease;
  /*mix-blend-mode: ;*/
}

.color-block {
  height: 100%;
  width: 100%;
  background-color: #2845AA;
  position: absolute;
  top: 0;
  bottom: 0;
  margin: auto;
  right: -90%;
  transition: .5s;
}

.color-block:hover {
  right: -40%;
}

.color-block:hover+.main-text {
  animation-duration: 0.3s;
  animation-fill-mode: forwards;
  animation-delay: 0.1s;
  animation-name: gradient-animation;
}

@keyframes gradient-animation {
  from {
    background: linear-gradient(to right, black 100%, white 0%);
    -webkit-background-clip: text;
  }
  10% {
    background: linear-gradient(to right, black 95%, white 5%);
    -webkit-background-clip: text;
  }
  20% {
    background: linear-gradient(to right, black 90%, white 10%);
    -webkit-background-clip: text;
  }
  30% {
    background: linear-gradient(to right, black 85%, white 15%);
    -webkit-background-clip: text;
  }
  40% {
    background: linear-gradient(to right, black 80%, white 20%);
    -webkit-background-clip: text;
  }
  50% {
    background: linear-gradient(to right, black 75%, white 25%);
    -webkit-background-clip: text;
  }
  60% {
    background: linear-gradient(to right, black 70%, white 30%);
    -webkit-background-clip: text;
  }
  70% {
    background: linear-gradient(to right, black 65%, white 35%);
    -webkit-background-clip: text;
  }
  80% {
    background: linear-gradient(to right, black 60%, white 40%);
    -webkit-background-clip: text;
  }
  to {
    background: linear-gradient(to right, black 0%, black 57%, white 57%, white 100%);
    -webkit-background-clip: text;
  }
}
<main>
  <div class="color-block"></div>
  <div class="main-text">Lorem ipsum dolor sit amet consectetur, adipisicing elit. Doloribus tenetur saepe optio corrupti earum? Eligendi fugit nemo, quibusdam quas vero error qui obcaecati placeat suscipit provident? Consectetur, alias velit dignissimos. Lorem ipsum dolor
    sit amet consectetur, adipisicing elit. Doloribus tenetur saepe optio corrupti earum? Eligendi fugit nemo, quibusdam quas vero error qui obcaecati placeat suscipit provident? Consectetur, alias velit dignissimos.</div>
</main>

→ Ссылка
Автор решения: Miha

Можно использовать filter: invert(1) в сочетаний с mix-blend-mode: difference

P.S: если не добавить стиль filter: invert(1) для .color-block то цвет блока будет инверсирован а цвет текста который указан в background-color

main {
  position: relative;
  overflow: hidden;
  margin: 30px 0;
  filter: invert(1); /* <- тут */
}

.main-text {
  position: relative;
  max-width: 70%;
  color: white;
  mix-blend-mode: difference; /* <- тут */
}

.color-block {
  height: 100%;
  width: 100%;
  filter: invert(1); /* <- тут, не обязательно */
  background-color: #2845AA;
  position: absolute;
  top: 0;
  bottom: 0;
  margin: auto;
  right: -90%;
  transition: 5s;
}

.color-block:hover {
  right: -40%;
}
<main>
  <div class="color-block"></div>
  <div class="main-text">Lorem ipsum dolor sit amet consectetur, adipisicing elit. Doloribus tenetur saepe optio corrupti earum? Eligendi fugit nemo, quibusdam quas vero error qui obcaecati placeat suscipit provident? Consectetur, alias velit dignissimos. Lorem ipsum dolor
    sit amet consectetur, adipisicing elit. Doloribus tenetur saepe optio corrupti earum? Eligendi fugit nemo, quibusdam quas vero error qui obcaecati placeat suscipit provident? Consectetur, alias velit dignissimos.</div>
</main>

Попытка № 2: Используя background-image: linear-gradient и background-clip: text

.mix-text+.mix-text {
  margin-top: 20px;
}

.mix-text {
  position: relative;
}

.mix-text:hover .box {
  width: var(--to);
}

.mix-text .text {
  color: transparent;
  width: 100%;
  transition: all 2s;
  background-color: white;
  background-size: 200% 100%;
  background-clip: text;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

.mix-text:not(.reverse) .text {
  background-image: linear-gradient(to right, white 50%, black 50%);
  background-position: calc(100% - var(--from)) 0;
}

.mix-text.reverse .text {
  background-image: linear-gradient(to left, white 50%, black 50%);
  background-position: calc(0% + var(--from)) 0;
}

.mix-text:not(.reverse):hover .text {
  background-position: calc(100% - var(--to)) 0;
}

.mix-text.reverse:hover .text {
  background-position: calc(0% + var(--to)) 0;
}

.mix-text .box {
  position: absolute;
  top: 0;
  height: 100%;
  width: var(--from);
  transition: all 2s;
  background: black;
  z-index: -1;
}

.mix-text:not(.reverse) .box {
  left: 0;
}

.mix-text.reverse .box {
  right: 0;
}
<div class="mix-text" style="--from: 40%; --to: 20%">
  <div class="text">
    Lorem ipsum dolor sit amet consectetur, adipisicing elit. Doloribus tenetur saepe optio corrupti earum? Eligendi fugit nemo, quibusdam quas vero error qui obcaecati placeat suscipit provident? Consectetur, alias velit dignissimos.
  </div>
  <div class="box"></div>
</div>

<div class="mix-text" style="--from: 40%; --to: 60%">
  <div class="text">
    Lorem ipsum dolor sit amet consectetur, adipisicing elit. Doloribus tenetur saepe optio corrupti earum? Eligendi fugit nemo, quibusdam quas vero error qui obcaecati placeat suscipit provident? Consectetur, alias velit dignissimos.
  </div>
  <div class="box"></div>
</div>

<div class="mix-text reverse" style="--from: 40%; --to: 20%">
  <div class="text">
    Lorem ipsum dolor sit amet consectetur, adipisicing elit. Doloribus tenetur saepe optio corrupti earum? Eligendi fugit nemo, quibusdam quas vero error qui obcaecati placeat suscipit provident? Consectetur, alias velit dignissimos.
  </div>
  <div class="box"></div>
</div>

<div class="mix-text reverse" style="--from: 40%; --to: 60%">
  <div class="text">
    Lorem ipsum dolor sit amet consectetur, adipisicing elit. Doloribus tenetur saepe optio corrupti earum? Eligendi fugit nemo, quibusdam quas vero error qui obcaecati placeat suscipit provident? Consectetur, alias velit dignissimos.
  </div>
  <div class="box"></div>
</div>

→ Ссылка
Автор решения: Grundy

Можно разделить на две части:

  1. черный текст на белом фоне
  2. белый текст на синем

main {
  position: relative;
  overflow: hidden;
  margin: 30px 0;
}

.main-text {
  position: relative;
  max-width: 70%;
  mix-blend-mode: difference;
  color: #ffffff;
}

.white-block {
  height: 100%;
  width: 90%;
  background-color: #ffffff;
  position: absolute;
  transition: .5s;
}

.color-block {
  height: 100%;
  width: 100%;
  background-color: #2845AA;
  position: absolute;
  top: 0;
  bottom: 0;
  margin: auto;
  right: -90%;
  transition: .5s;
  z-index: 1;
  mix-blend-mode: screen;
}

.color-block:hover {
  right: -40%;
}

.color-block:hover+.white-block {
  width: 40%;
}
<main>
  <div class="color-block"></div>
  <div class="white-block"></div>
  <div class="main-text">Lorem ipsum dolor sit amet consectetur, adipisicing elit. Doloribus tenetur saepe optio corrupti earum? Eligendi fugit nemo, quibusdam quas vero error qui obcaecati placeat suscipit provident? Consectetur, alias velit dignissimos. Lorem ipsum dolor
    sit amet consectetur, adipisicing elit. Doloribus tenetur saepe optio corrupti earum? Eligendi fugit nemo, quibusdam quas vero error qui obcaecati placeat suscipit provident? Consectetur, alias velit dignissimos.</div>
</main>

→ Ссылка
Автор решения: Qwertiy

Не на тот элемент ты их ставил. И вообще, нужны два оверлея: один для маски, а другой - для фона. Вот так (разметку не менял):

main {
  position: relative;
  overflow: hidden;
  margin: 30px 0;
}

.main-text {
  position: relative;
  max-width: 70%;
  z-index: 3;
}

.color-block {
  position: absolute;
  inset: 0 0 0 auto;
  width: 10%;
  transition: .5s;
}

.color-block:hover {
  width: 60%;
}

.color-block::before, .color-block::after {
  content: "";
  position: absolute;
  inset: 0;
}

.color-block::before {
  background: white;
  z-index: 4;
  mix-blend-mode: difference;
}

.color-block::after {
  background: #D7BA55; /* станет #2845AA */
  z-index: 2;
}
<main>
  <div class="color-block"></div>
  <div class="main-text">Lorem ipsum dolor sit amet consectetur, adipisicing elit. Doloribus tenetur saepe optio corrupti earum? Eligendi fugit nemo, quibusdam quas vero error qui obcaecati placeat suscipit provident? Consectetur, alias velit dignissimos. Lorem ipsum dolor sit amet consectetur, adipisicing elit. Doloribus tenetur saepe optio corrupti earum? Eligendi fugit nemo, quibusdam quas vero error qui obcaecati placeat suscipit provident? Consectetur, alias velit dignissimos.</div>
</main>

→ Ссылка