71

I have to make a button with a ::before hidden which shows on :hover. This animation is working great on Chrome, IE and Firefox, but i have a weird issue on Safari.

Overflow:hidden is working but without the border radius.

You should run the fiddle in safari to see this issue.

Thanks !

.btn{
  border-radius: 3rem;
  cursor: pointer;
  display: inline-block;
  font-size: 15px;
  font-weight: 400;
  font-family: arial;
  overflow: hidden;
  position: relative;
  padding: 0.8rem 2.5rem;
  text-decoration: none;
  }

.btn-primary{
  background-color: blue;
  border-color: blue;
  color: white;
}

.btn-primary::before{
  background-color: deeppink;
  border-radius: 50%;
  content: '';
  color: white;
  height: 100%;
  left: 100%;
  margin: 0;
  position: absolute;
  top: 0;
  transform-origin: 100% 50%;
  transform: scale3d(1, 1.4, 1);
  transition: all 300ms cubic-bezier(0.7,0,0.9,1);
  width: 20%;
}

.btn-primary:hover::before{
  transform: scale3d(1, 5, 1);
  width: 110%;
  left: -2%;
  z-index: 0;
}

.btn-primary span{
  position: relative;
  z-index: 1;
}
<a href="#" class="btn btn-primary">
  <span>Button primary</span>
</a>
Victor Allegret
  • 2,344
  • 3
  • 18
  • 31

6 Answers6

158

The accepted answer works, but indeed it removes the box shadow. A comment I saw in this github post says that it can be also fixed by creating a new stacking context (kind of moving an element into a new painting layer). That can be achieved with a small hack like

transform: translateZ(0)

In my case, both overflow and box-shadow are working with this solution.

UPD: just like @JadHaidar suggested in the comments isolation is a property specifically for working with the stacking context:

isolation: isolate;
starball
  • 20,030
  • 7
  • 43
  • 238
Blind Despair
  • 3,190
  • 2
  • 20
  • 31
  • 7
    One other way to create a new stacking context is by using `isolation: isolate;` Not supported by IE but is technically more correct. https://developer.mozilla.org/en-US/docs/Web/CSS/isolation – Jad Haidar Oct 28 '21 at 20:47
  • Which element are you adding this style to? – Cully Jan 13 '22 at 17:30
  • 8
    `isolation: isolate;` was and fast and easy fix for me. – Des Aug 08 '22 at 06:52
  • Apply isolation: isolate; to the element with overflow:hidden property. – oomer Oct 06 '22 at 18:31
  • `isolation: isolate;` fixed my similar issue - very interesting! Could someone explain or provide some docs related to stacking order and how this fixes the issue? I'd love to know – Lushawn May 27 '23 at 10:50
57

So I found a little hack to fix this issue on https://gist.github.com/ayamflow/b602ab436ac9f05660d9c15190f4fd7b

Just add this line to your element with overflow :

-webkit-mask-image: -webkit-radial-gradient(white, black);

Let me know if someone find another solution :)

.btn{

  /* Add this line */
  -webkit-mask-image: -webkit-radial-gradient(white, black);

  border-radius: 3rem;
  cursor: pointer;
  display: inline-block;
  font-size: 15px;
  font-weight: 400;
  font-family: arial;
  overflow: hidden;
  position: relative;
  padding: 0.8rem 2.5rem;
  text-decoration: none;
  }

.btn-primary{
  background-color: blue;
  border-color: blue;
  color: white;
}

.btn-primary::before{
  background-color: deeppink;
  border-radius: 50%;
  content: '';
  color: white;
  height: 100%;
  left: 100%;
  margin: 0;
  position: absolute;
  top: 0;
  transform-origin: 100% 50%;
  transform: scale3d(1, 1.4, 1);
  transition: all 300ms cubic-bezier(0.7,0,0.9,1);
  width: 20%;
}

.btn-primary:hover::before{
  transform: scale3d(1, 5, 1);
  width: 110%;
  left: -2%;
  z-index: 0;
}

.btn-primary span{
  position: relative;
  z-index: 1;
}
<a href="#" class="btn btn-primary">
  <span>Button primary</span>
</a>
Victor Allegret
  • 2,344
  • 3
  • 18
  • 31
24

will-change: transform; on element with overflow: hidden; solved issue for me

  • 1
    careful tho, the will-change property is not supported by IE at all and Edge earlier versions. – Alex Feb 19 '20 at 15:17
  • 4
    While this code may solve the question, [including an explanation](//meta.stackexchange.com/q/114762) of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please [edit] your answer to add explanations and give an indication of what limitations and assumptions apply. – double-beep Feb 19 '20 at 15:31
  • 3
    I believe the crux of all these answers is they bump the div into a new layer (i.e. `transform: translateZ(0)`) and for some reason that achieves the desired effect on Safari – Dmitry Minkovsky Feb 29 '20 at 15:06
22

This is caused by one of several unresolved bugs in WebKit, the rendering engine used by Safari:

As Simon Fraser writes in the second link:

You can work around it in recent builds by making the element with overflow:hidden into a stacking context (e.g. position:relative, z-index:0).

This is probably the simplest solution since, unlike some of the other answers here, it does not unnecessarily introduce render layers.

Dmitry Minkovsky
  • 36,185
  • 26
  • 116
  • 160
14

For me, adding a high z-index setting to the item with the border-radius, was enough to fix the problem.

jorisw
  • 875
  • 1
  • 11
  • 17
0

You can use any of these on your parent component:

clip-path: inset(0 0 round 50%);
clip-path: inset(0 0 round 3rem);
clip-path: inset(0 0 round 20px);

Clip-path is considered partially supported nowadays, but that applies to full specification, which has a lot of functionality. Specifically inset should be supported widely.

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Oleksandr Leskiv
  • 539
  • 5
  • 10