75

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>

4
  • Have you tried this in Safari on a Mac or Windows system? My experience with safari for windows is that it is exceptionally buggy. Commented Mar 2, 2018 at 9:41
  • I tried this on a Mac Commented Mar 2, 2018 at 9:42
  • Do you get the same result when adding -webkit- tags to your css like here? Commented Mar 2, 2018 at 9:44
  • I'm using autoprefixer in my project so it automatically add every -webkit tags I need Commented Mar 2, 2018 at 9:47

7 Answers 7

161

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;
Sign up to request clarification or add additional context in comments.

5 Comments

One other way to create a new stacking context is by using isolation: isolate; Not supported by IE but is technically more correct. developer.mozilla.org/en-US/docs/Web/CSS/isolation
Which element are you adding this style to?
isolation: isolate; was and fast and easy fix for me.
Apply isolation: isolate; to the element with overflow:hidden property.
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
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>

4 Comments

Worked like a charm for me, thanks! Only pitfall was, that I had to move my box-shadow to another div, but I can live with that ;)
Fantastic answer.
thanks. I'm very confused/curious why this fixes the issue
Thanks for the solution! This overflow bug in iOS was driving me nuts.
26

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

3 Comments

careful tho, the will-change property is not supported by IE at all and Edge earlier versions.
While this code may solve the question, including an explanation 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.
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
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.

Comments

14

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

1 Comment

I found that setting z-index: 0 is enough, and shouldn't have consequences.
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.

Comments

0

.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>

1 Comment

As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.