В прошлом совете мы разобрали простые случаи. Теперь попробуем собрать такую же кнопку, но с прозрачным фоном.

Для начала восстановим кнопку:

/* html */
        
<button class="button">
  Кнопка
</button>
/* css */

/* Кнопка */
.button {
  height: 60px;
  border: 0;
  font-size: 20px;
  text-transform: uppercase;
  background-image: linear-gradient(
    to right, 
    #45aee5 0%, 
    #6be492 100%
  );
}

Вместо того, чтобы заливать кнопку фоновым цветом, возьмём подходящую маску:

И наложим её на нашу кнопку:

/* css */

.button {
  /* ... */
  mask-image: url("border-mask.svg");
}

У получившейся кнопки две проблемы. Во‑первых, текст стал невидимым, так как он тоже попал под маску. Во‑вторых, при изменении ширины кнопки, рамка деформируется.

Исправим первый недостаток. Для этого вынесем фон на отдельный слой:

/* html */
        
<button class="button">
  <span class="button-background"></span>
  Кнопка
</button>
/* css */

.button {
  /* ... */
  position: relative;
}
        
.button-background {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-image: linear-gradient(
    to right, 
    #45aee5 0%, 
    #6be492 100%
  );
}

Чтобы исправить второй недостаток, придётся повозиться и вспомнить времена олдскульного скругления уголков.

Распилим нашу маску на три части:

И применим все три маски:

/* css */
        
.button-background {
  mask-image: url("border-left.svg"), 
    url("border-right.svg"),
    url("border-center.svg");
  mask-position: center left, center right, center center;
  mask-repeat: no-repeat, no-repeat, repeat-x;
  mask-size: contain, contain, contain;
}

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

/* html */
        
<button class="button">
  <span class="button-sides"></span>
  <span class="button-center"></span>
  Кнопка
</button>
/* css */
        
.button-sides {
  /* ... */
  mask-image: url("border-left.svg"), url("border-right.svg");
  mask-position: center left, center right;
  mask-repeat: no-repeat, no-repeat;
  mask-size: contain, contain;
}

.button-center {
  /* ... */
  left: 30px;
  right: 30px;
  mask-image: url("border-center.svg");
  mask-position: center;
  mask-repeat: repeat-x;
  mask-size: contain;
}

Центральная часть на месте. Но, если присмотреться, то видно, что градиент у центральной части рамки начинается не с того оттенка:

Дело в том, что ширина центральной части уже, чем ширина самой кнопки. Это становится заметнее, если убрать маску:

Чтобы это победить, растянем фон центральной части так, чтобы он по длине совпадал с кнопкой. Для этого перенесём фон на псевдоэлемент и вытянем его влево и вправо:

/* css */
        
.button-center {
  /* ... */
  left: 30px;
  right: 30px;
  mask-image: url("border-center.svg");
  mask-position: center;
  mask-repeat: repeat-x;
  mask-size: contain;
  background: none;
}

.button-center::before {
  position: absolute;
  top: 0;
  bottom: 0;
  right: -30px;
  left: -30px;
  background-image: linear-gradient(
    to right, 
    #45aee5 0%, 
    #6be492 100%
  );
  content: '';
}

Готово. Если вы знаете, как сделать такую кнопку проще, пишите в комментарии.

P. S. Это был совет о веб‑разработке. Хотите знать всё о коде, тестах, фронтенд‑разработке, цеэсэсе, яваскрипте, рельсах и джейде? Присылайте вопросы.

Веб‑разработка
Отправить
Поделиться
Запинить

Комментарии

Могу предложить следующий вариант:

<svg width="0" height="0">
  <linearGradient id="gradient" x1="0" x2="1" y1="0" y2="0">
    <stop offset="0"/>
    <stop offset="1"/>
  </linearGradient>
  <symbol id="border" overflow="visible">
    <rect width="100%" height="100%" rx="30px" ry="30px"/>
  </symbol>
</svg>
<button class="button">
  <svg class="button__border"><use href="#border"/></svg>
  Кнопка
</button>

.button {
  position: relative;
  height: 60px;
  border: 0;
  background: transparent;
}
​
.button__border {
  position: absolute;
  top: 0;
  left: 0;
  overflow: visible;
  width: 100%;
  height: 100%;
  fill: none;
  stroke: url(#gradient);
  stroke-width: 4px;
}
​
#gradient stop:nth-child(1) {
  stop-color: #45aee5;
}
​
#gradient stop:nth-child(2) {
  stop-color: #6be492;
}
17 янв 2019

Можно обойтись без масок и отдельных ресурсов: https://codepen.io/wingerie/pen/qLGOea

17 янв 2019

Радомир, ваш вариант совпадает с описанным в прошлом совете:
https://bureau.ru/soviet/20190103/

Это решение работает только в случае, когда фон заранее известен. Если добавить случайный фон к вашему решению, получится так:

17 янв 2019

Рекомендуем другие советы