Можно ли применить 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", "