CSS внутри Shadow DOM

Shadow DOM создаёт изолированное дерево элементов внутри веб-компонента, обеспечивая локальный контекст для разметки и стилей. В библиотеке Atomico работа со Shadow DOM является встроенной и естественной частью создания компонентов.

Определение стилей внутри компонента

В Atomico стили задаются с помощью функции css из пакета библиотеки. Это позволяет писать CSS прямо внутри компонента, а библиотека автоматически внедряет их в Shadow DOM:

import { c, css } from "atomico";

const styles = css`
    :host {
        display: block;
        font-family: sans-serif;
        color: #333;
    }

    button {
        background: #007acc;
        border: none;
        color: white;
        padding: 0.5em 1em;
        cursor: pointer;
        border-radius: 4px;
        transition: background 0.3s ease;
    }

    button:hover {
        background: #005fa3;
    }
`;

function MyButton() {
    return (
        <host>
            <button>Click me</button>
        </host>
    );
}

MyButton.styles = styles;

export default c(MyButton);

Ключевые моменты:

  • :host — селектор, который обращается к корневому элементу компонента. С его помощью можно задавать базовые стили самого компонента.
  • Стили автоматически применяются только внутри Shadow DOM компонента. Они не затрагивают глобальные элементы страницы.
  • Hover, focus и другие псевдоклассы работают в пределах Shadow DOM без конфликтов с внешними стилями.

Инкапсуляция и каскадирование

Shadow DOM обеспечивает полную инкапсуляцию стилей. Любые CSS-правила, определённые внутри компонента, не воздействуют на внешние элементы, и наоборот.

const inputStyles = css`
    input {
        border: 1px solid #ccc;
        padding: 0.5em;
        border-radius: 2px;
        outline: none;
        transition: border-color 0.2s;
    }

    input:focus {
        border-color: #007acc;
    }
`;

function TextInput() {
    return (
        <host>
            <input placeholder="Введите текст" />
        </host>
    );
}

TextInput.styles = inputStyles;

export default c(TextInput);

Особенности:

  • Любые глобальные CSS-правила не могут переопределить стили внутри Shadow DOM.
  • Псевдоэлементы ::before и ::after работают только внутри компонента, если определены локально.
  • Использование переменных CSS (--variable) позволяет передавать стили из внешнего контекста внутрь Shadow DOM через :host.

Работа с CSS-переменными

Atomico позволяет сочетать Shadow DOM и CSS-переменные для гибкой кастомизации компонентов:

const cardStyles = css`
    :host {
        display: block;
        padding: var(--card-padding, 1em);
        background-color: var(--card-bg, #f9f9f9);
        border-radius: var(--card-radius, 8px);
        box-shadow: 0 2px 6px rgba(0,0,0,0.1);
    }

    h2 {
        margin: 0 0 0.5em 0;
        font-size: 1.2em;
    }

    p {
        margin: 0;
        font-size: 0.9em;
    }
`;

function Card({ children }) {
    return (
        <host>
            {children}
        </host>
    );
}

Card.styles = cardStyles;

export default c(Card);

Выводы по CSS-переменным:

  • Значения переменных можно менять извне, используя стандартные селекторы для кастомных свойств.
  • Shadow DOM сохраняет инкапсуляцию, но позволяет компоненту адаптироваться под внешний стиль через переменные.

Scoped анимации и ключевые кадры

Анимации можно задавать напрямую в Shadow DOM, что предотвращает конфликты с глобальными анимациями:

const fadeInStyles = css`
    @keyframes fadeIn {
        from { opacity: 0; }
        to { opacity: 1; }
    }

    :host {
        display: block;
        animation: fadeIn 0.5s ease-out;
    }
`;

function FadeBox() {
    return (
        <host>
            <div>Анимированный блок</div>
        </host>
    );
}

FadeBox.styles = fadeInStyles;

export default c(FadeBox);
  • Ключевые кадры (@keyframes) объявленные внутри Shadow DOM не конфликтуют с глобальными анимациями.
  • Каждая анимация полностью локальна и применяется только к элементам внутри компонента.

Динамические стили

Atomico позволяет создавать динамические стили с помощью функции css и шаблонных литералов:

const buttonStyles = (color) => css`
    button {
        background: ${color};
        border: none;
        padding: 0.5em 1em;
        color: white;
        border-radius: 4px;
        cursor: pointer;
    }
`;

function ColoredButton({ color }) {
    return (
        <host>
            <button>Нажми меня</button>
        </host>
    );
}

ColoredButton.styles = (props) => buttonStyles(props.color);

export default c(ColoredButton);

Особенности динамических стилей:

  • Возможность менять CSS по свойствам компонента (props).
  • Стили остаются внутри Shadow DOM и не создают глобальных конфликтов.
  • Поддерживаются любые CSS-правила, включая медиазапросы и псевдоклассы.

Медиазапросы и адаптивность

Shadow DOM полностью поддерживает медиазапросы, позволяя делать адаптивные компоненты:

const responsiveStyles = css`
    :host {
        display: block;
        padding: 1em;
    }

    div {
        background: #eee;
        padding: 1em;
    }

    @media (max-width: 600px) {
        div {
            background: #ddd;
        }
    }
`;

function ResponsiveBox() {
    return (
        <host>
            <div>Контент</div>
        </host>
    );
}

ResponsiveBox.styles = responsiveStyles;

export default c(ResponsiveBox);
  • Медиазапросы работают внутри Shadow DOM без дополнительных настроек.
  • Адаптивные изменения стилей не влияют на другие компоненты.

Итоговые особенности CSS в Atomico с Shadow DOM

  1. Полная изоляция стилей и элементов компонента.
  2. Поддержка всех стандартных CSS-селекторов и псевдоклассов.
  3. Работа с CSS-переменными для внешней кастомизации.
  4. Локальные анимации и ключевые кадры.
  5. Возможность динамического изменения стилей через props.
  6. Поддержка медиазапросов и адаптивного дизайна.

Эти возможности делают Shadow DOM в Atomico мощным инструментом для создания модульных и полностью инкапсулированных компонентов с гибкой стилизацией.