Как сделать составную границу блока: solid и dashed

    При создании пошаговых интерфейсов часто требуется визуально отображать прогресс с помощью границы блока. Например, часть рамки должна быть сплошной (solid), а остальная - пунктирной (dashed). Стандартное свойство border не позволяет комбинировать разные стили в одной линии. Однако эту задачу можно решить с помощью CSS-градиентов и псевдоэлементов. Рассмотрим рабочий способ.

    Проблема комбинирования стилей границы

    Свойство border-style принимает только одно значение для каждой стороны. Нельзя напрямую указать, что левая половина верхней границы - solid, а правая - dashed. Это ограничение обходят с помощью наложения слоёв: один элемент отвечает за сплошную часть, другой - за пунктирную.

    Решение: CSS-градиент + маска

    Используем background-image с линейным градиентом и свойство mask для создания составной рамки. Алгоритм:

    • Создаём сплошную границу через border: solid на самом блоке.
    • Накладываем пунктирную границу через псевдоэлемент ::after или ::before с border-style: dashed.
    • Обрезаем пунктирную часть с помощью mask-image с градиентом, который скрывает её в области, где уже есть solid.

    Пример кода

    .progress-border {
    position: relative;
    width: 300px;
    height: 200px;
    border: 4px solid #3498db; /* сплошная граница по умолчанию */
    }
    .progress-border::after {
    content: '';
    position: absolute;
    top: -4px; left: -4px;
    width: 100%; height: 100%;
    border: 4px dashed #3498db; /* пунктирная граница */
    pointer-events: none;
    mask-image: linear-gradient(to right, transparent 50%, black 50%);
    mask-size: 100% 100%;
    -webkit-mask-image: linear-gradient(to right, transparent 50%, black 50%);
    }

    В этом примере пунктирная граница видна только на правой половине блока (начиная с 50% ширины). Меняя процент в градиенте, вы управляете точкой перехода от solid к dashed.

    Динамическое заполнение в зависимости от шага

    Чтобы обновлять границу при изменении шага, используйте JavaScript для изменения значения в маске. Например, сохраняйте процент прогресса в CSS-переменной --progress и обновляйте её:

    .progress-border::after {
    mask-image: linear-gradient(to right, transparent var(--progress), black var(--progress));
    -webkit-mask-image: linear-gradient(to right, transparent var(--progress), black var(--progress));
    }

    Теперь вы можете задавать --progress: 30% для отображения 30% сплошной границы и 70% пунктирной.

    Альтернативный подход: два вложенных блока

    Если нужно поддерживать более старые браузеры без mask, используйте вложенные элементы:

    • Внешний блок имеет пунктирную границу.
    • Внутренний блок - сплошную, ширина которого равна проценту прогресса.
    • Внутренний блок перекрывает часть пунктира, создавая иллюзию составной границы.

    Этот метод проще, но требует дополнительной разметки.

    Заключение

    Составная граница из solid и dashed реализуется с помощью CSS-масок или наложения блоков. Выберите способ в зависимости от требуемой поддержки браузеров. Для современных проектов используйте mask-image - он гибкий и не загромождает HTML.

    Часто задаваемые вопросы