← HTML & CSS/CSS фильтры и режимы наложения#37 из 383← ПредыдущийСледующий →+15 XP
Полезно по теме:Гайд: старт в frontendПрактика: DOM и событияТермин: DOMМаршрут: старт с нуля

CSS фильтры и режимы наложения

Фильтры и blend modes дают CSS-фотошоп прямо в браузере: размытие, обесцвечивание, контраст, наложение слоёв. Без Canvas, без JS-библиотек.

filter — функции фильтрации

/* Базовые функции */
.image {
  filter: blur(4px);              /* Размытие (Gaussian blur) */
  filter: brightness(1.5);       /* Яркость: >1 светлее, <1 темнее */
  filter: contrast(2);           /* Контраст: >1 больше, <1 меньше */
  filter: grayscale(1);          /* 0 = цвет, 1 = ч/б */
  filter: saturate(0.5);         /* 0 = серый, 1 = норма, 2 = насыщенный */
  filter: hue-rotate(90deg);     /* Сдвиг цветового тона */
  filter: invert(1);             /* Инверсия цветов */
  filter: sepia(0.8);            /* Сепия */
  filter: opacity(0.5);          /* Прозрачность (как opacity, но compositing) */
}

/* drop-shadow — тень повторяет форму (в отличие от box-shadow) */
.icon {
  filter: drop-shadow(4px 4px 8px rgba(0,0,0,0.4));
}

/* Комбинирование — применяются слева направо */
.stylized {
  filter: contrast(1.2) brightness(1.1) saturate(1.3);
}

backdrop-filter — фильтр фона

Применяется к содержимому ЗА элементом (не к самому элементу):

/* Glassmorphism — стеклянный эффект */
.glass-card {
  background: rgba(255, 255, 255, 0.15);
  backdrop-filter: blur(12px) saturate(1.8);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 16px;
}

/* Затемнённый модальный фон */
.modal-overlay {
  backdrop-filter: blur(4px) brightness(0.7);
}

mix-blend-mode — наложение на нижние слои

.text-overlay {
  mix-blend-mode: multiply;    /* Умножение — тёмные тона */
  mix-blend-mode: screen;      /* Экран — светлые тона */
  mix-blend-mode: overlay;     /* Наложение — комбо */
  mix-blend-mode: difference;  /* Разница — инверсия */
  mix-blend-mode: luminosity;  /* Яркость */
  mix-blend-mode: color;       /* Цвет без яркости */
}

/* Классический эффект: текст "вырезает" фон */
.knockout-text {
  mix-blend-mode: multiply;
  color: black;  /* На белом фоне станет прозрачным */
}

background-blend-mode — наложение фонов одного элемента

/* Два фона с наложением */
.duotone {
  background-image:
    linear-gradient(to right, #7b2ff7, #06b6d4),
    url(photo.jpg);
  background-blend-mode: luminosity;
  /* Даёт эффект двухцветной фотографии */
}

Творческие эффекты

Hover с desaturate:

.portfolio-item {
  filter: grayscale(1) brightness(0.8);
  transition: filter 0.3s;
}
.portfolio-item:hover {
  filter: grayscale(0) brightness(1);
}

Неоновое свечение через drop-shadow:

.neon-text {
  filter:
    drop-shadow(0 0 8px #7b2ff7)
    drop-shadow(0 0 20px #7b2ff7)
    drop-shadow(0 0 40px #7b2ff7);
}

Матовое стекло:

.frosted {
  background: rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);  /* Safari */
}

Производительность

filter и backdrop-filter создают stacking context и новый composite layer. blur() — одна из дорогих операций; для производительности ограничивай радиус и площадь элемента.

Примеры

Интерактивный редактор CSS-фильтров с ползунками для каждого параметра

// CSS фильтры — интерактивный редактор
const style = document.createElement('style')
style.textContent = `
  body { font-family: sans-serif; padding: 16px; }
  .editor { display: flex; gap: 16px; flex-wrap: wrap; }
  .target {
    width: 200px; height: 150px;
    background: linear-gradient(135deg, #7b2ff7 0%, #06b6d4 50%, #f59e0b 100%);
    border-radius: 12px;
    flex-shrink: 0;
    transition: filter 0.2s;
  }
  .controls { flex: 1; min-width: 220px; }
  .control-row { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
  .control-row label { width: 110px; font-size: 13px; }
  .control-row input { flex: 1; }
  .control-row span { width: 40px; font-size: 12px; text-align: right; color: #7b2ff7; }
  pre { background: #1a202c; color: #a0aec0; padding: 8px; border-radius: 6px; font-size: 11px; margin-top: 8px; }
`
document.head.appendChild(style)

const editor = document.createElement('div')
editor.className = 'editor'
document.body.appendChild(editor)

const target = document.createElement('div')
target.className = 'target'
editor.appendChild(target)

const controlsDiv = document.createElement('div')
controlsDiv.className = 'controls'
editor.appendChild(controlsDiv)

const filterConfig = [
  { name: 'blur',       unit: 'px',  min: 0, max: 20, step: 0.5, default: 0 },
  { name: 'brightness', unit: '',    min: 0, max: 3,  step: 0.1, default: 1 },
  { name: 'contrast',   unit: '',    min: 0, max: 4,  step: 0.1, default: 1 },
  { name: 'grayscale',  unit: '',    min: 0, max: 1,  step: 0.05, default: 0 },
  { name: 'saturate',   unit: '',    min: 0, max: 4,  step: 0.1, default: 1 },
  { name: 'hue-rotate', unit: 'deg', min: 0, max: 360, step: 5, default: 0 },
]

const values = {}
filterConfig.forEach(cfg => { values[cfg.name] = cfg.default })

const output = document.createElement('pre')

function updateFilter() {
  const parts = filterConfig
    .filter(c => values[c.name] !== c.default)
    .map(c => `${c.name}(${values[c.name]}${c.unit})`)
  const filterStr = parts.length ? parts.join(' ') : 'none'
  target.style.filter = filterStr
  output.textContent = `filter: ${filterStr};`
}

filterConfig.forEach(cfg => {
  const row = document.createElement('div')
  row.className = 'control-row'

  const label = document.createElement('label')
  label.textContent = cfg.name

  const input = document.createElement('input')
  input.type = 'range'
  input.min = cfg.min
  input.max = cfg.max
  input.step = cfg.step
  input.value = cfg.default

  const span = document.createElement('span')
  span.textContent = cfg.default + cfg.unit

  input.addEventListener('input', () => {
    values[cfg.name] = parseFloat(input.value)
    span.textContent = input.value + cfg.unit
    updateFilter()
  })

  row.appendChild(label)
  row.appendChild(input)
  row.appendChild(span)
  controlsDiv.appendChild(row)
})

controlsDiv.appendChild(output)
updateFilter()

CSS фильтры и режимы наложения

Фильтры и blend modes дают CSS-фотошоп прямо в браузере: размытие, обесцвечивание, контраст, наложение слоёв. Без Canvas, без JS-библиотек.

filter — функции фильтрации

/* Базовые функции */
.image {
  filter: blur(4px);              /* Размытие (Gaussian blur) */
  filter: brightness(1.5);       /* Яркость: >1 светлее, <1 темнее */
  filter: contrast(2);           /* Контраст: >1 больше, <1 меньше */
  filter: grayscale(1);          /* 0 = цвет, 1 = ч/б */
  filter: saturate(0.5);         /* 0 = серый, 1 = норма, 2 = насыщенный */
  filter: hue-rotate(90deg);     /* Сдвиг цветового тона */
  filter: invert(1);             /* Инверсия цветов */
  filter: sepia(0.8);            /* Сепия */
  filter: opacity(0.5);          /* Прозрачность (как opacity, но compositing) */
}

/* drop-shadow — тень повторяет форму (в отличие от box-shadow) */
.icon {
  filter: drop-shadow(4px 4px 8px rgba(0,0,0,0.4));
}

/* Комбинирование — применяются слева направо */
.stylized {
  filter: contrast(1.2) brightness(1.1) saturate(1.3);
}

backdrop-filter — фильтр фона

Применяется к содержимому ЗА элементом (не к самому элементу):

/* Glassmorphism — стеклянный эффект */
.glass-card {
  background: rgba(255, 255, 255, 0.15);
  backdrop-filter: blur(12px) saturate(1.8);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 16px;
}

/* Затемнённый модальный фон */
.modal-overlay {
  backdrop-filter: blur(4px) brightness(0.7);
}

mix-blend-mode — наложение на нижние слои

.text-overlay {
  mix-blend-mode: multiply;    /* Умножение — тёмные тона */
  mix-blend-mode: screen;      /* Экран — светлые тона */
  mix-blend-mode: overlay;     /* Наложение — комбо */
  mix-blend-mode: difference;  /* Разница — инверсия */
  mix-blend-mode: luminosity;  /* Яркость */
  mix-blend-mode: color;       /* Цвет без яркости */
}

/* Классический эффект: текст "вырезает" фон */
.knockout-text {
  mix-blend-mode: multiply;
  color: black;  /* На белом фоне станет прозрачным */
}

background-blend-mode — наложение фонов одного элемента

/* Два фона с наложением */
.duotone {
  background-image:
    linear-gradient(to right, #7b2ff7, #06b6d4),
    url(photo.jpg);
  background-blend-mode: luminosity;
  /* Даёт эффект двухцветной фотографии */
}

Творческие эффекты

Hover с desaturate:

.portfolio-item {
  filter: grayscale(1) brightness(0.8);
  transition: filter 0.3s;
}
.portfolio-item:hover {
  filter: grayscale(0) brightness(1);
}

Неоновое свечение через drop-shadow:

.neon-text {
  filter:
    drop-shadow(0 0 8px #7b2ff7)
    drop-shadow(0 0 20px #7b2ff7)
    drop-shadow(0 0 40px #7b2ff7);
}

Матовое стекло:

.frosted {
  background: rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);  /* Safari */
}

Производительность

filter и backdrop-filter создают stacking context и новый composite layer. blur() — одна из дорогих операций; для производительности ограничивай радиус и площадь элемента.

Примеры

Интерактивный редактор CSS-фильтров с ползунками для каждого параметра

// CSS фильтры — интерактивный редактор
const style = document.createElement('style')
style.textContent = `
  body { font-family: sans-serif; padding: 16px; }
  .editor { display: flex; gap: 16px; flex-wrap: wrap; }
  .target {
    width: 200px; height: 150px;
    background: linear-gradient(135deg, #7b2ff7 0%, #06b6d4 50%, #f59e0b 100%);
    border-radius: 12px;
    flex-shrink: 0;
    transition: filter 0.2s;
  }
  .controls { flex: 1; min-width: 220px; }
  .control-row { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
  .control-row label { width: 110px; font-size: 13px; }
  .control-row input { flex: 1; }
  .control-row span { width: 40px; font-size: 12px; text-align: right; color: #7b2ff7; }
  pre { background: #1a202c; color: #a0aec0; padding: 8px; border-radius: 6px; font-size: 11px; margin-top: 8px; }
`
document.head.appendChild(style)

const editor = document.createElement('div')
editor.className = 'editor'
document.body.appendChild(editor)

const target = document.createElement('div')
target.className = 'target'
editor.appendChild(target)

const controlsDiv = document.createElement('div')
controlsDiv.className = 'controls'
editor.appendChild(controlsDiv)

const filterConfig = [
  { name: 'blur',       unit: 'px',  min: 0, max: 20, step: 0.5, default: 0 },
  { name: 'brightness', unit: '',    min: 0, max: 3,  step: 0.1, default: 1 },
  { name: 'contrast',   unit: '',    min: 0, max: 4,  step: 0.1, default: 1 },
  { name: 'grayscale',  unit: '',    min: 0, max: 1,  step: 0.05, default: 0 },
  { name: 'saturate',   unit: '',    min: 0, max: 4,  step: 0.1, default: 1 },
  { name: 'hue-rotate', unit: 'deg', min: 0, max: 360, step: 5, default: 0 },
]

const values = {}
filterConfig.forEach(cfg => { values[cfg.name] = cfg.default })

const output = document.createElement('pre')

function updateFilter() {
  const parts = filterConfig
    .filter(c => values[c.name] !== c.default)
    .map(c => `${c.name}(${values[c.name]}${c.unit})`)
  const filterStr = parts.length ? parts.join(' ') : 'none'
  target.style.filter = filterStr
  output.textContent = `filter: ${filterStr};`
}

filterConfig.forEach(cfg => {
  const row = document.createElement('div')
  row.className = 'control-row'

  const label = document.createElement('label')
  label.textContent = cfg.name

  const input = document.createElement('input')
  input.type = 'range'
  input.min = cfg.min
  input.max = cfg.max
  input.step = cfg.step
  input.value = cfg.default

  const span = document.createElement('span')
  span.textContent = cfg.default + cfg.unit

  input.addEventListener('input', () => {
    values[cfg.name] = parseFloat(input.value)
    span.textContent = input.value + cfg.unit
    updateFilter()
  })

  row.appendChild(label)
  row.appendChild(input)
  row.appendChild(span)
  controlsDiv.appendChild(row)
})

controlsDiv.appendChild(output)
updateFilter()

Задание

Создай страницу с фотогалереей и эффектами CSS-фильтров. По умолчанию изображения (замени цветными блоками) показываются в чёрно-белом виде (`grayscale(1)`). При наведении — полноцветные с яркостью 1.1 и насыщенностью 1.2. Добавь отдельную карточку с эффектом glassmorphism через `backdrop-filter: blur()`.

Подсказка

По умолчанию: `filter: grayscale(1) brightness(0.8)`. При `:hover`: `filter: grayscale(0) brightness(1.1) saturate(1.2)`. Для glassmorphism: `background: rgba(255,255,255,0.1)`, `backdrop-filter: blur(12px)`. Фон страницы тёмный, чтобы эффект стекла был виден.

Загружаем среду выполнения...
Загружаем AI-помощника...