Слоистые маски в CSS - PullRequest
       13

Слоистые маски в CSS

0 голосов
/ 01 сентября 2018

Я пытаюсь выяснить, возможны ли маски слоев в CSS. В основном у меня есть SVG, который обозначает какую-то сцену. Это отображается в виде маски с использованием маски-изображения и имеет черный фоновый цвет. Что-то вроде:

mask-image: url(image.svg);
background-color: #000;
...

В зависимости от некоторого связанного состояния мне нужно обратить внимание на этот маскированный svg, наложив поверх него другой svg, например, и восклицательный знак. Это может иметь другой цвет, например красный, но может меняться в зависимости от обстоятельств.

Грубый пример показан ниже, где у меня есть кнопка с текстом. Квадрат - это svg, который появляется только тогда, когда существует какое-то состояние (состояние A), и в этом случае класс добавляется в div. Круг внутри квадрата является связанным состоянием и появляется только тогда, когда квадратом является состояние A, истинное, плюс некоторое дополнительное состояние. Таким образом, в структуре Less / BEM это дополнительное состояние будет реализовано как модификатор как таковой:

&__state {
  mask-image: url(state.svg);
  background-color: #000;
  ...

  &--inner-state {
    mask-image: url(inner-state.svg);
    background-color: red;
    ...
  }
}

enter image description here

Кнопка ничего не знает о svgs, так как я динамически добавляю div и вышеупомянутый CSS в зависимости от состояния.

Это легко сделать в CSS? Как уже упоминалось, я использую Less со структурой BEM, но мне не обязательно нужен ответ, связанный с ними. Меня больше интересует концепция.

Не стесняйтесь спрашивать дополнительную информацию, если потребуется, и я был бы признателен за любую помощь!

Ответы [ 2 ]

0 голосов
/ 03 сентября 2018

(отправка другого ответа, потому что это очень отличается)

Демо-версия:

(В идеале вы должны сначала прочитать объяснение, но в случае, если хотите сначала увидеть конечный результат ...)

Внешний интерфейс: https://codepen.io/devanshj/pen/OomRer

Бэкэнд: https://glitch.com/edit/#!/mature-teller?path=server.js:8:0

Пояснение:

Я не мог понять, чего вы пытаетесь достичь с помощью этих масок и фонов (вместо прямых svgs), пока не наткнулся на эту статью: Раскраска SVG в фоновых изображениях CSS ...

Причина, по которой решение (я) в этой статье не работает для вас, заключается в том, что вы хотите использовать несколько цветных svgs (а решение в статье - только для одного svg)

Объединяя проблему, которую решает статья, с тем, что вы хотите в качестве конечной цели, я бы перефразировал вопрос примерно так:

  1. Я хочу иметь несколько фонов SVG для элемента
  2. Я также хочу контролировать цвет каждого SVG
  3. Только решение css. Вам не разрешено изменять html.

Это довольно невозможно. «довольно», - сказал я, следовательно, это возможно (с супер экстраординарным решением).

Довольно невозможная часть - раскраска svg. Несколько фонов SVG только с CSS просто.

Но что, если я сделаю что-нибудь, что раскрасит svg из самого URL, например url(my-icon.svg?fill=#f00) Если я смогу сделать это, ваша проблема будет решена, и мы можем сделать что-то вроде:

.icon-a{
    background-image: url("a.svg?fill=%23000"); // # encoded to %23 so that server doesn't think #000 is the hash part of the request

    &.icon-b{
        background-image: url("a.svg?fill=%23000"), url("b.svg?fill=%23fff");

        &:hover{
            background-image: url("a.svg?fill=%23000"), url("b.svg?fill=%23f00");
        }
    }
}

Это можно сделать с помощью небольшого серверного кода (используя здесь express и nodejs, аналогичный код можно написать и для других языков / сред):

app.get("/icons/*.svg", async (req, res) => {
    let svgCode = await readFileAsync(path.join(__dirname, req.path), {encoding: "utf8"});
    svgCode = svgCode.replace(/{{queryFill}}/g, req.query.fill);
    res.set("Content-Type", "image/svg+xml");
    res.send(svgCode);
});

и svg:

<svg xmlns="http://www.w3.org/2000/svg">
    <style>
        .query-fill{
            fill: {{queryFill}};
        }
    </style>
    <rect x="0" y="0" width="100" height="100" class="query-fill"></rect>
</svg>

Альтернатива:

Если вы позволите мне изменить html, решение будет очень простым с использованием встроенного svg и <use> ... Но я думаю, что вам нужно решение только для css ...

PS: Если вам интересно, есть ли решение без какого-либо серверного кода? Нет.

PPS: Если перефразированный вопрос не тот, который вы хотите, то то, что вы ищете (многослойные маски), невозможно только с помощью css.

0 голосов
/ 01 сентября 2018

Если я правильно понял ваш вопрос ... Вы можете просто поместить дополнительный оверлейный svg как <img> или встроенный <svg>, например:

.masked{
  width: 100px;
  position: relative;
}
.masked img{
  width: 100%;
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'><circle cx='50' cy='50' r='50' fill='#fff'></circle></svg>") top left / cover;
  mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'><circle cx='50' cy='50' r='50' fill='#fff'></circle></svg>") top left / cover;
}

.masked svg{
  width: 100%;
  position: absolute;
  top: 0;
  opacity: 0;
}

.masked:hover svg{
  opacity: 1;
}
<div class="masked">
  <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/Harry-Potter-1-.jpg" />
  <svg viewBox="0 0 100 100">
    <rect x="25" y="25" width="50" height="50" fill="red"></rect>
  </svg>
</div>
...