This is a read-only archive of the Framer Community on Facebook.

What is Framer? Join the Community
Return to index
Ed Chao
Posted Jul 30 - Read on Facebook

Anyone else having trouble keeping the borderRadius when trying to clip sublayers? It looks like you can only clip sublayers within a square corner. (borderRadius only seems to work on the layer its assigned to. I know that I can add the borderRadius to the actual sublayer, but that doesn't work if there are moving sublayers all being masked by the superLayer, like a carousel.)

31 Comments

Jens Nikolaus

Just add borderRadius: '8px 8px 0 0' to the sublayer

Stephen Crowley

Jens Nikolaus: Bottom, Top, Right, Left? not TRBL?

Jens Nikolaus

I assumed he wanted to round the top left and top right corners. So yes, it’s TRBL

Stephen Crowley

Ah, cool. Thanks for clarifying for me.

Benjamin Den Boer

I've run into some similar issues a while ago - in my case, it turned out to be a CSS bug, which may be the case here too. (Divs within divs not properly clipping with border-radius applied)

Ed Chao

Jens Nikolaus yes adding borderRadius to the actual sublayer would work, however if you're trying to mask a series of moving sublayers, for example a carousel, then it won't.

Ed Chao

Benjamin Den Boer were you able to achieve a fix? I would be very curious to see how you did it.

Aaron Carámbula

+1 Would love for this to be fixed.

Benjamin Den Boer

Ed Chao Unfortunately not, I recreated the issue in plain HTML/CSS and was unable to fix it..

Ed Chao

ah. the tragedy that is our lives.

Ninh Bui

Ed would you be able to post the emitted html/css somewhere? I've been able to reproduce it by hand, and after diving into the framer source, I think the culprit is translate3d webkit-transform which assumes imageLayer is on a higher z-axis value I think by natural nesting. Could you add a z property in the imageLayer, and set it to -1 to combat this? That is: "z: -1". I'm unfortunately not a framer user yet, so had to handroll some html/css to try to reproduce this based on the info from your screenshot. Please see below and beneath that for the -1 version which seems to fix it.

<!DOCTYPE html>
<html>
<head>
<title>Layer test</title>

<style type="text/css">
body {
position: relative;
background-color: black;
margin: 0;
padding: 0;
}

#myLayer {
position: absolute;
-webkit-transform: translate3d(20px, 40px, 0);
width: 200px;
height: 200px;
border-radius: 8px;
background-color: #fff;
overflow: hidden;
}

#imageLayer {
position: absolute;
-webkit-transform: translate3d(0, 0, 0);
width: 800px;
height: 100px;
background-color: #e9e9e9;
}
</style>

</head>
<body>

<div id="myLayer">
<div id="imageLayer"></div>
</div>

</body>
</html>

And now with a -1 z-axis argument to make it respect clipping:
<!DOCTYPE html>
<html>
<head>
<title>Layer test</title>

<style type="text/css">
body {
position: relative;
background-color: black;
margin: 0;
padding: 0;
}

#myLayer {
position: absolute;
-webkit-transform: translate3d(20px, 40px, 0);
width: 200px;
height: 200px;
border-radius: 8px;
background-color: #fff;
overflow: hidden;
}

#imageLayer {
position: absolute;
-webkit-transform: translate3d(0, 0, -1);
width: 800px;
height: 100px;
background-color: #e9e9e9;
}
</style>

</head>
<body>

<div id="myLayer">
<div id="imageLayer"></div>
</div>

</body>
</html>

It's a bit of a dirty fix, I admit. Maybe you want to make use of translate (for 2d) if you don't plan on doing 3d translations which fixes the problem as well: don't forget to omit the third z-axis parameter then. I see that there is a code path in framer to have translate be emitted instead of translate3d if the _prefer2d property of a layer is set to true and its z-index is 0. I don't see a documented way of setting this property however and the prefix makes me think this is intended to be a private property. See also: https://github.com/koenbok/Framer/blob/master/framer/LayerStyle.coffee#L106

Ed Chao

huge. im on it. (that photo. nobody told me koen was a GQ model)

Ninh Bui

Ed woops, haven't had my coffee yet, meant to say, add a z property to #imageLayer and set it to -1 instead of index. So

imageLayer = new Layer
#yadayadayada
z: -1

Ed Chao

Alright, so heres something funny.

this hack works because it omits "px" from the -1:
-webkit-transform: translate3d(0, 0, -1);

but you can't do that from the framer coffeescript, because you'll note that in the framer source it says: css.push "translate3d(#{layer.x}px,#{layer.y}px,#{layer.z}px)"

so "px" is always added.

Thomas Aylott

That design is actually pretty difficult to achieve with high-performance anywhere with native code or web code.

Applying a mask or rounded corners to some complex layers like this forces it to be calculated on the CPU instead of the GPU which loses hardware acceleration and has a really bad hit on battery life and makes it really difficult to have a nice smooth 60 FPS animation.

What I've done in the past is fake it by making the rounded corners a layer on top and keeping that still and just moving the layer underneath. The problem with that technique is that you lose the ability to have dynamic graphics behind the rounded corner layer. For most designs, that isn't a problem

Ninh Bui

Ed can you try:

imageLayer = new Layer
#yadayada
z: 0

imageLayer._prefers2d = true

If this works, it'll probably have some perf. implications as I think it'll go over the CPU instead of GPU as Thomas Aylott has pointed out.

Ed Chao

Thomas Aylott I was under the impression that using translate3d forces hardware acceleration?

Ninh Bui

Ed I think having the third argument being -1 is invalid according to the spec, and it should be -1px or 1em etc... that is, in a valid length value. -1 probably accidentally triggered it to use translate over translate3d, which also seems to "fix" the problem, but comes at the cost of it likely going over the CPU instead of GPU. I'd need to dive into the webkit code to look into that, and would normally be happy to do so, but don't have the time :(

Could you let me know if the _prefers2d method "works"? I'm curious at the FPS in particular.

Thomas Aylott
Ed Chao

Ninh Bui ah. Makes sense. Well I've been fiddling with it, but it doesn't seem to force framer to emit translate2d instead of translate3d.

Ed Chao

Thomas Aylott thanks for the article

Ninh Bui

Ed sorry, typo, meant prefer2d instead of prefers2d.

Ed Chao

tried both, no bueno. (which is weird bc I see that little note in the framer source)

Thomas Aylott

Long story short, the GPU only knows about rectangles. It can really quickly animate position and 3d transform and rotation and scale and opacity of rectangles. But the GPU doesn't know anything about rounded corners. That needs to be done on the CPU.

So, if you want to apply a rounded corners clipping mask to the child layers of a parent layer, the only way to make it work (in JS or Objective-C or Java or anything else) the only choice is to do it on the CPU. With HTML5 that means you need to disable hardware acceleration on the child layers if you want them to get that rounded corners clipping mask

Ed Chao

thanks for that insight Thomas Aylott I guess meanwhile we'll have to fake it

Thomas Aylott

Here's the part where he explains this specific stuff… http://youtu.be/gTHAn-nkQnI?t=15m27s

Thomas Aylott

FramerJS was built to take advantage of how the GPU functions in order to give you the best perf by default. I'm not sure if FramerJS has the equivalent of Apple's `shouldRasterize`, but maybe it should.

#FeatureRequest Implement Layer shouldRasterize to disable hardware accelleration for child layers. cc Koen Bok

Koen Bok

Thomas is exactly right. To get this effect you need to take a different (slower) rendering path.

I was playing with this myself and added _prefers2d to layers to not use 3d stuff:
https://github.com/koenbok/Framer/blob/master/framer/Layer.coffee#L61
https://github.com/koenbok/Framer/blob/master/framer/LayerStyle.coffee#L96

So if you apply this to a layer (and/or sublayers) you can get it to work, but it will be very slow:

myLayer. _prefers2d = true
myLayer.x = myLayer.x # To trigger re-render, sorry.

I'll try to come up with a nicer way to do this and some documentation in the future.

Koen Bok

Bonus to Ninh for finding it :-)

Ed Chao

ah. myLayer.x = myLayer.x thanks Koen Bok

Read the entire post on Facebook