Веб

Кастомная пунктирная граница в CSS: SVG и градиенты

Как сделать кастомную пунктирную границу в CSS: толщина 12px, длина штриха 90px и удлинённые штрихи в углах. Варианты: SVG, border-image и CSS-градиенты.

Как создать кастомную пунктирную границу для блока в CSS?

Мне нужно реализовать блок с пунктирной обводкой, где:

  • Ширина штриха составляет 12 пикселей
  • Длина штриха равна 90 пикселям
  • В углах блока должен быть более длинный штрих, плавно переходящий с верхней границы на боковую

Какие CSS-свойства и техники можно использовать для создания такой кастомной пунктирной обводки?

Самый надёжный способ получить точную, pixel‑perfect пунктирную обводку — использовать SVG (как background-image или border-image), где можно задать stroke-width: 12px и stroke-dasharray: 90, <gap>, а плавный длинный штрих в углах сделать отдельными SVG‑траекториями или накладываемыми элементами. Если нужна чисто CSS‑реализация — можно использовать несколько linear-gradient/repeating-* на псевдоэлементе и дополнительный оверлей для углов; border-image с SVG даёт гибридный вариант (border image css) между точностью и простотой. Ниже — проверенные шаблоны и пояснения, как настроить длину штриха, толщину и поведение в углах.


Содержание


CSS кастомная пунктирная граница: обзор методов

Коротко — какие варианты есть и за что они отвечают:

  • SVG (inline / data-URL) — максимально гибкий: задаёте stroke-width:12px, stroke-dasharray:90, <gap> и рисуете отдельные paths для длинных штрихов в углах. Лучший выбор для pixel‑perfect и сложных углов. Пример идеи — генератор и трюки с SVG: https://kovart.github.io/dashed-border-generator/
  • Чистый CSS (несколько градиентов на ::before/::after) — удобно и без ресурсов; точно контролирует длину штриха в px, хорошо для адаптивных блоков; углы делаете оверлеями (диагональные градиенты или маленькие SVG в фоне). Смотреть подходы с repeating-conic-gradient/масками: https://css-tip.com/css-dashed-border/
  • border-image с SVG — гибрид: даёт контроль и использует стандартный border-API (border-image-slice, border-image-repeat) — удобно, если хотите, чтобы браузер «рисовал» рамку как border. Документация: https://developer.mozilla.org/ru/docs/Web/CSS/border-image

Дальше — рабочие примеры для ваших требований: толщина штриха 12px, длина штриха 90px, в углах — длинный плавный штрих.


SVG как border-image — точный контроль штриха и углов

Когда нужна точность (12px, 90px) — лучше делать SVG, где вы контролируете каждую траекторию. Ниже — пример для фиксированного блока (проще для точных пикселей). Идея: основной прямоугольник рисуем с stroke-dasharray="90 30", а в местах углов накладываем отдельные paths — длинные штрихи, идущие из верхней границы на боковую.

HTML

html
<div class="card svg-border">Контент</div>

CSS (пример для блока 400×200px)

css
.card {
 width: 400px;
 height: 200px;
 padding: 20px;
 background: #fff;
 box-sizing: border-box;
}

/* SVG в background: stroke-width = 12, dash = 90px, gap = 30px */
.svg-border {
 background-image: url("data:image/svg+xml;utf8,\
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 200' preserveAspectRatio='none'>\
 <rect x='6' y='6' width='388' height='188' fill='none' \
 stroke='%23333' stroke-width='12' stroke-linecap='butt' stroke-linejoin='round' stroke-dasharray='90 30' vector-effect='non-scaling-stroke'/>\
 <!-- corner overlays: каждый path — единый штрих, проходящий через угол -->\
 <path d='M360 6 L394 6 L394 54' fill='none' stroke='%23333' stroke-width='12' stroke-linecap='round' stroke-linejoin='round' stroke-dasharray='120 999' vector-effect='non-scaling-stroke'/>\
 <path d='M6 6 L44 6 L6 44' fill='none' stroke='%23333' stroke-width='12' stroke-linecap='round' stroke-linejoin='round' stroke-dasharray='120 999' vector-effect='non-scaling-stroke'/>\
 <path d='M360 194 L394 194 L394 146' fill='none' stroke='%23333' stroke-width='12' stroke-linecap='round' stroke-linejoin='round' stroke-dasharray='120 999' vector-effect='non-scaling-stroke'/>\
 <path d='M6 194 L44 194 L6 146' fill='none' stroke='%23333' stroke-width='12' stroke-linecap='round' stroke-linejoin='round' stroke-dasharray='120 999' vector-effect='non-scaling-stroke'/>\
</svg>");
 background-repeat: no-repeat;
 background-size: 100% 100%;
}

Пояснения и советы:

  • В data URI цвета # закодированы как %23 (см. %23333). Это нужно для корректной вставки в CSS.
  • stroke-dasharray="90 30" — задаёт длину штриха 90px и промежуток 30px (подставьте желаемый gap).
  • Для длинного штриха в углу я добавил отдельные <path> с большой первой частью dasharray (120 999), чтобы этот путь отрисовывался как единый длинный штрих, проходящий через угол. Такой трюк даёт плавный переход с верхней границы на боковую.
  • Если блок не фиксированного размера, используйте один из вариантов: генерировать SVG динамически с JS под размеры элемента, либо применять viewBox в тех же пикселях, что и размер блока, либо принимать небольшую погрешность.
  • vector-effect="non-scaling-stroke" позволяет сохранять толщину штриха (12px) при масштабировании SVG; без него при растяжении stroke тоже масштабируется.

Плюсы SVG: абсолютный контроль за stroke-width, stroke-dasharray, stroke-linecap, stroke-linejoin. Минусы: чуть больше работы при адаптивной верстке (или требуется генерировать SVG в зависимости от размеров).

См. практику с SVG и dash-параметрами: https://kovart.github.io/dashed-border-generator/ и базовую теорию border-image/SVG: https://developer.mozilla.org/ru/docs/Web/CSS/border-image


Чистый CSS: градиенты + псевдоэлементы (responsive, без файлов)

Если вы хотите обойтись без SVG/файлов — используйте псевдоэлемент с четырьмя линейными градиентами для сторон (точный контроль длины штриха в px) и дополнительным оверлеем для вырезания центра. Для длинного штриха в углах добавьте четыре небольших диагональных градиента, позиционированных в углах.

HTML

html
<div class="box css-dashed">Контент</div>

CSS

css
.box {
 position: relative;
 background: #fff;
 padding: 20px;
 box-sizing: border-box;
}

/* ::before — рисует даши по всем сторонам + corner overlays */
.box::before{
 content: "";
 position: absolute;
 inset: 0;
 pointer-events: none;
 /* параметры */
 --thick: 12px; /* толщина штриха */
 --dash: 90px; /* длина штриха */
 --gap: 30px; /* промежуток */
 /* 4 стороны (top, right, bottom, left) */
 background:
 linear-gradient(90deg, #333 0 calc(var(--dash)), transparent calc(var(--dash)) calc(var(--dash) + var(--gap))) top/100% var(--thick) repeat-x,
 linear-gradient(0deg, #333 0 calc(var(--dash)), transparent calc(var(--dash)) calc(var(--dash) + var(--gap))) right/var(--thick) 100% repeat-y,
 linear-gradient(270deg,#333 0 calc(var(--dash)), transparent calc(var(--dash)) calc(var(--dash) + var(--gap))) bottom/100% var(--thick) repeat-x,
 linear-gradient(180deg,#333 0 calc(var(--dash)), transparent calc(var(--dash)) calc(var(--dash) + var(--gap))) left/var(--thick) 100% repeat-y,
 /* corner overlays: диагональные полосы, длину можно подгонять (здесь 140px) */
 linear-gradient(135deg, #333 0 140px, transparent 140px) top left/140px 140px no-repeat,
 linear-gradient(45deg, #333 0 140px, transparent 140px) top right/140px 140px no-repeat,
 linear-gradient(225deg, #333 0 140px, transparent 140px) bottom right/140px 140px no-repeat,
 linear-gradient(315deg, #333 0 140px, transparent 140px) bottom left/140px 140px no-repeat;
 background-repeat: repeat;
}

/* ::after — «маска» (вырезает центр, оставляя только рамку толщиной --thick) */
.box::after{
 content: "";
 position: absolute;
 top: var(--thick);
 left: var(--thick);
 right: var(--thick);
 bottom: var(--thick);
 background: #fff; /* тот же цвет, что и у блока (или transparent, если нужно) */
 pointer-events: none;
}

Пояснения:

  • Длина штриха --dash и толщина --thick заданы в пикселях — вы получаете точные 12px и 90px.
  • ::before рисует все стороны с повторяющимися градиентами; ::after закрывает внутреннюю область, оставляя только «рамку» заданной толщины.
  • Для длинного штриха в углах я добавил диагональные градиенты, размер и угол которых можно подогнать (значение 140px — ориентир). Это даёт плавный визуальный переход сверху на боковую грань.
  • Подстройка: при скруглённых углах (border-radius) диагональные накладки нужно корректировать (или заменить SVG).

Плюсы: полностью на CSS, responsive, легко менять --dash/--thick. Минусы: сложнее добиться абсолютно ровной векторной кривизны в углах — для идеального результата лучше SVG.

Более продвинутые CSS‑подходы используют repeating-conic-gradient + маски, см. практику: https://css-tip.com/css-dashed-border/


border-image css: использовать SVG как border-image (срезы и углы)

Если хотите, чтобы рамка обрабатывалась браузером как border, используйте border-image с SVG. Идея: подготовить маленький SVG-шаблон (3×3 срезы), где центральные части повторяются вдоль сторон, а уголовые срезы содержат «удлинённые» штрихи.

Пример (упрощённый):

css
.box {
 border: 12px solid transparent; /* ширина рамки = толщина штриха */
 border-image-source: url("data:image/svg+xml;utf8,\
<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120' viewBox='0 0 120 120'>\
 <!-- в центре стороны делаем повторяющуюся полосу с dash 90 -->
 <g fill='none' stroke='%23333' stroke-width='12' stroke-linecap='butt'>\
 <line x1='0' y1='6' x2='120' y2='6' stroke-dasharray='90 30'/>\
 <line x1='6' y1='0' x2='6' y2='120' stroke-dasharray='90 30'/>\
 </g>\
 <!-- в углах — нарисовать большие штрихи в срезах -->\
</svg>");
 border-image-slice: 12; /* отступ для срезов = толщина */
 border-image-repeat: round; /* repeat / round / stretch по вкусу */
 border-image-width: 12;
}

Плюсы:

  • Рамка ведёт себя как border (вёрстка, box-model), вы легко задаёте border-radius и т. п.
  • Corner‑tiles (угловые куски) позволяют держать «длинный» штрих именно в углу.

Минусы:

  • Нужно подготовить корректный SVG‑тайл и правильно установить border-image-slice так, чтобы углы не искажались.
  • Нюансы при масштабировании; иногда удобнее использовать border-image-repeat: round или space.

Документация и разъяснения по свойствам: https://developer.mozilla.org/ru/docs/Web/CSS/border-image


Практические замечания: адаптивность, pixel‑perfect, производительность

  • Pixel‑perfect (точно 90px): проще при фиксированных размерах блока или при генерации SVG под размеры (через JS). В адаптивных макетах либо допускайте относительную длину, либо пересчитывайте dash в runtime.
  • Retina / масштабирование: SVG (вектор) масштабируется чётко; если вы хотите фиксированную толщину в px при масштабировании, используйте vector-effect="non-scaling-stroke".
  • Corner smoothing: для «плавного» перехода штриха на угол удобнее рисовать отдельный path в SVG, который идёт через угол — так вы гарантируете один непрерывный штрих. В чистом CSS чаще делают диагональные/угловые оверлеи.
  • Поддержка браузеров: все современные браузеры понимают градиенты и inline SVG в data-URI; но свойства маски/композитинга (mask-composite) имеют особенности в поддержке (-webkit- префиксы). Всегда делайте fallback: border: 12px dashed #333;.
  • Производительность: inline SVG в background хорошо кешируется, но большие или генерируемые SVG лучше хранить отдельно. Чистый CSS — без сетевых запросов, но с большим количеством градиентов может чуть «нагружать» рендер для сложных страниц.
  • Доступность: рамка остаётся декоративной; если вы используете цвет для состояния (focus) — дополнительно добавьте видимый фокус для клавиатуры (outline или box-shadow), чтобы не полагаться только на цвет.

Источники


Заключение

Для точного контроля толщины (12px), длины штриха (90px) и плавного длинного штриха в углах самый надёжный путь — SVG (использовать как background-image или border-image), где вы явно задаёте stroke-width, stroke-dasharray и дорисовываете corner‑paths. Если нужен чисто CSS‑подход — делайте повторяющиеся линейные градиенты на псевдоэлементе и добавляйте уголковые оверлеи; это гибко и responsive. Выберите SVG для pixel‑perfect и сложных углов, или CSS‑градиенты для простоты и адаптивности.

Авторы
Проверено модерацией
Модерация