Можно ли применить CSS к половине символа? Хитрый трюк на JavaScript

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Можно ли применить CSS к половине символа? Разбираем хитрый трюк на JavaScript

Вы когда-нибудь задумывались, можно ли покрасить левую половину буквы «А» в красный, а правую — в синий? Или сделать так, чтобы верхняя часть текста была полупрозрачной, а нижняя — нет? Если вы открывали Stack Overflow и задавались вопросом «Is it possible to apply CSS to half of a character?», то вы не одиноки. Этот вопрос собрал тысячи просмотров, а ответ на него — настоящий вызов для веб-разработчика.

На первый взгляд кажется, что CSS работает только с целыми элементами. Но с помощью JavaScript и пары хитростей мы можем обмануть браузер и создать иллюзию «половинчатого» стиля. Сегодня мы разберём три рабочих способа: от простого дублирования текста до использования SVG и clip-path. Поехали!

Почему CSS не может «разрезать» символ?

Прежде чем лезть в код, давайте поймём природу проблемы. CSS оперирует блоками (боксами). Каждый символ — это часть текстового потока, и браузер рендерит его как единое целое. Нет такого свойства half-color или half-background. Даже псевдоэлементы ::before и ::after работают на уровне всего элемента, а не его содержимого.

Но это не значит, что задача нерешаема. Мы можем использовать JavaScript для разделения текста на части и применить стили к каждой половине визуально. Главное — сохранить читаемость и семантику.

Способ 1: Дублирование текста с clip-path (CSS + JS)

Самый популярный трюк, который обсуждают на Stack Overflow — это наложение двух копий текста друг на друга и обрезка каждой половины с помощью clip-path. Давайте реализуем его на JavaScript.

Шаг 1. HTML-структура

<div class="half-text" data-text="Привет, мир!"></div>

Шаг 2. JavaScript-логика

const container = document.querySelector('.half-text');
const text = container.dataset.text;

// Создаём две копии текста
const leftPart = document.createElement('span');
leftPart.textContent = text;
leftPart.className = 'half left';

const rightPart = document.createElement('span');
rightPart.textContent = text;
rightPart.className = 'half right';

container.appendChild(leftPart);
container.appendChild(rightPart);

Шаг 3. CSS-стили

.half-text {
  position: relative;
  font-size: 48px;
  font-weight: bold;
  display: inline-block;
}

.half {
  position: absolute;
  top: 0;
  left: 0;
}

.half.left {
  color: #ff6b6b;
  clip-path: inset(0 50% 0 0); /* левая половина */
}

.half.right {
  color: #4ecdc4;
  clip-path: inset(0 0 0 50%); /* правая половина */
}

Результат: каждая буква разделена ровно посередине. clip-path обрезает символы по вертикальной линии. Трюк идеально работает с моноширинными шрифтами, но для обычных шрифтов может быть небольшое смещение — его легко поправить, добавив letter-spacing: 0.

Способ 2: Разделение текста на символы (продвинутый JS)

Если вам нужно применить стиль не ко всему блоку, а к каждой букве индивидуально (например, верхняя половина «А» — зелёная, нижняя — жёлтая), то придётся работать с каждым символом отдельно. Здесь на помощь приходит JavaScript для стилизации текста.

Идея

Мы разбиваем строку на массив символов, каждый символ помещаем в отдельный <span> и снова дублируем, но уже на уровне букв. Затем применяем clip-path к каждому спану.

function splitTextToHalf(selector) {
  const element = document.querySelector(selector);
  const originalText = element.textContent;
  element.innerHTML = '';

  // Создаём контейнер для каждой буквы
  for (let char of originalText) {
    const wrapper = document.createElement('span');
    wrapper.className = 'char-wrapper';
    wrapper.style.position = 'relative';
    wrapper.style.display = 'inline-block';

    // Левая половина буквы
    const left = document.createElement('span');
    left.textContent = char;
    left.className = 'char-half left';
    left.style.clipPath = 'inset(0 50% 0 0)';
    left.style.position = 'absolute';
    left.style.left = '0';
    left.style.top = '0';
    left.style.color = '#e74c3c';

    // Правая половина буквы
    const right = document.createElement('span');
    right.textContent = char;
    right.className = 'char-half right';
    right.style.clipPath = 'inset(0 0 0 50%)';
    right.style.position = 'absolute';
    right.style.left = '0';
    right.style.top = '0';
    right.style.color = '#3498db';

    wrapper.appendChild(left);
    wrapper.appendChild(right);
    // Сохраняем ширину буквы
    wrapper.style.width = left.offsetWidth + 'px';
    element.appendChild(wrapper);
  }
}

splitTextToHalf('.magic-text');

Этот метод даёт полный контроль. Вы можете анимировать каждую половину, менять цвета при наведении или даже сделать градиентный переход. CSS для половины символа становится реальностью!

Способ 3: SVG и маски — для гиков

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

Пример

<svg width="200" height="100" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <linearGradient id="halfGrad" x1="0%" y1="0%" x2="100%" y2="0%">
      <stop offset="50%" stop-color="#ff6b6b" />
      <stop offset="50%" stop-color="#4ecdc4" />
    </linearGradient>
  </defs>
  <text x="10" y="70" font-size="60" font-family="Arial" fill="url(#halfGrad)">
    Половина
  </text>
</svg>

Градиент обрезается ровно посередине. Минус: текст не выделяется мышью и не интерактивен. Зато код чистый, без дублирования DOM.

Для динамического создания таких SVG из обычного текста можно использовать JavaScript:

function createHalfSVG(text, color1, color2) {
  const svgNS = "http://www.w3.org/2000/svg";
  const svg = document.createElementNS(svgNS, "svg");
  svg.setAttribute("width", text.length * 30);
  svg.setAttribute("height", 100);

  const defs = document.createElementNS(svgNS, "defs");
  const gradient = document.createElementNS(svgNS, "linearGradient");
  gradient.setAttribute("id", "dynamicHalf");
  gradient.setAttribute("x1", "                

Блоги

Рекомендаций по книгам