When working with view objects you are going to be constantly dealing with how to position them within your web application. And in SproutCore, positioning views is kind of but not exactly like positioning elements in a typical web page using CSS. With views, you are going to be thinking about where a view is anchored within its parent view, what it’s relative position is to where the view is anchored, and its size.
To get a basic idea of just how SproutCore positions views, it’s best to work with a simple application. Start by first creating a new SproutCore application called layout by running the following command:
sc-init layout
Now run your application just to make sure everything is working as expected. Do this by running the following command within the layout directory created for you by sc-init:
sc-server
If everything went okay, you should be able to open up your favorite browser and go to http://localhost:4020/layout and see the screen shown below:

Okay, great. Now, to make it obvious just how the views are being positioned, we need to modify the look of the views. We will do this by creating a new CSS file called layout.css and placing it in the layout/apps/layout/english.lproj directory. In the CSS file enter the following:
h1 {
border-style: solid;
border-width: 1px;
border-color: red;
background-color: white;
}
Awesome. If you refresh your browser you should get the following:

Now open up the main_page.js file located in the layout/apps/layout/english.lproj directory. This file is where you typically setup the views. You should see the following code (excluding comments):
Layout.mainPage = SC.Page.design({
mainPane: SC.MainPane.design({
childViews: 'labelView'.w(),
labelView: SC.LabelView.design({
layout: { centerX: 0, centerY: 0, width: 100, height: 18 },
tagName: "h1", value: "Hello World"
})
})
});
You’ll notice that there is a SC.LabelView object that is being setup within a SC.MainPane object. The main pane is the parent view of the label view. This parent-child view relationship is important in how the views get positioned by SproutCore. In the label view, the part we care about is the layout property. By default, the label is centered in the middle of the parent view (centerX: 0, centerY: 0), and its width is 100 pixels and height is 18 pixels. Let’s update the code so that the label view is called labelView1 and its value is “Label View 1”. In addition, let’s add two more label views called labelView2 and labelView3. We’ll position labelView2 so that it is positioned in the top-left corner of the pane and labelView3 is position in the bottom-right corner. The code should be the following:
Layout.mainPage = SC.Page.design({
mainPane: SC.MainPane.design({
childViews: 'labelView1 labelView2 labelView3'.w(),
labelView1: SC.LabelView.design({
layout: { centerX: 0, centerY: 0, width: 100, height: 18 },
tagName: "h1",
value: "Label View 1"
}),
labelView2: SC.LabelView.design({
layout: { left: 0, top: 0, width: 100, height: 18 },
tagName: "h1",
value: "Label View 2"
}),
labelView3: SC.LabelView.design({
layout: { bottom: 0, right: 0, width: 100, height: 18 },
tagName: "h1",
value: "Label View 3"
})
})
});
So if you save your file and then reload your browser you should see the following:

Label views 1, 2 and 3 are all children of the main pane and as such SproutCore will do all the necessary work to make sure the views are positioned correctly. Note that although we are just using label views to understand how views are positioned, this still applies for most of the other views in SproutCore framework.
As of now, all the views have been given an absolute width and height, but that doesn’t have to be the case. In fact, let’s change our views so that the second label view and the third label view stretch out across the top and bottom of the browser window. Update the layout of the second and third label views to be the following:
...
labelView2: SC.LabelView.design({
layout: { left: 0, top: 0, height: 18 },
tagName: "h1",
value: "Label View 2"
}),
labelView3: SC.LabelView.design({
layout: { bottom: 0, right: 0, height: 18 },
tagName: "h1",
value: "Label View 3"
})
...
Save the file and refresh your browser. You should get the following:

Huh. So by removing the width from each layout that informed SproutCore to stretch the views horizontally. Cool. Well, what about the first label view. How about if we would like to fill in the all the vacant space in the middle of the window instead of just sitting lonely in the middle. Let’s update the layout property of label view 1 to be the following:
...
labelView1: SC.LabelView.design({
layout: { left: 0 },
tagName: "h1",
value: "Label View 1"
}),
...
If you save your file and reload your browser you’ll end up getting the following:

What the? Somethings not right! You’ll notice that the middle of the window is now all white, but no where do you see the text “Label View 1”. This doesn’t seem to make any sense. Actually it does. SproutCore followed your layout instructions and made label view 1 fill up the entire window, but label view 1 is partly hidden behind label view 2 and 3 because of the how the views have been layered. Go back to the code for a second. In the main pain you see a line of code reads the following:
childViews: ‘labelView1 labelView2 labelView3’.w(),
Because of the ordering, SproutCore is instructed to first render labelView1 as HTML and then render label views 2 and 3 as HTML. In reality, SproutCore is just consecutively placing the views as HTML one at a time and the browser uses its default CSS styling rules to layer the elements as normally does. So SproutCore is making use of the web browser to position and layer the element accordingly. Great. So what if we were to reorder to the main pane’s children to be the following:
childViews: ‘labelView2 labelView3 labelView1’.w(),
We’ll get the following screen:

Yay! We now see label view 1… er, wait, now label view 2 and 3 are no longer visible. Actually, they are there but because of the browser layers the HTML elements labels 2 and 3 are hidden behind label view 1. D’oh. Well then how do we get all three label views to appear correctly so that they aren’t overlapping each other? Turns out we have to do a little finessing with the positioning of label view 1. Notice how label view 2 and label view 3 each have a height of 18 pixels? Well that tells us that we have to shrink the height of label view 1 based on the other views’ size. Update label view 1’s layout property to be the following:
layout: { left: 0, top: 18, bottom: 18 }
Now save and refresh your browser. You should get the following:

Yes! We finally got all three label views to be correctly visible. Basically, we told SproutCore to push label view 1 down from the top of the parent view (main pane) by 18 pixels and push it up from the bottom of the parent view by 18 pixels. This means we have to be mindful of both where a view is anchored and its size and position relative to the other sibling views within the same parent view.
Okay, this is great stuff. But we aren’t done just yet. Remember that it is important to know that the position of a view is based on the parent-child relationship. So let’s look at a bit more of a complex example where we place one view inside of another view instead of just in the main pane. We are going to add a generic view (a SC.View object) to our pane and put label view 1 inside of it. Update your code so that it is the following:
Layout.mainPage = SC.Page.design({
mainPane: SC.MainPane.design({
childViews: 'plainView labelView2 labelView3'.w(),
plainView: SC.View.design({
childViews: 'labelView1'.w(),
layout: { centerX: 0, centerY: 0, width: 200, height: 200 },
classNames: ['plainView'],
labelView1: SC.LabelView.design({
layout: { left: 0, centerY: 0, width: 100, height: 18 },
tagName: "h1",
value: "Label View 1"
})
}),
labelView2: SC.LabelView.design({
layout: { left: 0, top: 0, height: 18 },
tagName: "h1",
value: "Label View 2"
}),
labelView3: SC.LabelView.design({
layout: { bottom: 0, right: 0, height: 18 },
tagName: "h1",
value: "Label View 3"
})
})
});
Our generic view is called plainView and labelView1 is now a child of it. We positioned label view 1 so that it will be placed left of center of the plain view. We also need to update our CSS file to be the following:
h1, .plainView {
border-style: solid;
border-width: 1px;
border-color: red;
background-color: white;
}
Finally, save all files and refresh the browser. You should get the following:

Boo-ya! We see that label view 1 is indeed positioned relative to the parent view’s boundaries. Go ahead and resize the window. Everything works as expected. Again, SproutCore is doing the rendering into HTML so that the browser at the end will correctly place all the elements according to its CSS rules. Check out the HTML source. You’ll see how everything is setup just so by SproutCore in order to give us the right look and feel.
So there ya are. While this was a basic look at how views are positioned, I hope it helped those new to the framework get a better grip of just how views are actually positioned in SproutCore. If you interested in more layout details you can dig through the view.js file’s comments located in the frameworks/foundation/views folder in the SproutCore root directory. Around line 1456 there is some decent comments on all the various layout attributes and how they can be combined together.
Excellent post,
One thing to note is that if you wish to circumvent the default ‘absolute’ positioning of views in SC, you can set ‘useStaticLayout: YES’ in your view which will enable you to position it with CSS.
Although not often used, it can be useful for elements where you have unknown heights/widths and need a much more tigher ‘flow’ of layout. (although SC even has a StackedView to cover collection scenarios see stacked.js)
Nice post & a useful comment. I feel almost compelled to write something with SproutCore once and for all, just to see if I can explain this to myself in HTML/CSS terms. But I’m beginning to think I should just once try it from an app designer’s perspective. I mean, just because custom views on an iPhone are tricky doesn’t mean they will be necessissarily difficult in SproutCore. I’ll still have the power of CSS at least, I just won’t be using floats as such. And I suppose unlike CSS, I could probably use variables to calculate the absolute positioning where useful. I’ll have to trust there’s a reason to doing it this way, as I do Rails’ oddities, for instance.
@Louis: You are correct that you can still use the power of CSS to stylize all the views that make up your app, which you can witness in many of the tutorials I’ve written so far (speaking of which, I really need to get back to posting more about SproutCore).
If you have a view that requires more CSS control then you can always maxin SC.StaticLayout into your view. That’s what SproutCore does with the SC.ListItemView. Also remember that your never far away from the HTML if you override the view’s render method.
Regarding the absolute position used in SproutCore, there are a couple of reasons for it. The primary reason is so that the framework can calculate where a view boundaries are when handling events and dealing with drag and drop. Without getting too deep into the details, SproutCore handles most of the event mechanisms compared to more traditional web apps that use the browser to bubble events and such. Absolute position is also handled by SC for clipping and visibility so it can do some nifty optimization techniques, such as when a view should and should not be rendered, when bindings/observers should be notified, and minimizing calls the browser’s DOM that can be expensive, especially in IE.
Funny, I’d hardly thought about IE compatibility being the reason for avoiding such. Considering it now, it makes sense.
I’m beginning to think that SproutCore might be most fun when hosted on Google App Engine, as in Django or this: http://github.com/joshholt/SproutCoreTasks-AppEngineBackend … I like the comment on how Ruby spoilt him, I certainly am trying to decide between the recent http://code.google.com/p/appengine-jruby/ for all things Ruby and coding it with http://code.google.com/p/google-app-engine-django/ in Python. with something like this: http://groups.google.com/group/django-sproutcore While I’d prefer Ruby, it sounds like I may have more fun via Django. And I should probably re-learn Python also.
I just ran through this tutorial using sproutcore (1.0.1046), installed as a gem in early June 2010.
I get a slate grey border at the top and bottom of the window and can’t track down why. I’m assuming its due to some sproutcore framework styling, but I’ve poked around w/web inspector on safari, and the devoper toolbar on Firefox and can’t find the attribute/ style definition that’s causing the border.
Any help?
@Hawley:
Ya, some things have changed in SproutCore since I wrote this way back when. For one, the english.lproj directory should now be a resource directory, and the CSS file should go into the resource directory. Second, the default color for a label’s text is now white, not black. So in the CSS file, you’ll need to add an additional attribute where color is black. When I made that change the text was visible again. However, there appears to be a new issue where the label and the top and bottom are slightly offset. Not sure why that’s happening at the moment. I’ll have to investigate further.
@fc : Thanks for looking into this. I had already figured out the white text issue, but, as I said, I can’t for the life of me figure out where the top and bottom offsets are coming from. I’ll be interested to know what the scoop is.