Hello fellow Forrsters! We're in the midst of writing Foundation 4 here at ZURB and I'd like to share our new button mixin with you guys. The code I'm sharing with you will work if you paste it into any Scss project that uses Compass so feel free to try it out.

What you're seeing is the existing Foundation button styles turned into an Scss mixin that gives you just enough control to create awesome buttons without being overly complex. You can see the existing code on line 1-53 here:

For Foundation 4, we want to make sure people using Scss have an awesome experience with the power of using mixins and placeholder classes. This will enable more semantic markup and rid more of the world of presentational classes.

I'm looking for specific feedback on this code:

  • Does the final mixin syntax seem easy enough to use?
  • Would you use the placeholder classes more than the mixin?
  • Is there anything you'd do to optimize this code further?
  • Is there anything you wish this mixin did differently?
//
// VARIABLES AND FUNCTIONS
//

// Button Variables
$mainColor: #2ba6cb !default;
$primaryColor: $mainColor !default;
$secondaryColor: #e9e9e9 !default;
$alertColor: #c60f13 !default;
$successColor: #5da423 !default;
$shinyEdge: rgba(#fff, .5) !default;
$darkEdge: rgba(#000, .2) !default;
$btnBase: 10px !default;
$btnTinyBase: 5px !default;
$btnSmallBase: 7px !default;
$btnLargeBase: 15px !default;
$btnFontColor: #fff !default;
$btnFontSize: 14px !default;
$btnTinyFontSize: 10px !default;
$btnSmallFontSize: 11px !default;
$btnLargeFontSize: 17px !default;
$btnTransitionSpeed: .15s !default;
$btnTransitionEase: ease-in-out !default;
$btnRadius: 3px !default;
$btnShinyEdge: 0 1px 0 $shinyEdge inset !default;
$btnDarkEdge: 0 1px 0 $darkEdge inset !default;
$btnBorderWidth: 1px !default;
$btnBorderStyle: solid !default;
$btnAlignIndention: 12px !default;
$btnDisabledOpacity: 0.6 !default;

// Button Functions
@function btnSidePad($btnSize) {
  @return $btnSize * 2;
}
@function btnBtmPad($btnSize) {
  @return $btnSize + 1;
}

View Raw Code →


//
// PLACEHOLDER CLASSES USED TO BUILD MIXIN LOGIC
// CAN BE USED BY THEMSELVES TO BUILD OUT STYLES AS WELL.
//

// Placeholder Class for Shared Styles
%btnBaseStyles {
  border-width: $btnBorderWidth;
  border-style: $btnBorderStyle;
  cursor: pointer;
  font-family: inherit;
  font-weight: bold;
  line-height: 1;
  margin: 0;
  position: relative;
  text-decoration: none;
  width: auto;
  color: $btnFontColor;
  @include box-shadow($btnShinyEdge);
  @include single-transition(background-color, $btnTransitionSpeed, $btnTransitionEase);
  &:active { @include box-shadow($btnDarkEdge); }
}

// Primary Button Base
%btnPrimaryBase {
  background-color: $primaryColor;
  border-color: darken($primaryColor, 15%);
  &:hover,
  &:focus { color: $btnFontColor; background-color: darken($primaryColor, 10%); }
}
// Secondary Button Base
%btnSecondaryBase {
  background-color: $secondaryColor;
  border-color: darken($secondaryColor, 15%);
  color: #333;
  &:hover,
  &:focus { background-color: darken($secondaryColor, 10%); }
}
// Alert Button Base
%btnAlertBase {
  background-color: $alertColor;
  border-color: darken($alertColor, 15%);
  &:hover,
  &:focus { background-color: darken($alertColor, 10%); }
}
// Success Button Base
%btnSuccessBase {
  background-color: $successColor;
  border-color: darken($successColor, 15%);
  &:hover,
  &:focus { background-color: darken($successColor, 10%); }
}
// Extend Button Width
%btnExtendStyle {
  width: 100%;
  padding-left: 0px !important;
  padding-right: 0px !important;
}
// Disabled Button Base
%btnDisabledBase {
  opacity: $btnDisabledOpacity;
  cursor: default;
  @include box-shadow(none);
}
// Disabled Background Colors
%btnPrimaryDisabled { background-color: $primaryColor;
  &:hover,
  &:focus { background-color: $primaryColor; }
}
%btnSecondaryDisabled { background-color: $secondaryColor;
  &:hover,
  &:focus { background-color: $secondaryColor; }
}
%btnSuccessDisabled { background-color: $successColor;
  &:hover,
  &:focus { background-color: $successColor; }
}
%btnAlertDisabled { background-color: $alertColor;
  &:hover,
  &:focus { background-color: $alertColor; }
}

// Button Size Shared Styles
%btnTinyStyles {
  font-size: $btnTinyFontSize;
  padding: $btnTinyBase btnSidePad($btnTinyBase) btnBtmPad($btnTinyBase);
}
%btnSmallStyles {
  font-size: $btnSmallFontSize;
  padding: $btnSmallBase btnSidePad($btnSmallBase) btnBtmPad($btnSmallBase);
}
%btnMediumStyles {
  font-size: $btnFontSize;
  padding: $btnBase btnSidePad($btnBase) btnBtmPad($btnBase);
}
%btnLargeStyles {
  font-size: $btnLargeFontSize;
  padding: $btnLargeBase btnSidePad($btnLargeBase) btnBtmPad($btnLargeBase);
}

// Button Radii
%btnRadiusRound { @include border-radius($btnRadius); }
%btnRadiusPill { @include border-radius(1000px); }

// Button Text Alignment
%btnTextCenter { text-align: center; }
%btnTextLeft { text-align: left; text-indent: $btnAlignIndention; }
%btnTextRight { text-align: right; padding-right: $btnAlignIndention; }

// Button Display Property
%inlineBlock { display: inline-block; }
%block { display: block; }

View Raw Code →


// Button Mixin
@mixin button($color:primary, $size:medium, $expand:false, $radius:false, $align:center, $disabled:false, $display:inline-block) {

  // Shared styles
  @extend %btnBaseStyles;

  // $color options, defaults to primary, false will omit.
  @if $color == primary   { @extend %btnPrimaryBase; }
  @if $color == secondary { @extend %btnSecondaryBase; }
  @if $color == success   { @extend %btnSuccessBase; }
  @if $color == alert     { @extend %btnAlertBase; }

  // $size options, can do $size:false to omit these styles.
  // Available option: "tiny, small, medium, large";
  @if      $size == tiny   { @extend %btnTinyStyles; }
  @else if $size == small  { @extend %btnSmallStyles; }
  @else if $size == medium { @extend %btnMediumStyles; }
  @else if $size == large  { @extend %btnLargeStyles; }

  // "$size:expand" styles for full-width buttons
  @if $expand { @extend %btnExtendStyle; }

  // $radii options. This is automatically set to false for default square corner buttons.
  @if      $radius == round { @extend %btnRadiusRound; }
  @else if $radius == pill  { @extend %btnRadiusPill; }

  // $align options for text alignment in buttons, setting this to "false" omits the styles.
  // Available options: "center, left, right";
  @if      $align == center { @extend %btnTextCenter; }
  @else if $align == left   { @extend %btnTextLeft; }
  @else if $align == right  { @extend %btnTextRight; }

  // $disabled options, "false" by default
  @if $disabled { @extend %btnDisabledBase; }

  // $display options, set to "inline-block" by default. Can set to "false" to omit.
  // Available options: "inline-block, block";
  @if $display == inline-block { @extend %inlineBlock; }
  @else if $display == block { @extend %block; }

}

View Raw Code →


//
// A FEW EXAMPLES OF HOW THE SCSS CODE WOULD BE WRITTEN IN YOUR CODE
//

// THE DEFAULT MIXIN SYNTAX

@include button($color:primary, $size:medium, $expand:false, $radius:false, $align:center, $disabled:false, $display:inline-block) {

// HTML

<a class="more-link" href="#">More</a>
<a id="cta" href="#">Button Text</a>
<button>Button Text</button>


// Scss Examples

.more-link {
  @extend %btnBaseStyles;
  @extend %btnMediumStyles;
  @extend %btnPrimaryBase;
  @extend %inlineBlock;
  @extend %btnTextCenter;
}

#cta {
  @include button($size:large, $radius:pill);
}

button {
  @include button($expand:true, $align:left);
}


// CSS Output

.more-link,
#cta,
button { 
  border-width: 1px; 
  border-style: solid; 
  cursor: pointer; 
  font-family: inherit; 
  font-weight: bold; 
  line-height: 1; 
  margin: 0; 
  position: relative; 
  text-decoration: none; 
  width: auto; 
  color: white; 
  -webkit-box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5) inset; 
  -moz-box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5) inset; 
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5) inset; 
  -webkit-transition: background-color 0.15s ease-in-out; 
  -moz-transition: background-color 0.15s ease-in-out; 
  -o-transition: background-color 0.15s ease-in-out; 
  transition: background-color 0.15s ease-in-out; 
}

.more-link:active,
#cta:active,
button:active { 
  -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2) inset; 
  -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2) inset; 
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2) inset; 
}

.more-link,
#cta,
button { 
  background-color: #2ba6cb; 
  border-color: #1e728c; 
}
.more-link:hover,
#cta:hover,
button:hover,
.more-link:focus,
#cta:focus,
button:focus { 
  color: white; background-color: #2284a1; 
}

button { 
  width: 100%; 
  padding-left: 0px !important; 
  padding-right: 0px !important; 
}

.more-link, 
button { 
  font-size: 14px; 
  padding: 10px 20px 11px; 
}

#cta { 
  font-size: 17px; 
  padding: 15px 30px 16px; 
}

#cta { 
  -webkit-border-radius: 1000px; 
  -moz-border-radius: 1000px; 
  -ms-border-radius: 1000px; 
  -o-border-radius: 1000px; 
  border-radius: 1000px; 
}

.more-link,
#cta {
  text-align: center; 
}

button { 
  text-align: left; 
  text-indent: 12px; 
}

.more-link, 
#cta, 
button { 
  display: inline-block; 
}

View Raw Code →


I'm looking forward to hearing what you guys think. There will be lots more like this built into Foundation 4 over the next few weeks.