When we released Neat—a semantic grid framework built on top of Sass and Bourbon—earlier this fall, it was welcomed with great enthusiasm in the Sass community. Today I’m pleased to announce that Neat is finally out of the beta, introducing new responsive features, a visual grid, and better support for non-Rails projects.
The breakpoint() mixin becomes media() in Neat 1.0 in order to keep the syntax as close to CSS3 as possible.The update also introduces new-breakpoint(), a helper function that you can use to define new media contexts and use them throughout your project.
A media context is comprised of a width breakpoint and an optional total column count that would redefine the grid. For instance, using a four-column grid for mobile devices would involve defining a new media context with a max-width of 480px and a grid column count of 4, like so:
$mobile: new-breakpoint(max-width 480px 4);
Once defined, you can use the $mobile context throughout your project using the media() mixin:
div {
height: 500px;
@include media($mobile) {
// All layout mixins in this context will use a base grid of 4 columns
height: 100px;
}
}
Which would output the following CSS:
div {
height: 500px;
}
@media screen and (max-width: 480px) {
div {
height: 100px;
}
}
Additionally, you can now use both min-width and max-width in the same context:
$tablet: new-breakpoint(min-width 481px max-width 991px 8); // Use an 8 column grid on tablets
Keep in mind that each call of the media() mixin would result in a separate @media block in the CSS output, a Sass limitation that is still being actively discussed.
Due to popular demand, we’ve baked in a pure-Sass visual grid in this milestone release. You can now display the underlying grid either as a background or as an overlay, and even change its color and opacity to better fit your content. Add the following line in your Neat settings to turn the visual grid on:
$visual-grid: true;
You can then change its look by overriding the default variables:
$visual-grid-color: yellow;
$visual-grid-index: front;
$visual-grid-opacity: 0.3;

Bonus: If you use new-breakpoint() to change the base grid, the visual grid will automatically follow. You’re welcome.
If you are planning to use Neat on a non-Rails project, you’re in for some good news. Neat 1.0 comes with a command line interface that allows you to install, update and remove the framework without hassle.
Start off by installing the gem in your Ruby environment:
gem install neat
Then run the neat install command in your project Sass folder:
cd your-project/your-sass-folder
neat install
To update Neat:
gem update neat
cd your-project/your-sass-folder
neat update
Make sure you don’t alter any internal Neat files as any changes would be overridden when you run this command. Lastly, you can remove Neat either by deleting the folder or by running neat remove.
This update also comes with a few bug fixes, namely the compatibility between nested columns and the shift() mixin, and a new _neat-helpers.scss file that you can use to access helper functions without having to import the whole framework.
The only thing we’re missing at this point is your feedback, so give Neat a spin and let us know what you think through comments, tweets and pull requests.
Today, I’m happy to launch a new online version of our Design for Developers workshop.
We’ve been giving our workshops in Boston for over four years now, and we’ve since expanded them to our new San Francisco office. During that time, we’ve received requests from people around the world asking to take our workshops online. However, we did not want to offer our workshops online until we felt we’d achieved the same intensive, hands-on nature of the in-person version.
We think we’ve figured it out. Here’s how it works:
Instead of taking place in our office over two days, the online version takes place over the course of a month. You pick a project of your own. This can be anything from your personal site, to a side project, to something you’re working on at your job. Each week, we release a pre-recorded video on a design topic and give you a workshop to apply to your project. Throughout the week you work through the workshop, emailing us questions you have along the way. We then hold office hours via group chat, where we have a group critique of your work.
We believe that this hybrid approach will replicate the success of our in person workshop, and we’re excited to bring this to developers around the world.
We’d love to have you take this course. You can sign up now and the course begins Friday, November 2nd, 2012.
I have lots of typographic pet peeves. Lots. But the biggest one is when people put two spaces after a period. It leaves me looking like this:

Every well-designed typeface already includes extra space for the first space after the period. This gives the reader just enough breathing room to recognize that this is the end of a thought. When you add two spaces after the period you are breaking the reader’s flow.

Now, you might be thinking ‘Why was I taught to do this in grade school?’. That’s the remnants of the days when we were typing on typewriters. The monospace fonts used in typewriters couldn’t accommodate for the extra space needed at the end of a sentence, so to make that break obvious people were taught to add two spaces. This became obsolete once personal computers had variable-width typefaces but some people never left the habit behind.
Need more than just my word? Every major manual of style holds this rule, including MLA and the Chicago Manual of Style. HTML follows this rule too: it will collapse two spaces down to one.
Please: for my sanity and your reader’s flow, stop putting two spaces after a sentence. Save your spaces for your code.
Ben Orenstein is joined by Kyle Fiedler, a designer at thoughtbot, and one of the creators of Bourbon Neat. Ben and Kyle discuss responsive design, what it is, and how to implement it. They also discuss Bourbon (a library of Sass mixins) and Neat (a fluid grid framework based on Bourbon), what’s wrong with Twitter Bootstrap and why Bourbon Neat is better, and the other reasons why Bourbon Neat was created despite all the other grid frameworks that are available. Kyle shares the most common design mistakes he sees developers make in projects, whether or not design is subjective or whether it can be more objective, his design process and how it has changed, what the Golden Ratio is, and how it’s used in Neat. Finally, they also discuss the Design for Developers workshop offered by thoughtbot, which teaches the fundamental design principles and tools to developers, and much, much more.
Regardless of the platform you are designing for, getting familiar with its technologies and frameworks is key to refining your design process; even a basic understanding of the technical environment and its constraints can help you streamline the transition from Photoshop comps to design implementation, or completely bypass the former where appropriate.
In this tutorial, we’ll cover four techniques of varying levels of difficulty to draw a custom UIButton, the primary button class in iOS. If you are just getting started, I recommend reading Mike Rundle’s introduction and giving these tutorials a go to get a more hands-on experience.
Start by creating a single view application in Xcode using Apple’s default settings. In the file navigator, select MainStoryboard.storyboard then drag-and-drop a Round Rect Button from the bottom-left objects library to the view canvas. Center the button in the canvas and resize it to your liking, then make few copies of it as shown in the screenshot below.

Make sure to choose the label font and color using the Attribute inspector in the right-hand side of the Xcode window.
The most common and straightforward approach consists in using background images to customize the stock UI controls provided by Apple.
Difficulty: ★☆☆☆☆
The first option involves using a full-sized graphic as the background of your UIButton instance. To do so, design the button (normal and highlighted states) in your favorite graphic editor then export the assets as uncompressed PNGs in both standard and double resolutions.

Import the images to your project by dragging them into the File navigator. In Interface builder, change the button type to custom in the top-right Attributes Inspector.

Then add your images as backgrounds for both the default and the highlighted states using the drop-down shown below.

You can also set background images in code by control-dragging your button to the @interface section of the main view controller as an IBOutlet:
@property (weak, nonatomic) IBOutlet UIButton *fullSizeImage;
…then calling the setBackgroundImage method inside viewDidLoad for each state:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.fullSizeImage setBackgroundImage:[UIImage imageNamed:@"button.png"] forState:UIControlStateNormal];
[self.fullSizeImage setBackgroundImage:[UIImage imageNamed:@"buttonHighlighted.png"] forState:UIControlStateHighlighted];
}
It is worthing noting at this point that anything drawn in code is not previewable in Interface builder. Run the app on the iOS simulator by hitting cmd+R to see the result.
Difficulty: ★★★☆☆
A recently introduced second option consists in using a resizable image as a button background after having set its resizable and non-resizable areas in code. Start by making a pill-shaped background image in your graphic editor.

Next, you should instruct Xcode what areas should be stretched to fit the dimension of the button. For instance, you can prevent the four corners of the background image from being stretched using cap insets. To see this in action, import the assets into Xcode and create a resizable image object to be used with setBackgroundImage (inside viewDidLoad):
UIImage *resizableButton = [[UIImage imageNamed:@"resizableButton.png" ] resizableImageWithCapInsets:UIEdgeInsetsMake(17, 5, 17, 5)];
UIImage *resizableButtonHighlighted = [[UIImage imageNamed:@"resizableButtonHighlighted.png" ] resizableImageWithCapInsets:UIEdgeInsetsMake(17, 5, 17, 5)];
The UIEdgeInsets argument takes four floats corresponding to the distance (in density-independent pixels) separating the caps from each side of the image in the following order: top, left, bottom, right.

For the sake of clarity, the center area in the example above is much wider than it should actually be. In most cases, a 1pt stretchable area is what you should be aiming for.
Unlike full-sized images, setting a resizable image as a background can only be done in code (same steps as the previous method):
// Drag-and-drop the UIButton instance to the @interface section of your view controller
@property (weak, nonatomic) IBOutlet UIButton *resizableImage;
// Inside viewDidLoad
[self.resizableImage setBackgroundImage:resizableButton forState:UIControlStateNormal];
[self.resizableImage setBackgroundImage:resizableButtonHighlighted forState:UIControlStateHighlighted];
In iOS 6, Apple updated the resizableImageWithCapInsets method to accept a resizingMode argument that explicitly instructs Xcode which of the two available resizing modes to use: tiling or stretching. When unspecified, the former is used.
Difficulty: ★★★★☆
Update: The code in this technique has been refactored for better performance with the help of Joris Kluivers.
The CALayer (Core Animation layer) object is the fundamental drawing unit in iOS; a view draws itself into its layer before this latter appears on screen. You’d be surprised at how much you can accomplish without having to draw a single pixel in Photoshop.
First, we need to create a UIButton subclass where our drawing code will end up. Hit cmd+N and create a new Objective-C class by subclassing UIButton.

In Interface builder, set the class of the target button to CBLayer (or whatever you named your subclass) using the top-most field in the Identity inspector.

Go back to the implementation file of your custom button class (.m extension) and implement initWithCoder, a method that will get called on our button instance in order to unarchive it when the view loads. Between the @implementation and the @end directives:
- (id)initWithCoder:(NSCoder *)coder
{
// Our custom CALayer drawing will go here
}
To better organize our code, we’ll split the different parts of the button (background, border, inner-glow, etc.) into separate properties and drawing methods, then call each from within initWithCoder. To do so, we’ll start by declaring the properties that will be used in this process above the @implementation directive:
@interface CBLayer ()
@property (strong,nonatomic) CAGradientLayer *backgroundLayer, *highlightBackgroundLayer;
@property (strong,nonatomic) CALayer *innerGlow;
@end
We’ll implement four instance methods (a message that can be sent to a single button instance) to take care of drawing the button and setting its properties. Whenever using CALayer, remember to link the QuartzCore framework in the Build phases tab of the project manager:

You’ll also need to import its header file in your subclass using this directive #import.
Let’s start by drawing the button itself:
- (void)drawButton
{
// Get the root layer (any UIView subclass comes with one)
CALayer *layer = self.layer;
layer.cornerRadius = 4.5f;
layer.borderWidth = 1;
layer.borderColor = [UIColor colorWithRed:0.77f green:0.43f blue:0.00f alpha:1.00f].CGColor;
}
For the gradients, we’ll use the CAGradientLayer subclass made specifically for this purpose:
- (void)drawBackgroundLayer
{
// Check if the property has been set already
if (!_backgroundLayer)
{
// Instantiate the gradient layer
_backgroundLayer = [CAGradientLayer layer];
// Set the colors
_backgroundLayer.colors = (@[
(id)[UIColor colorWithRed:0.94f green:0.82f blue:0.52f alpha:1.00f].CGColor,
(id)[UIColor colorWithRed:0.91f green:0.55f blue:0.00f alpha:1.00f].CGColor
]);
// Set the stops
_backgroundLayer.locations = (@[
@0.0f,
@1.0f
]);
// Add the gradient to the layer hierarchy
[self.layer insertSublayer:_backgroundLayer atIndex:0];
}
}
The highlighted state gradient can be set using a separate - (void)drawHighlightBackgroundLayer method that is identical to the one above, save for he color values. To DRY up your code, it is recommended that you move the layer drawing code to a separate -(void)drawBackgroundLayerWithGradient:(NSArray)colors method.
Next, we will implement an instance method to set the _innerGlow property:
- (void)drawInnerGlow
{
if (!_innerGlow)
{
// Instantiate the innerGlow layer
_innerGlow = [CALayer layer];
_innerGlow.cornerRadius= 4.5f;
_innerGlow.borderWidth = 1;
_innerGlow.borderColor = [[UIColor whiteColor] CGColor];
_innerGlow.opacity = 0.5;
[self.layer insertSublayer:_innerGlow atIndex:2];
}
}
If we build and run the app at this stage, only the label will be visible on the button. To get our layers onto the screen, we need to call the layer methods from within initWithCoder.
- (id)initWithCoder:(NSCoder *)coder
{
// Call the parent implementation of initWithCoder
self = [super initWithCoder:coder];
// Custom drawing methods
if (self)
{
[self drawButton];
[self drawInnerGlow];
[self drawBackgroundLayer];
[self drawHighlightBackgroundLayer];
}
return self;
}
That doesn’t seem to be enough though; we also need to set the frame rectangles of our different layers and update them every time the button is tapped by implementing the layoutSubviews method:
- (void)layoutSubviews
{
// Set inner glow frame (1pt inset)
_innerGlow.frame = CGRectInset(self.bounds, 1, 1);
// Set gradient frame (fill the whole button))
_backgroundLayer.frame = self.bounds;
// Set inverted gradient frame
_highlightBackgroundLayer.frame = self.bounds;
[super layoutSubviews];
}
Hit cmd+R to see our layers in action. We’ve got one little problem though: the button looks constantly pressed (highlighted) and does not visually react to user taps. Having a closer look at the code, the former appears to be a direct result of calling drawHighlightBackgroundLayer which draws the inverted gradient with a higher z-index (see insertSublayer:layer atIndex:index). To fix this, we need to initially hide the alternate background and make it only visible when the button is tapped. Inside initWithCoder, we’ll add the following line below our drawing methods:
_highlightBackgroundLayer.hidden = YES;
Then we’ll implement setHighlighted, a method that gets called whenever a UIButton is tapped:
- (void)setHighlighted:(BOOL)highlighted
{
// Hide/show inverted gradient
_highlightBackgroundLayer.hidden = !highlighted;
[super setHighlighted:highlighted];
}
When using CALayer, properties are animated by default (cross-fade in this case). We can disable the implicit animation inside setHighlighted:
- (void)setHighlighted:(BOOL)highlighted
{
// Disable implicit animations
[CATransaction begin];
[CATransaction setDisableActions:YES];
// Hide/show inverted gradient
_highlightBackgroundLayer.hidden = !highlighted;
[CATransaction commit];
[super setHighlighted:highlighted];
}
With this we are good to go. One last thing that you may want to do is override the UIButton method buttonWithType in order to prevent inconsistent results if the button is instantiated in code.
+ (CBLayer *)buttonWithType:(UIButtonType)type
{
return [super buttonWithType:UIButtonTypeCustom];
}
Difficulty: ★★★★★
In this last method, we will be using drawRect (base custom drawing method in iOS) and Core Graphics to design our custom button in code.
Go ahead a create a new UIButton subclass then assign it to a button instance in Interface builder. All the code below should go inside drawRect.
We’ll start by defining the color space and the graphics context, a blank canvas where our custom drawing will take place.
// General Declarations
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = UIGraphicsGetCurrentContext();
Next, we will define the colors and the gradients that will be used throughout our implementation:
// Color Declarations
UIColor *borderColor = [UIColor colorWithRed:0.77f green:0.43f blue:0.00f alpha:1.00f];
UIColor *topColor = [UIColor colorWithRed:0.94f green:0.82f blue:0.52f alpha:1.00f];
UIColor *bottomColor = [UIColor colorWithRed:0.91f green:0.55f blue:0.00f alpha:1.00f];
UIColor *innerGlow = [UIColor colorWithWhite:1.0 alpha:0.5];
// Gradient Declarations
NSArray *gradientColors = (@[
(id)topColor.CGColor,
(id)bottomColor.CGColor
]);
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)(gradientColors), NULL);
NSArray *highlightedGradientColors = (@[
(id)bottomColor.CGColor,
(id)topColor.CGColor
]);
CGGradientRef highlightedGradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)(highlightedGradientColors), NULL);
For the rounded rectangle shapes, we will be using UIBezierPath’s bezierPathWithRoundedRect class method.
// Draw rounded rectangle bezier path
UIBezierPath *roundedRectanglePath = [UIBezierPath bezierPathWithRoundedRect: CGRectMake(0, 0, 280, 37) cornerRadius: 4];
// Use the bezier as a clipping path
[roundedRectanglePath addClip];
// Use one of the two gradients depending on the state of the button
CGGradientRef background = self.highlighted? highlightedGradient : gradient;
// Draw gradient within the path
CGContextDrawLinearGradient(context, background, CGPointMake(140, 0), CGPointMake(140, 37), 0);
// Draw border
[borderColor setStroke];
roundedRectanglePath.lineWidth = 2;
[roundedRectanglePath stroke];
// Draw Inner Glow
UIBezierPath *innerGlowRect = [UIBezierPath bezierPathWithRoundedRect: CGRectMake(1.5, 1.5, 277, 34) cornerRadius: 2.5];
[innerGlow setStroke];
innerGlowRect.lineWidth = 1;
[innerGlowRect stroke];
// Cleanup
CGGradientRelease(gradient);
CGGradientRelease(highlightedGradient);
CGColorSpaceRelease(colorSpace);
In order to get our button to change appearance when highlighted, we’ll have to force drawRect to be called whenever the button is tapped. This can be done through calling setNeedsDisplay inside setHighlighted:
- (void)setHighlighted:(BOOL)highlighted
{
[self setNeedsDisplay];
[super setHighlighted:highlighted];
}
If you are not inclined to learn Core graphics and are willing to fork $99, you can use PaintCode, a “graphic editor” that generates the drawing code to go inside drawRect.
CALayer.
Get the demo app here.
Update: Andy Matuschak, a member of the UIKit team, was kind enough to point out in this article’s HN thread that these techniques have different performance ramifications. This is will be most certainly the topic of a future article.
Apple provides different ways to customize the look and feel of your iOS apps, and it’s only getting better with each major iOS release. Learning Objective-C and Core graphics is sure daunting for many designers, but it may be worthwhile considering how it can empower you and help you become more efficient on the long run.