Как добавить оттенок к фоновому изображению с прозрачностью в CSS

У меня есть некоторый контент на странице, который служит глобальным фоном. Я поместил спрайт (div с background-image: url(...), меняя кадры, модифицировав background-position) поверх спрайта, используя position: absolute. Спрайт представляет собой PNG с альфа-каналом.

Теперь я пытаюсь добавить оттенок этому изображению (зеленоватый, голубоватый или другой).

Я изучил подобные вопросы, и, по-видимому, единственными возможными решениями являются:

  1. Создайте div поверх спрайта с желаемым цветом в качестве его background-color, желаемой интенсивностью оттенка в качестве opacity и исходным изображением спрайта в виде mask-image (и установите mask-type: alpha). Хотя на бумаге это должно работать, на практике это не так - этот новый div просто невидим :(
  2. Используйте mix-blend-mode для наложения цветного div и укажите что-то вроде multiply или overlay. Он дает отличные результаты, пока глобальный фон черный. Если это что-то другое - оно включается в расчеты, и оверлей div тоже модифицирует его, создавая окрашенный прямоугольник вместо окрашенного спрайта...
  3. Используйте фильтр SVG, как описано в ответе здесь: https://stackoverflow.com/a/30949302/306470. Я еще не пробовал это, но для этой задачи он кажется излишне сложным. Меня также беспокоит производительность, сильно ли это замедлит работу, если на экране одновременно будет несколько тонированных спрайтов? Если у кого-то был опыт с этим, пожалуйста, напишите здесь :)
  4. Подготовьте тонированную версию спрайта, используя невидимый canvas. Звучит еще сложнее, имеет недостаток в том, что нужно тратить время на подготовку тонированной версии спрайта, но должен ли он работать так же быстро, как и исходный спрайт после его подготовки? Однако реализация должна быть довольно сложной. Чистое решение CSS было бы намного лучше...

Я что-то упускаю? Есть ли другие варианты? Или я должен пойти с № 3 или № 4?


person mephisto123    schedule 14.11.2020    source источник
comment
Попробуйте filter: hue-rotate(Xdeg) изменить значение X в соответствии с вашими требованиями.   -  person Akshay    schedule 14.11.2020
comment
Спасибо! Я думал об этом, но это будет работать только для более или менее одноцветных изображений, и я должен знать этот оттенок перед применением фильтра.   -  person mephisto123    schedule 14.11.2020
comment
Если ваши изображения не являются динамическими, вы можете найти желаемый оттенок для каждого изображения, добавить их к объекту, а затем использовать js для динамического применения фильтра. Но это может быть неприменимо, если у вас много изображений или если изображения созданы пользователем.   -  person Akshay    schedule 14.11.2020
comment
Изображения не создаются пользователями, но у меня потенциально может быть много из них, и поиск правильного оттенка вручную не вариант. Но все равно спасибо за предложение!   -  person mephisto123    schedule 14.11.2020
comment
Вы можете использовать JS, чтобы получить положение изображения/ов getBoundingClientRect(), затем установить положение элемента наложения, установленное в абсолютное положение с более высоким zindex, а затем с помощью настроек rect.top, rect.left ваших изображений установить их в наложение, чтобы они располагались сверху. Получите ширину и высоту изображений, используя this.width и this.height, и установите элементы наложения на эти значения ширины и высоты. Установите backgroundColor вашего элемента наложения на желаемый RGB с непрозрачностью (0, 255, 0, 0,5) => зеленоватое наложение или рандомизируйте RGB с непрозрачностью, установленной на 0,5, чтобы он действовал как фильтр.   -  person dale landry    schedule 14.11.2020


Ответы (2)


Вот рабочий пример изложенного комментария, который я оставил, надеюсь, он поможет. Я использую созданный элемент div для наложения поверх изображения. Получите положение элементов изображения, используя boundingClientRect и this.width/this.height внутри цикла for, перебирающего элементы изображения. Установите положение элементов наложения на положение элемента изображения, на которое накладывается цикл, и рандомизируйте цвет с помощью функции с параметром rgb для альфа-канала равным 0,5.

let fgrp = document.getElementById("group");
let images = document.querySelectorAll(".imgs");
//function to randomize the RGB overlay color
function random() {
  var o = Math.round,
    r = Math.random,
    s = 255;
  return o(r() * s);
}
//function to randomize a margin for each image to show the overlay will snap to the image 
function randomWidth() {
  var n = Math.round,
    ran = Math.random,
    max = 400;
  return n(ran() * max);
}
// loop through the img elements and create an overlay div element for each img element
for (let i = 0; i < images.length; i++) {
  // load the images and get their wisth and height
  images[i].onload = function() {
    let width = this.width;
    let height = this.height;
    this.style.marginLeft = randomWidth() + "px";
    // create the overlay element
    let overlay = document.createElement("DIV");
    // append the overlay element
    fgrp.append(overlay);
    // get the image elements top, left positions using `getBoundingClientRect()`
    let rect = this.getBoundingClientRect();
    // set the css for the overlay using the images height, width, left and top positions
    // set position to absolute incase scrolling page, zindex to 2 
    overlay.style.cssText = "width: " + this.offsetWidth + "px; height: " + this.offsetHeight + "px; background-color: rgba(" + random() + ", " + random() + ", " + random() + ", 0.5); left: " + rect.left + "px; top: " + rect.top + "px; position: absolute; display: block; z-index: 2; cursor pointer;";
  }
}
img {
  margin: 50px 0;
  display: block;
}
<div id="group">
  <image src="https://artbreeder.b-cdn.net/imgs/275c7c05efca3a40e3178208.jpeg?width=256" class="imgs"></image>
  <image src="https://artbreeder.b-cdn.net/imgs/275c7c05efca3a40e3178208.jpeg?width=256" class="imgs"></image>
  <image src="https://artbreeder.b-cdn.net/imgs/275c7c05efca3a40e3178208.jpeg?width=256" class="imgs"></image>
</div>

person dale landry    schedule 14.11.2020
comment
Он не будет работать для изображений с прозрачностью: он добавит оттенок всему прямоугольнику, включая фон под изображением, который виден в прозрачных частях изображения. - person mephisto123; 15.11.2020

Следуя приведенному ниже руководству, можно придать красочный оттенок div/изображению, используя только CSS, например:

<html>

<head>
    <style>
        .hero-image {
            position: relative;
            width: 100%;
        }

        .hero-image:after {
            position: absolute;
            height: 100%;
            width: 100%;
            background-color: rgba(0, 0, 0, .5);
            top: 0;
            left: 0;
            display: block;
            content: "";
        }
    </style>
</head>

<body>
    <div class="hero-image">
        <img src="https://cdn.jpegmini.com/user/images/slider_puffin_before_mobile.jpg" alt="after tint" />
    </div>
    <div>
        <img src="https://cdn.jpegmini.com/user/images/slider_puffin_before_mobile.jpg" alt="before tint" />
    </div>
</body>

</html>

Поскольку вы пытаетесь поместить его поверх изображения с абсолютным положением, как говорится в руководстве, добавьте z-индекс 1 (например) к фрагменту :after.

Изменить: может потребоваться некоторая настройка процента ширины!

Источник: https://ideabasekent.com/wiki/adding-image-overlay-tint-using-css

person hkZeneus    schedule 14.11.2020
comment
К сожалению, это не сработает для изображений с прозрачными частями, как я объяснил в вопросе :( - person mephisto123; 15.11.2020